Советы тем, кто программирует на VB & VBA

Андрей Колесов, Ольга Павлова

Совет 256. Программное обращение к CommonDialog

Совет 257. Как узнать, существует ли файл?

Совет 258. Как выбрать имя каталога

Совет 259. Какие операторы лучше использовать: Print # или Write #?

    Преимущества Write #

    Преимущества Input #

Совет 260. Где хранить INI-файл

Совет 261. Как обеспечить совместимость VBA и VB

Совет 262. Как контролировать макросы в шаблонах

Совет 263. Использование даты в SQL-запросах

Совет 264. Программный сброс хранителя экрана

Совет 265. Как подключить VB-процедуры обратного вызова к API-функции

Совет 266. Как избежать ошибок сравнения битовой маскировки при использовании API-функций в VB

Совет 267. Используйте VB-объект RegExp для проверки синтаксиса адреса электронной почты

Совет 268. Как осуществить прокрутку элемента управления ListView в VB до заданного элемента

Совет 269. Работа в VB с формулами, представленными в виде строковых переменных

Совет 270. Как сделать невидимым курсор мыши в VB-приложении

 

Все программные примеры, которые использовались в приведенных здесь советах, можно найти по адресу: www.visual.2000.ru/develop/vb/source/.

Совет 256. Программное обращение к CommonDialog

Если требуется выполнить выборку имени файла для операций открытия или закрытия, для этого обычно используется элемент управления CommonDialog. Однако в ряде случаев полезнее бывает выполнить прямое обращение к функциям GetOpenFileName и GetSaveFileName библиотеки COMDGL32.DLL. Например, если вы пишете собственный мастер по созданию проекта, то подключиться в проект с модулем кода гораздо удобнее, чем делать коррекцию кода модуля формы. Тем более что такая процедура будет единой для всего проекта.

В листинге 1 приведен один из вариантов реализации универсальной процедуры FileOpenSave поиска имени файла в режиме «Открыть/Сохранить», а также пример обращения к ней.

В начало

В начало

Совет 257. Как узнать, существует ли файл?

Проще всего сделать это следующей операцией в одну строчку:

If Dir$(FileName$)="" Then ' такого файла нет!
В начало

В начало

Совет 258. Как выбрать имя каталога

В разных вспомогательных утилитах довольно часто встречается задача выборки имени файла или имени каталога. Например, если вы пишете утилиту по перекодировке текстовых файлов, будет достаточно предоставить пользователю возможность выбрать или конкретный файл, или каталог, в котором нужно преобразовать все файлы.

К сожалению, диалоговое окно Open (или DLL-функция GetOpenFileName) не позволяет выбирать только имя файла. Конечно, можно из этого имени по специальной команде пользователя сделать выделение каталога. А что делать, если нужный каталог содержит только подкаталоги?

Разумеется, лучшим вариантом является создание собственного диалогового окна, которое будет учитывать все режимы, необходимые в конкретной задаче. Но можно использовать и стандартное окно Open.

Для этого в поле File Name нужно просто ввести любое имя несуществующего в данном каталоге файла (например, QQQQ). Соответственно в программе, которая обращается к окну (например, с использованием функции FileOpenSave, о чем говорилось в предыдущем совете), напишется такой программный код:

MyFile$ = FileOpenSave$(...)
If Dir$(MyFile$) = "" Then ' задан несуществующий файл
    ' значит задано имя каталога
    In1% = InstrRev (MyFile$, "\")
    MyDir$ = Left$ (MyFile$, in1% - 1) ' имя каталога
    ' обработка данных в режиме "выделен
каталог"
End If
В начало

В начало

Совет 259. Какие операторы лучше использовать: Print # или Write #?

В своем совете 228 мы привели пример утилиты Summa.vbp (представление числового значения прописью), которая, в частности, сохраняет введенные параметры (для последующего восстановления) в виде простого текстового файла. Данные последовательно записываются оператором Print #, а при запуске утилиты читаются оператором Input #.

В связи с этим наш читатель Константин Абакумов обратил внимание на то, что в справке Visual Basic подчеркивается следующее: «Для записи данных в файл, который в будущем планируется читать с помощью инструкции Input #, следует вместо инструкции Print # использовать Write #. Это гарантирует, что записанные данные будут корректно разделены и могут быть корректно прочитаны при наличии любых национальных настроек».

Это замечание совершенно справедливо (хотя конкретно в случае утилиты Summa — не существенно), однако порой Print # является предпочтительнее. Рассмотрим эту ситуацию подробнее.

В начало

В начало

Преимущества Write #

Предположим, вы хотите сохранить четыре переменные — дату, две символьные строки и число:

Dim MyDate As Date, MyStr1$, MyStr2$, MyInt%
MyDate = Date$ ‘ текущая дата
MyStr1 = "Коля"
MyStr2 = "Петя, Лена, 2000"
MyInt = 12
Open MyFile$ For Output As #1
    Print #1, MyDate
    Print #1, MyStr1; MyStr2; MyInt
Close
Open MyFile$ For Output As #1
Input #1, MyDate ‘ ! здесь будет выдана ошибка!
Input #1, MyStr1; MyStr2; MyInt
Close

Очевидная проблема возникнет при чтении даты, записанной в файл в виде 26.02.00: программа просто не поймет, что это — дата. Можно решить этот вопрос, сделав следующую конструкцию чтения даты:

Input #1, MyDate2$ ‘ чтение строки
MyDate = MyDate2$ ‘ и преобразование ее в дату

Однако здесь также имеется потенциальная опасность — нужно быть уверенным, что данные читаются и записываются в Windows с одинаковыми региональными установками. (Представьте себе, что вам нужно переслать файл с расчетными данными в виде текстового файла своему коллеге в США.)

Еще больше проблем возникнет с конструкцией:

Print #1, MyStr1; MyStr2; MyInt
...
Input #1, MyStr1; MyStr2; MyInt

В случае нашего примера вы получите следующие результаты при чтении:

MySrt1 = "КоляПетя"
MySrt2 = "Лена"
MyInt = 2000

Видно, что они отличаются от исходных значений. Если же использовать в операторе Print # в качестве разделителя в списке запятую, то получится следующий результат:

MySrt1 = "Коля Петя"
MySrt2 = "Лена"
MyInt = 2000

Если мы заменим оператор Print # на Write #, то все данные будут сохраняться и читаться верно, поскольку дата будет записываться в виде литерала #2000-02-26# (обратите внимание, что литералы даты хранятся в американском формате, независимо от региональных установок), строковые переменные — в двойных кавычках и все поля в текстовом файле будут разделены запятыми.

Но здесь есть очевидная проблема: если ваши строковые переменные содержат двойные кавычки, то будут происходить неприятные искажения данных. Например, вы ввели в текстовое поле название ЗАВОД «САЛЮТ» и хотите сохранить его значение в текстовом файле. Чтобы гарантированно избежать подобной ситуации, нужно проверять строки на наличие двойных кавычек и, в частности, автоматически их удалять (можно поставить соответствующий контроль при вводе данных) или менять на одинарные кавычки.

В начало

В начало

Преимущества Input #

Предположим, вам нужно сохранить в виде текстового файла числовой массив с переменными границами Arr (M, N). Конечно, можно воспользоваться оператором Write #:

For i = 1 To M
    For j = 1 To N
        Write #1, Arr(i, j)
    Next
Next

Однако с таким текстовым файлом будет крайне неудобно работать, если потребуется изучать или корректировать его с помощью простого текстового редактора (такая задача встречается достаточно часто). Файл будет выглядеть гораздо лучше, если применить следующий код:

For i = 1 To M
    For j = 1 To N
        Print #1, Arr(i, j); ‘ запись в одну строку
    Next
    Print #1 ‘ перевод строки
Next

Таким образом, оператор Print # очень полезен в случае, когда нужно вывести в одну строку текстового файла набор данных переменной длины или просто большое число однородных данных.

В свое время мы именно в силу необходимости получения структурируемого текстового файла (хорошо читаемого в текстовом редакторе) полностью отказались от использования оператора Write #. Для беспроблемного применения Print # мы создали очень простой набор процедур, который имитировал Write — заключал в кавычки строки, писал даты в виде литералов, расставлял запятые в качестве разделителей.

Какой вариант удобнее? Это, конечно же, зависит от конкретной решаемой задачи.

В начало

В начало

Совет 260. Где хранить INI-файл

В данном случае мы имеем в виду файлы, в которых хранятся некоторые параметры приложения между его перезапусками. (В общем случае они могут иметь любое расширение и любую удобную для разработчика структуру.) Конечно, для хранения подобных файлов можно выделить специальный каталог, например системный Windows. Или вообще хранить подобные данные в файле Реестр. Однако, на наш взгляд, такая концентрация данных разных приложений в одном месте является довольно порочной практикой (к сожалению, именно она используется авторами Windows, а по их примеру — и многими независимыми разработчиками). В связи с этим можно привести несколько возражений: использование единого Реестра снижает производительность и надежность системы («падение» одного файла приводит к «падению» данных всех приложений), кроме того, резко усложняется проблема «удаления мусора».

Поэтому мы советуем создавать для отдельных приложений собственные INI-файлы. И хранить их лучше всего в одном каталоге с самим приложением — тогда вам не придется писать инструкции пользователям «Создайте каталог IniFolder для хранения файла MyApplication.INI». Более того, может оказаться удобным предоставить возможность использования нескольких вариантов INI-файлов (например, при работе нескольких пользователей). В этом случае вызов утилиты (через ярлык) может выполняться командной строкой:

MyUtility [User.INI]

Программный код обработки будет в этом случае иметь, например, такой вид:

Public Sub Main()
    Dim IniFile$, Say$
    '
    ' Запуск приложения
    ' SomeUtil.EXE [MyIniFile]
    '=====================
    ' открытие INI-файла приложения:
    IniFile$ = Command$ ' читаем командную строку
    
    If IniFile$ = "" Then ' не задан в командной строке
    ' по умолчанию: имя самой утилиты с расширением INI
        IniFile$ = App.EXEName + ".INI"
    End If
    ' формируем полный путь - там же, где находится приложение
    IniFile$ = App.Path + "\" + IniFile$
    
    Say$ = "INI-файл = " & IniFile$
    If Dir(IniFile$) <> "" Then
        MsgBox Say$, , "СУЩЕСТВУЕТ"
        ' открытие INI-файла, чтение исходных данных
    Else
        MsgBox Say$, , "НЕ СУЩЕСТВУЕТ"
        ' Тут можно спросить, нужно ли запускать приложение
        ' с параметрами по умолчанию и создавать новый INI-файл
    End If
End Sub

При отладке приложений в среде командная строка задается в поле Command Line Arguments в диалоговом окне Project Properties|Make.

В начало

В начало

Совет 261. Как обеспечить совместимость VBA и VB

В статье об интеграции VBA в VB-приложения («Интеграция VBA в бизнес-приложения независимых разработчиков», КомпьютерПресс 3’2000) мы отмечали следующую проблему с отладкой приложений.

Если мы запускали созданное приложение (с уже интегрированным в него VBA) непосредственно в среде Visual Basic, то, перейдя затем в VBA, обнаруживали, что глобальный объект приложения CApplication (он создавался мастером VB Integration) недоступен. Если же создать загрузочный EXE-модуль, то с объектом можно будет нормально работать.

Для иллюстрации этой ситуации продемонстрируем несложный пример. При этом имеется в виду, что вы работаете с VB и у вас на компьютере установлен VBA 6.0 SDK 6.1.

В среде VB создайте самый простой проект — Standard EXE. Обратите внимание: у нас получилось вполне работоспособное приложение, которое просто загружает формы. Но нам для примера ничего больше и не нужно. Далее запустите VB Integration Wizard из меню Add-ins и пройдите все этапы его работы, просто нажимая кнопку Next (ничего не меняя в полях окон).

Итак, за полминуты мы создали приложение, которое само по себе ничего не умеет делать, но зато имеет среду VBA, где можно разрабатывать и выполнять автономные VBA-проекты любой сложности.

  1. Запустим наше приложение Project1, перейдем в среду VBA (Alt-F11) и напишем в окне Immediate:
Print Project1.CApplication.Name

Нажав Enter (выполнив эту строку), мы увидим сообщение: «Method or data member not found».

Теперь создадим EXE-модуль нашего проекта и повторим с ним пункт 1. Ошибки не будет, и мы увидим в окне Immediate имя нашего проекта — Project1.

Получается, что отлаживать макрокоманды, которые работают с объектами основного приложения, можно только в варианте EXE. Это, конечно, очень неудобно, особенно в том режиме, когда мы ведем разработку и отладку этих объектов.

Но, оказывается, есть очень простое решение этой проблемы. Нужно просто переименовать объект CApplication в Application, внеся также соответствующие изменения во все упоминания этого объекта, например используя команду Replace. (Еще проще сделать это в момент работы мастера VB Integration, исправив предлагаемое имя глобального объекта приложения.)

Теперь объект Project1.Application будет доступен и в среде VB, и при работе с EXE-модулем. Почему так получается, что в среде VB доступен только объект с именем Application, — непонятно. Но тем не менее это так!

В начало

В начало

Совет 262. Как контролировать макросы в шаблонах

В своем обзоре по MS Office 2000 (КомпьютерПресс 12’99) мы отмечали некоторые проблемы при использовании шаблонов в Word 2000. Так, при загрузке шаблонов в виде автономных документов или присоединенного файла из каталога Шаблоны пользователя не производилась проверка на наличие макрокода, хотя такой режим контроля был задан. Оказывается, проблема заключается в более детальных установках контроля за макрокодом.

Управление режимом контроля за наличием макрокода при загрузке документов производится в диалоговом окне Security[Безопасность] (команда меню Tools|Macro|Securiry [Сервис|Макрос|Безопасность]). На его вкладке Trusted Sources [Надежные источники] имеется флажок Trust all installed Add-ins and templates [Доверять всем установленным надстройкам и шаблонам]. Под «установленными» подразумеваются дополнения и шаблоны, помещенные в каталог «Шаблоны пользователя». (Конкретное имя этого каталога указывается в поле User Templates [Шаблоны пользователя] во вкладке File Locations [Расположение] диалогового окна Tools|Options [Сервис|Параметры].)

По умолчанию данный флажок установлен, поэтому все шаблоны из этого каталога не проверяются на наличие макрокода (подразумевается, что вы помещаете туда файлы, в которых точно уверены). Если вы все же хотите выполнять такую проверку, то очистите флажок.

В Word 97 такого специального режима для загрузки шаблонов не было. Но в начальной версии программы иногда имела место ошибка — когда шаблоны загружались без проверки на макрокод. Этот дефект уже устранен — заплатку, которая решает данную проблему, можно скачать по адресу http://www.microsoft.com/rus/download/wd97sp.htm.

В начало

В начало

Совет 263. Использование даты в SQL-запросах

В своей статье «Особенности обработки дат в Visual Basic» (КомпьютерПресс 07'99) мы обращали внимание читателей на необходимость учета национальных особенностей обработки дат. Вот еще один из примеров подобной ситуации.

При обращении к базе данных для выборки каких-то записей по дате нужно написать символьную строку приблизительно такого вида:

SELECT * FROM SomeTable WHERE Time <= #02/29/2000#

Обратите внимание, что дата задается здесь как литерал, но самое главное — литерал может быть представлен только в формате американской даты. Поэтому вариант, часто предлагаемый американскими авторами:

Sql1$ = "SELECT * FROM SomeTable WHERE Time <= "
SQL$ = Sql1$ & "#" & Now & "#"

с российскими региональными установками работать не будет. Для этого требуется использовать функцию Format с заданием американского формата:

D$ = Format(Now, "MM/dd/yyyy HH:mm")
Mid$(D$, 3) = "/" ‘ меняем разделители
Mid$(D$, 6) = "/"
SQL$ = Sql1$ & "#" & D$ & "#"

Здесь нужно обязательно в явном виде установить разделители в дате, так как, хотя мы и указали "MM/dd/yyyy" в Windows с российскими региональными установками, в символьном представлении даты будут записаны точки.

В начало

В начало

Совет 264. Программный сброс хранителя экрана

Наш читатель Владимир Чикин прислал нам такой вопрос: каким образом выключить хранитель экрана программным способом из приложения, чтобы вновь был виден программный интерфейс? Это бывает нужно, если приложение работает без использования диалога с пользователем (например, программа отслеживает данные, поступающие из COM-порта, или просто выполняет очень длительные вычисления) и требуется выдать сообщения о каких-либо критических событиях в программе.

Здесь видятся два варианта решений:

  1. Если приложение работает фактически в однозадачном режиме и вас интересует только проблема предохранения экрана (без какой-либо экзотической графики), то проще всего реализовать такой режим внутри программы, без использования автономных хранителей экрана.

Для этого создайте форму, на которую поместите элемент управления Label, содержащий какой-либо текст, а также элемент управления Timer, для которого установите свойство Interval как 1000 (то есть 1 секунда). Для формы установите свойства WindowState = Maximized, Border Style = None и выберите черный цвет в качестве фона BackColor. Теперь введите следующий код для вашей формы:

Private Sub Form_Click()
    ' хранитель экрана выгружается, если щелкнуть форму
    Unload Me
End Sub
Private Sub Timer1_Timer()
    ' мигание метки каждую секунду
    Label1.Visible = Not (Label1.Visible)
End Sub

Соответственно в программе, когда потребуется погасить экран, нужно загрузить форму, а в необходимый момент — выгрузить ее.

Если требуется обеспечить такой режим, чтобы по щелчку мыши хранитель исчезал на некоторое время, а потом появлялся опять, то можно написать такой код формы:

Private Sub Form_Click()
    ' убрать хранитель
    Me.WindowState = 1 'Minimized
    Timer1.Enabled = False
    Timer1.Interval = 60000 ' минута
    Timer1.Enabled = True
End Sub
Private Sub Form_KeyPress(KeyAscii As Integer)
    ' если нажата Esc - выгрузить форму
    If KeyAscii = 27 Then ' Esc
        Unload Me
    End If
End Sub
Private Sub Timer1_Timer()
    If Me.WindowState = 1 Then ' хранитель свернут
        Me.WindowState = 2 ' развернуть хранитель экрана
        Timer1.Interval = 1000 ' секунда
    Else ' управляем выводом метки
        Label1.Visible = Not (Label1.Visible)
    End If
End Sub
  1. Но что же делать, если вам действительно нужно программно сбросить внешний «фирменный» хранитель экрана? В этом случае можно воспользоваться функцией keybd_event из состава Win API, которая имитирует манипуляции с клавиатурой. (Здесь также нужно упомянуть об аналогичной функции mouse_event для имитации мыши.)

Пример процедуры SendMyKey, которая обеспечивает имитацию записи в буфер указанного ASCI-символа, приведен на листинге 2. В этом случае для сброса внешнего хранителя экрана можно использовать такую программную конструкцию:

' посылка символа в буфер клавиатуры
Call SendMyKey(Chr$(9)) ' клавиша Tab
' почему-то нужно сделать вывод окна
' -- тогда срабатывает посылка символа
MsgBox "Hello!"

Мы не смогли понять почему, но посланный символ срабатывает только в случае, если программа потом выдает на экран еще какое-либо окно. Разумеется, если вы точно знаете, какой символ собираетесь имитировать, то можно обратиться напрямую к keybd_event, без дополнительных обращений к другим API-функциям для вычисления вспомогательных кодов. Для случая клавиши Tab это будет выглядеть следующим образом:

keybd_event 9, 15, 0, 0
keybd_event 9, 15, 2, 0
В начало

В начало

Совет 265. Как подключить VB-процедуры обратного вызова к API-функции

Оператор AddressOf, появившийся в VB версии 5.0, позволяет передавать указатель для определяемой пользователем подпрограммы, функции или свойства в API-функцию, которая затем может передавать различные данные в процедуру обратного вызова (callback procedure). Для передачи такого указателя в API-функцию следует использовать

AddressOf procedurename

в качестве аргумента в этой функции. Поэтому, например, чтобы заменить или расширить стандартную процедуру работы с сообщениями, можно написать такую подпрограмму:

Private Sub Form_Load()
    gWH = Me.hwnd
    OldWndProc = SetWindowLong(gWH, GWL_WNDPROC, _
    AddressOf WindowProc)
End Sub

где WindowProc является пользовательской процедурой. Подобная операция называется подключением обратного вызова. В этом случае аргумент WindowProc сможет перехватывать сообщения формы. В нашем случае для отключения пользовательской процедуры следует вызвать ту же самую API-функцию с указателем предыдущей процедуры приблизительно так:

SetWindowLong gWH, GWL_WNDPROC, AddressOf OldWndProc

При использовании ключевого слова AddressOf необходимо, однако, соблюдать следующие правила. Названия определяемых пользователем подпрограмм, функций или свойств, которые будут использоваться в качестве обратного вызова, должны следовать непосредственно за оператором AddressOf. Проект, в котором имеются подпрограммы, функции и свойства обратного вызова, должен содержать соответствующие описания API-функций и процедуры. Нельзя применять AddressOf ни с какими другими функциями, кроме определяемых пользователем подпрограмм, функций или свойств. Например, вы не можете использовать другую API-функцию или функцию из библиотеки типов. Обратный вызов должен находиться в стандартном модуле. И, наконец, последнее -- определяемая пользователем подпрограмма или функция должна иметь тип Any либо Long.

В начало

В начало

Совет 266. Как избежать ошибок сравнения битовой маскировки при использовании API-функций в VB

При использовании API-функций достаточно часто возникает необходимость определить, содержат ли получаемые результаты определенный признак (flag) или нет. Для этого данный признак маскируется и применяется оператор And. Например, предположим, что мы хотим узнать, в каком состоянии находится текущее окно — развернуто оно или свернуто. Вначале получим установки этого окна с помощью API-функции GetWindowLong(), которую опишем в стандартном модуле следующим образом:

Public Const WS_MAXIMIZE = &H1000000
Public Const GWL_STYLE = -16
Public Declare Function GetWindowLong Lib _
"user32" Alias "GetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long) As Long

Затем поместим на форму командную кнопку и введем такой код в ее событие Click():

Dim lWinStyle As Long
lWinStyle = GetWindowLong(Me.hwnd, GWL_STYLE)
If lWinStyle And WS_MAXIMIZE Then
    MsgBox "Форма развернута"
Else
    MsgBox "Форма свернута"
End If

Теперь запустим наш пример на выполнение и щелкнем на кнопке. Приведенный выше код определяет, содержит ли значение стиля битовое значение признака. Если да, то логическое сравнение возвращает число, которое VB интерпретирует как True (Истина). В противном случае возвращается 0 или False (Ложь).

Ошибки же могут возникнуть, если мы попытаемся проверить исключение какого-либо признака. Так, предположим, мы хотим выполнить определенные действия, когда окно находится в свернутом состоянии. Попробуем просто написать:

If Not (lWinStyle And WS_MAXIMIZE) Then

(Конечно, в данном конкретном случае мы могли бы выполнить тестирование признака WS_MINIMIZE, но иногда API-функции не имеют признака, представляющего собой противоположную установку.) К сожалению, такой условный оператор всегда возвращает значение True. Это происходит потому, что, когда мы используем оператор Not с числом, VB возвращает значение этого числа с противоположным знаком минус 1. Например, выражение Not 15 возвращает -16, которое интерпретируется VB как True. В нашем примере с битовой маскировкой выражение Not (lWinStyle And WS_MAXIMIZE) для развернутого окна имеет ненулевое значение, которое опять оценивается как True.

Чтобы избежать появления подобного «глюка», можно использовать один из двух следующих операторов:

If Not Cbool(lWinStyle And WS_MAXIMIZE) Then

или

If Not ((lWinStyle And WS_MAXIMIZE)<>0) Then
В начало

В начало

Совет 267. Используйте VB-объект RegExp для проверки синтаксиса адреса электронной почты

В современных приложениях часто бывает необходимо, чтобы пользователь вводил информацию о своей компании, включая адрес электронной почты. При этом нужно быть уверенным не только в том, что такой адрес содержит знак @ и точку, но и в том, что все остальные символы представлены буквами, числами или знаками подчеркивания. На первый взгляд такая задача может показаться не очень простой, если вы будете пользоваться только стандартными VB-функциями обработки строк. К счастью, в VB существует объект RegExp, который существенно упрощает работу.

Однако прежде чем приступить к использованию этого объекта в VB, следует загрузить библиотеку VBScript 5.0 DLL, которая находится по адресу: www.microsoft.com/msdownload/vbscript/scripting.asp

После установки библиотеки в диалоговом окне References в VB появится строка Microsoft VBScript Regular Expressions. Добавьте эту ссылку к проекту — и можно приступать к работе. Следующий код проверяет адрес электронной почты, который вводится в текстовом поле Text1:

Dim myReg As RegExp
Private Sub Form_Load()
    Set myReg = New RegExp
    myReg.IgnoreCase = True
    myReg.Pattern = "^[\w-\.]+@\w+\.\w+$"
End Sub
Private Sub Text1_Validate(Cancel As Boolean)
    Cancel = Not myReg.Test(Text1)
End Sub

Приведенный в этом коде шаблон может принимать любое количество числовых и буквенных символов, символов подчеркивания, десятичной точки и тире перед знаком @, но только числа, буквы и символы подчеркивания до и после точки.

В начало

В начало

Совет 268. Как осуществить прокрутку элемента управления ListView в VB до заданного элемента

Известно, что элемент управления ListView позволяет простым способом связать элементы списка со значками, рисунками и строками отчетов. С его помощью легко выбрать определенный элемент списка. Однако это не всегда означает, что данный элемент будет виден пользователю. Например, если список содержит много элементов, то для просмотра последнего из них необходимо пользоваться линейкой прокрутки. К счастью, элемент управления ListView предоставляет возможность программным образом перейти к заданному элементу.

Для каждого элемента списка существует метод EnsureVisible, при вызове которого указанный элемент списка выводится в видимой части элемента управления ListBox. Для иллюстрации поместите этот компонент на форму, а затем щелкните на нем правой кнопкой мыши и выберите команду Properties из быстрого меню. В диалоговом окне Properties Pages измените свойство View на 3 — lvwReport. Затем перейдите во вкладку Column Headers, выберите поле теста Insert Column и введите там «Какой элемент?». Щелкните OK. И наконец напишите следующий код для события Load формы:

Private Sub Form_Load()
    Dim x As Integer
    With ListView1
        For x = 1 To 20
            .ListItems.Add Key:="Элемент" & x, _
                Text:="Элемент" & x
        Next x
        .SelectedItem = .ListItems("Элемент11")
        .SelectedItem.EnsureVisible
    End With
End Sub

Запустите проект на выполнение. VB откроет форму, выведет окно списка и выделит в нем одиннадцатый элемент.

В начало

В начало

Совет 269. Работа в VB с формулами, представленными в виде строковых переменных

Если до того, как начать программировать на VB, вы уже работали с Microsoft Access, то вы, вероятно, ощутили нехватку в VB очень удобного метода Eval, который вычисляет заданную строковую переменную, как если бы она была кодом. Так, в Access вы могли легко вычислять математические выражения, передаваемые как строки, например выражения подобного вида:

iResult = Eval("(2 * 3) + 5)")

где iResult принимает значение 11.

Чтобы получить те же возможности в VB, вам, несомненно, пришлось обратиться к сложным функциям синтаксического разбора строк. Или же вы были вынуждены добавить к своему проекту библиотеку из Access, что существенно усложняет его для реализации столь простого метода.

Теперь, с выходом VB6, вам больше не придется прибегать к подобным ухищрениям, чтобы воспользоваться методом Eval, поскольку Microsoft включила его в элемент управления Script. С помощью этого компонента вы можете добавлять к своим приложениям возможность написания сценариев конечным пользователем. Потому-то для реализации данной возможности в состав Script и вошел метод Eval, благодаря которому вы сможете легко вычислять математические строковые переменные.

Элемент управления Script находится по адресу http://msdn.microsoft.com/scripting/. Загрузите его и выполните следующий простой пример, где для события Click командной кнопки введен такой код:

Private Sub Command1_Click()
    MsgBox txtFormula & " = " & SC1.Eval(txtFormula)
End Sub

Здесь элемент управления SC1 вычисляет математическую формулу, вводимую в поле текста txtFormula.

В начало

В начало

Совет 270. Как сделать невидимым курсор мыши в VB-приложении

APi-функция ShowCursor предоставляет простой способ сделать невидимым курсор мыши:

Private Declare Function ShowCursor Lib "user32" _
    ByVal bShow As Long) As Long

Если вы зададите параметр bShow как 0, курсор мыши исчезнет, если как 1, — появится вновь. Только помните, что при использовании этой функции курсор просто становится невидимым, а это совсем не означает, что он отключен. Чтобы продемонстрировать, что мы имели в виду, добавим приведенное выше описание функции к проекту и введем следующий код для формы:

Dim blnShow As Boolean
Private Sub Form_Click()
    blnShow = Not blnShow
    ShowCursor blnShow
End Sub
Private Sub Form_Load()
    blnShow = True
End Sub
Private Sub Form_QueryUnload _
    (Cancel As Integer, UnloadMode As Integer)
    ShowCursor True
End Sub

Запустим проект на выполнение. Щелкнем форму, и VB уберет с экрана курсор мыши. Снова щелкнем форму, и курсор появится вновь. Если бы курсор мыши был действительно отключен, то мы бы не смогли вернуть его на экран одним только щелчком формы. Теперь опять щелкнем форму, чтобы курсор сделался невидимым, и перетащим его к линейке меню интегрированной среды разработки VB. Когда невидимый курсор будет перемещаться от одной кнопки меню к другой, последняя будет приподниматься над поверхностью, сообщая о том, что она готова для щелчка. И действительно, вы по-прежнему можете пользоваться мышью для вызова команд меню или выбора объектов на экране.

КомпьютерПресс 4'2000 


Наш канал на Youtube

1999 1 2 3 4 5 6 7 8 9 10 11 12
2000 1 2 3 4 5 6 7 8 9 10 11 12
2001 1 2 3 4 5 6 7 8 9 10 11 12
2002 1 2 3 4 5 6 7 8 9 10 11 12
2003 1 2 3 4 5 6 7 8 9 10 11 12
2004 1 2 3 4 5 6 7 8 9 10 11 12
2005 1 2 3 4 5 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
Популярные статьи
КомпьютерПресс использует