, который задает границы новой строки в таблице, и тег , который задает границы новой ячейки в строке. Теги также сопровождаются атрибутами - ключевыми словами с определенными значениями в пределах специфического тега. Тег <А> используется для выделения гиперссылки в документе, он распознает атрибут HREF Гиперссылка с домашней Web-страницей Microsoft задается так.
This link will take you to
Microsoft's home page.
Текст между тегами <А> и А> отмечен как гиперссылка (отображается на дисплее другим цветом и подчеркиванием). Атрибут HREF в теге <А> задает URL или адрес, на который следует переключиться при вызове этой гиперссылки.
Далее в главе приведено краткое введение в HTML (параграф "Учебник по HTML (для начинающих)").
В нем рассказывается об элементах языка, используемого в примерах следующих глав. Эта информация предназначена для программистов на VB Для полной справки по HTML, включая все теги, распознаваемые Internet Explorer, и их атрибуты, посетите следующий сайт:
http://www.microsоft.com/workshop/author/newhtml
Индексы
Индексы — это структуры, которые определяют порядок записей в таблице. Обычно данные в таблице не упорядочены. На практике, тем не менее, возникает необходимость обращаться к ним в определенном порядке. Когда печатается список имен заказчиков, необходимо печатать их в алфавитном порядке. Если печатаются почтовые этикетки, то, вероятно, необходимо печатать их в порядке почтового индекса. Тип обработки, выполняемой над базой, определяет порядок, в
котором должны быть расположены строки таблицы. Это главное для таблицы, которая будет по-разному использоваться в различных операциях.
Если запрос обуславливает различный порядок строк в таблице, то их придется реорганизовать. Но для этого требуется слишком много времени. Решение проблемы состоит в том, чтобы поддерживать маленькие таблицы, называемые индексами, которые определяют последовательность чтения записей из таблицы. Индексный файл не содержит информацию, которая появлялась бы в таблице непосредственно: только числа, определяющие порядок записей.
Предположим, пятая запись в таблице должна появиться первой, когда строки таблицы запрошены в алфавитном порядке. Первый элемент индексного файла содержит значение 5. Значит, когда из базы данных будут извлекаться строки заданной таблицы, сначала будет извлечен пятый элемент.
Примечание
В гл. 5 рассматривалось приложение, в котором использовалось свойство ItemData списка для поддержания отсортированных данных с помощью элемента управления ListBox. Индексные файлы подобны элементам свойства ItemData.
Таблица может иметь более одного индекса. Индексы всех таблиц в базе данных поддерживаются механизмом JET. Единственное, что нужно выполнить — это задать поля, на которых будет основан индекс.
В каких случаях индексация не нужна?
Когда запись модифицируется, индексы также должны модифицироваться. Это заметно увеличивает время модифицирования записи. Индексы также увеличивают занимаемый объем памяти и, следовательно, время и ресурсы, необходимые для обычного резервирования.
Поддержание множественных индексов для каждой таблицы на всякий случай — хорошая идея, однако за индексные файлы нужно платить. Вводить дополнительные индексы надо только в том случае, если они необходимы для соответствующей операции над базой данных. Слишком много индексов, особенно для очень больших таблиц, которые часто изменяются, замедлят их обработку.
Инициализация элемента управления и его свойств
Для этих целей можно использовать два события -
Initialize и InitProperties. Событие InitProperties предназначено для задания свойствам начальных значений.
До сих пор за нас это делал мастер интерфейса пользователя ActiveX. Событие Initialize может использоваться для выполнения кода инициализации, который не использует свойства. Если попытаться задать значение свойства или выполнить какое-либо действие на элементе управления (например, вывести Title на элементе управления оператором UserControl. Print "Control"), то будет выдано следующее сообщение об ошибке:
Object Required
Объект UserControl еще не существует. Именно поэтому оператор:
UserControl.Print "Control"
работает только тогда, когда находится внутри других событий, но не внутри события Initialize.
Что же можно сделать из кода этого события? Очень немного. Можно присвоить начальные значения закрытым переменным элемента управления, но нельзя обращаться к свойствам элемента управления и даже к объекту Ambient.
Больший интерес представляет событие InitProperties, которое Происходит после того, как создан элемент управления. Следует только помнить, событие Initialize имеет место каждый раз, когда происходит переключение между режимом конструирования и выполнения, но событие InitProperties за ним не следует.
Совет
Событие InitProperties происходит тогда, когда элемент управления создается и помещается на контейнер первый раз. После этого роль события InitProperties в цикле жизни элемента управления берет на себя событие ReadProperties. При изменении значения некоторых свойств элемента управления для Visual Basic бессмысленно сбрасывать эти свойства в их начальные значения. Вместо этого, он считывает их из Property Bag при вызове события ReadProperties.
В событии InitProperties можно вставить код инициализации, который управляет внешним видом "новорожденного" элемента управления. Например, можно определить, что случится, если пользователь помещает элемент управления на форму с помощью двойного щелчка на пиктограмме вместо перетягивания элемента управления на форму. Когда Visual Basic помещает экземпляр элемента управления на форму, он уже имеет некоторый размер (который одинаков для всех элементов управления). Если элемент управления содержит длинный заголовок, геометрическую фигуру или любой другой элемент, который должен быть виден полностью, можно откорректировать начальный размер элемента управления с помощью нескольких операторов:
UserControl.Width = 2400
UserControl.Height = 1200
При помещении элемента управления на форму с помощью двойного щелчка на его пиктограмме его начальный размер будет равен 2400 на 1200 твипов.
Объекты Extender и Ambient также доступны из процедуры InitProperties. Заголовок на элементе управления можно отобразить тем же шрифтом, что и у контейнера, следующим образом.
Set Font = Ambient.Font
UserControl.Print "FabControl"
Эти две строки отображают строку
"FabControl" шрифтом контейнера в верхнем левом углу элемента управления. Кроме того, шрифт элемента управления также будет первоначально установлен равным шрифту формы.
Примечание
Заголовок "FabControl" появится на новом экземпляре элемента управления только в том случае, если свойство AutoRedraw установлено в True. Элемент управления создается "за кулисами" и реально отображается только после того, как весь код инициализации будет выполнен. Если свойство AutoRedraw элемента управления равно False, строка будет первоначально напечатана на элементе управления, но когда элемент управления отображается, эта строка не является частью растрового изображения (вспомните гл. 6) и не будет перерисовываться.
Инициирование событий из кода класса
Это достаточно сложная тема и ее можно было бы благополучно пропустить. Инициирование событий из кода класса — не очень распространенная практика. Так как классы не имеют видимого интерфейса пользователя, то не существует внешних событий, реагируя на которые можно вызывать их обработчики. В следующей главе описано, как генерировать ошибки из кода элементов управления ActiveX. Элементы управления ActiveX имеют видимый интерфейс и должны реагировать на многие внешние события, такие как события мыши и клавиатуры. Как станет ясно, инициировать события из элементов управления ActiveX достаточно просто.
Совсем другая ситуация с ActiveX DLL. Классы инициируют события, основанные на внутренних событиях, таких как лимит времени. Модифицируем класс CTimer так, чтобы он вызывал события Minute и Hour каждый раз, когда минута или час прошли. Доработанный проект CTimer вместе с его тестовым проектом находится в папке EVNTimer в папке этой главы на компакт-диске.
Так как класс CTimer не может отслеживать время непрерывно, необходимо ему помочь, воспользовавшись элементом управления Timer. Но модуль класса не имеет формы, и как тогда можно использовать элемент управления Timer? Мы добавим форму к проекту, но отображаться она не будет. Это будет скрытая форма с элементом управления Timer. Модуль класса будет иметь доступ к элементу Timer на форме и перехватывать его событие Timer. Это один из способов использования элемента управления ActiveX в модуле класса.
1 . В окне Project Explorer выберите компонент CTimer и переименуйте его на EventTimer, как показано на рис. 15.3. Затем откройте меню Project, выберите команду Add Form (Добавить форму) и добавьте новую форму в проект модуля класса.
Примечание
Убедитесь, что новая форма появилась под компонентом
EventTimer, а не TestProject. Если форма добавилась к тестовому проекту, удалите ее и повторите процесс.
2 . Откроите форму Form1 в режиме конструирования и поместите на нее экземпляр элемента управления Timer. Установите его свойство Enabled в True, а его свой ство Interval в 10000. Это значение соответствует 10 секундам. Не нужно, чтобы TimerClass тратил слишком много компьютерного времени на обработку событий Timer, так что установите большой промежуток времени ожидания.
На рис 15.3 показан проект EventTimer в среде разработки Visual Basic. Обратите внимание на компоненты в окне Project, на Form1 в окне Design и на окно Code класса. Новый класс называется EventTimerClass, а проект называется EventTimer. Открывая этот пример проекта, не забудьте выбрать проект теста и добавить ссылку на EventTimer к нему.
Наша задача - перехватить событие Timer от элемента управления. Timer внутри модуля класса и использовать его для генерирования событий Minute и Hour. Событие Minute первый раз происходит через 60 секунд после запуска таймера и каждые 60 секунд после этого. Аналогично, событие Hour происходит первый раз через 60 минут после начала работы класса и через каждые 60 минут после этого.
Рис. 15.3. Проект EventTimer подобен проекту CTimer, но он использует внутренний таймер для отсчета времени
3 . Чтобы обеспечить доступ к элементу управления на другой форме, необходимо создать переменную формы в самом классе. Вставьте следующие объявления в окно программного кода класса.
Dim cFrrn As Formi
Dim WithEvents eTimer As Timer
Ключевое слово WithEvents
сообщает Visual Basic, что элемент управления должен содержать свойства, методы и события (вот почему он назван eTimer). Эти переменные оживут, если им поставить в соответствие объекты. Это должно произойти внутри события инициализации класса.
4 . Вставьте следующие строки в событие Class_Initialize:
Private Sub Class_Initialize ()
Set cFrm = New Form1
Load cFrm
Set eTimer = cFrm.Timer1
End Sub
Первый оператор связывает новый экземпляр объекта Formi с переменной cFrm. Затем загружается новая форма. С этого времени реализуется доступ к элементам управления, размещенным на форме. Последняя строка делает переменную eTimer
эквивалентной элементу управления Timer1 на форме Form1. Теперь класс может иметь доступ к элементу управления Timeri на форме Formi с помощью имени eTimer, также как и Form1 имеет доступ к нему с помощью имени Timer1. Два выражения эквивалентны, но нельзя получить доступ к элементу управления Timer как Form1.Timer1 из модуля класса.
Если открыть раскрывающийся список объектов в окне программного кода модуля класса, то можно увидеть объект eTimer. Так как объектная переменная eTimer объявлена с использованием ключевого слова WithEvents,
то есть возможность программировать его события. Вот почему его имя появилось в списке объектов. Выберите объект eTimer
в списке объектов и затем откройте список событий в окне Code. Появится имя события Timer. Выберите его, после чего можете программировать событие eTimer_Timer(), что эквивалентно программированию события Timer1_Timer.
5 . Добавьте строки программного кода 15.5 в обработчик события eTimer_Timer.
Программа 15.5. Инициирование событий из кода класса
Private Sub eTimer_Timer()
Static seconds As Long
Static minutes As Long
Static hours As Long
Dim RaiseMinutes As Boolean, RaiseHours As Boolean
If Not Counting Then Exit Sub
RaiseMinutes = False
RaiseHours = False
seconds = seconds + eTimer.Interval / 1000
If seconds = 60 Then
minutes = minutes + 1
seconds = 0
RaiseMinutes = True
If minutes = 60 Then
hours = hours + 1
minutes = 0
RaiseHours = True
End If
End If
If RaiseHours Then
RaiseEvent Hour
Elself RaiseMinutes Then
RaiseEvent Minute
End If
End Sub
Булева переменная Counting
объявлена в секции объявлений формы и служит признаком работы таймера. Если таймер остановлен, то не нужно обрабатывать событие Timer. Эта переменная устанавливается в True внутри метода StartCounting и устанавливается в False внутри метода StopCounting.
Эта подпрограмма вызывается каждые 10 секунд и увеличивает число прошедших секунд,
прибавляя к ним 10. Каждые 60 секунд она увеличивает число минут на 1, и каждые 60 минут она увеличивает число часов на 1. Если переменная minutes равна 0 (это значит, что она достигла значения 60 и сброшена в 0), должно быть инициировано событие Hour. Если это не так, то проверяется значение переменной seconds.
Если она равна 0, то должно быть инициировано событие Minute. В результате этого инициируются 59 последовательных событий Minute, затем событие Hour, после чего процесс повторяется. Так как нельзя выдать сразу два события, то событие Minute пропускается, когда инициируется событие Hour. Ясно, что событие Hour означает наличие и события Minute.
6 . Для того чтобы надлежащим образом инициировать события, необходимо объявить их имена. Добавьте следующие строки в окно кода модуля класса (вне любой процедуры):
Event Minute ()
Event Hour ()
Полный программный код EventTimerClass показан ниже. Обратите внимание на сходство и отличия с простым классом CTimer. Процедура Property Get и метод класса не изменились. Добавлен только код для доступа к элементу управления Timer на невидимой форме и запрограммировано событие Timer элемента Timer для инициирования соответствующих событий.
Программа 15.6. Листинг EventTimerClass
Dim cFrm As Formi
Dim WithEvents eTimer As Timer
Dim totallnterval As Double
Dim Tl As Double
Dim Counting As Boolean
Event Minute()
Event Hour()
Public Sub StartCounting ()
Tl = Time
Counting = True
End Sub
Public Sub StopCounting()
totallnterval = totallnterval + Time - Tl
Counting = False
End Sub
Property Get ElapsedTime() As Double
ElapsedTime = totallnterval
End Property
Public Sub ResetTimer()
totallnterval = 0
End Sub
Private Sub Class_Initialize ()
Set cFrm = New Formi
Load cFrm
Set eTimer = cFrm.Timer1
End Sub
Private Sub eTimer_Timer()
Static seconds As Long
Static minutes As Long
Static hours As Long
Dim RaiseMinutes As Boolean, RaiseHours As Boolean
If Not Counting Then Exit Sub
RaiseMinutes = False
RaiseHours = False
seconds = seconds + eTimer.Interval / 1000
If seconds = 60 Then
minutes = minutes + 1
seconds = 0
RaiseMinutes = True
If minutes = 60 Then
hours = hours + 1
minutes = 0
RaiseHours = True
End If
End If
If RaiseHours Then
RaiseEvent Hour
Elself RaiseMinutes Then
RaiseEvent Minute
End If
End Sub
Internet и Web-протоколы
Internet — это глобальная распределенная компьютерная сеть с общим протоколом связи TCP/IP (Transmission Control Protocol/Internet Protocol). TCP/IP - универсальный протокол, одинаково выполняющийся на всех компьютерах и операционных системах. Глубокие знания о нем для пользователя Internet необязательны.
Каждый компьютер в сети имеет уникальный адрес, например, 193.25.84.100. Каждое число, разделенное точкой — это значение в диапазоне от 0 до 255. Из этого следует, что Internet не может иметь подключенными более 4 миллиардов компьютеров (256*256*256*256). Это количество не так велико, как может показаться, потому что большая часть допустимых значений зарезервирована. Другие — переданы организациям, которые могут использовать или не использовать предоставленные адреса по своему усмотрению. Для предоставления большего количества адресов провайдеры Internet-служб используют область адресов (т.к. не все пользователи связываются одновременно, то те же 256 адресов позволяют обслуживать более 1000 пользователей). К сожалению, невозможно, чтобы все пользователи имели уникальные IP-адреса, подобно адресам E-mail. Каждый раз при связи с провайдером конкретному компьютеру присваиваются различные IP-адреса.
Если TCP/IP предоставляет возможность любым двум компьютерам связываться между собой с помощью Internet, то зачем нужен другой протокол? HTTP является протоколом Web. В то время как TCP/IP позволяет двум компьютерам связываться на аппаратном уровне, HTTP же является языком серверов и клиентов и используется для обмена информацией. HTTP оптимизирован для запрашивания и предоставления документов HTML. Например, при обмене файлами по Internet используется FTP (File Transfer Protocol - протокол передачи файлов). Используемый протокол зависит от типа передаваемой информации. Тем не менее, все эти протоколы произошли от TCP/IP.
В следующем параграфе вы подробнее узнаете о компонентах Web и об эволюции Web-документов.
Исходный текст приложения
Messages
В обработчике события Load (Загрузка) формы создаются две объектные пере менные — OLApp, которая указывает на приложение Outlook, и mNameSpace,
которая указывает на папки Outlook. Эти переменные объявлены в разделе декларации формы:
Dim OLApp As Application
Dim mNameSpace As NameSpace
Затем в программе объявляется переменная AllContacts, которая указывает на элементы (объекты) в папке Contacts.
Dim AllContacts As Items
Программа просматривает все объекты в семействе AllContacts и добавляет имена контактов (свойство FullName) в окно элемента управления Combo 1. Значение свойства Sorted элемента управления Combol устанавливается равным True, и программа удаляет любые повторяющиеся элементы (которые могут появиться в последовательных позициях списка). Ниже приведена программа, которая обращается к Outlook и устанавливает значение объектной переменной AllContacts.
Программа 14.22.
Инициализация проекта Messages
Private Sub Form_Load()
On Error GoTo OutlookNotStarted
Set OLApp - CreateObject ("Outlook Application")
On Error GoTo NoMAPINameSpace
Set mNameSpace = OLApp.GetNamespace("MAPI")
Set AllMessages = _
mNameSpace.GetDefaultFolder(olFolderInbox).Items
Set AllContacts = _
mNameSpace.GetDefaultFolder(olFolderContacts).Items
Combo1.Clear
For Each mcontact In AllContacts
Combo1.Addltem mcontact.FullName
If Combo1.List(Combo1.NewIndex)= _
Combo1.List(Combo1.NewIndex + 1) Then _
Combo1.RemoveItern Combo1.NewIndex
Next
Combo1.ListIndex = 0
Exit Sub
OutlookNotStarted:
MsgBox "Could not start Outlook"
' (He удалось запустить Outlook)
Exit Sub
NoMAPINameSpace:
MsgBox "Could not get MAPI NameSpace"
' (He удалось получить место расположения MAPI)
Exit Sub
End Sub
Фильтрация сообщений
Пользователь может выбирать имя и (или) диапазон дат для сужения области поиска. Если флажки "From this Sender (От данного отправителя)" и "Between this dates (Между этими датами)" сброшены, то щелчок на кнопке Show Selected Messages приведет к выводу в окно элемента управления List Box информации обо всех сообщениях, находящихся в папке InBox. Если установить один или оба флажка, то программа выведет информацию только о тех сообщениях, которые соответствуют указанным критериям.
Чтобы отфильтровать сообщения, следует воспользоваться методами Find и FindNext объектной переменной AllMessages. Переменная AllMessages объявлена как переменная типа Item. Объект Item поддерживает эти два метода для получения выбранных сообщений. Синтаксис метода Find имеет вид:
Items.Find(filterstring)
где filterstring — это выражение, которое задает критерий фильтрации. Метод Find возвращает объект, тип которого зависит от типа семейства Items. Если метод Find применяется к папке InBox, то будет возвращен объект Mailltem, если же этот метод применяется к папке Contacts, то будет возвращен объект Contactltem. После того как найден первый соответствующий критерию объект, оставшиеся могут быть получены вызовом метода FindNext, причем, без указания параметров.
Параметр filterstring — это строковое выражение, в котором объединены имена полей, логические операции и константы. Чтобы получить информацию о сообщениях, отправленных из Site Builder Network, необходимо набрать следующую строку:
"[SenderName] = "Site Builder Network"
Чтобы получить список всех сообщений, отправленных в октябре 1998 года, следует набрать следующую строку:
"[SentOn] >= ""10/01/98"" And [SentOn] <=""10/31/98""
(Последовательно набранные двойные кавычки указывают на внедренные двойные кавычки, которые вставлены в строку с помощью выражения Chr(34).)
Количество объединяемых критериев поиска зависит только от запросов пользователя. Имена полей для каждого типа объекта могут быть найдены в Object Browser. Выбрав желаемый объект (например, Mailltem или Contactltem), можно просмотреть список его свойств на Панели Members.
В проекте Messages при построении строки-фильтра используются значения различных элементов управления формы. Сначала проверяются значения введенных дат, а затем формируется строка фильтра:
If chkCompany.Value And Combo1.ListIndex >= 0
Then ContactName = Combo1.Text
filterString = "[SenderName] = """ & ContactName S """"
End If
If chkDate.Value Then
If filterString = "" Then
filterString = "[SentOn] >"""&_
DateFrom.Text & """ And [SentOn] <"""&_
DateTo.Text & """"
Else
filterString = filterString & " and _
[SentOn] > """ & DateFrom.Text & """ _
And [SentOn] < """ & DateTo.Text & """"
End If
End If
If filterString = "" Then
filterString = "[SentOn] > ""01/01/1980"""
End If
Обратите внимание на обилие кавычек в выражениях. Два символа двойных кавычек необходимы для вставки символа кавычки в строку. Если значение переменной ContactName равно "Sybex" то выражение:
"[SenderName] = """ & ContactName & """"
приведет к появлению следующей строки:
[SenderName] = "Sybex"
Переменная
filterstring
формируется медленно, в соответствии со значениями, введенными пользователем в окне формы. Если пользователь определяет имя, то оно присваивается свойству SenderName. Если пользователь определяет даты, то они присваиваются соответственно свойству SentOn.
Затем переменная filterstring
передается методу Find объекта AllMessages. Программа просматривает в цикле отфильтрованные сообщения, вызывая метод FindNext. После каждой итерации в окне элемента управления ListBox отображается отправитель очередного сообщения и тема. В это же самое время выбранные сообщения присоединяются к семейству Selectee/Messages:
Set thismessage = AllMessages.Find(filterString)
If thismessage Is Nothing Then
MsgBox "No messages sent in the specified interval"
' (В указанном интервале сообщений не было)
Else
List1.Clear
While Not thismessage Is Nothing
List1.AddItem thismessage.SenderName & _
Chr(9) & thismessage.Subject
SelectedMessages.Add thismessage
Set thismessage = AllMessages.FindNext
Wend
End If
Остальная часть программы проста. Если выполнить щелчок на объекте, находящемся в окне элемента управления ListBox, программа повторно вызывает из семейства SelectedMessages выбранный объект и отображает его основные поля в окне соответствующего элемента управления Label в нижней части экрана и, собственно, текст сообщения - в окне элемента управления TextBox (при этом его свойству Locked должно быть присвоено значение True, чтобы предотвратить редактирование сообщения). Ниже приведен текст программы обработчика события Click элемента управления ListBox.
Программа 14.23. Просмотр объекта
Message
Private Sub List1_Click()
Dim thismessage As Object
Dim MessageAttachments As Attachments
selectedEntry = Listl.Listlndex + 1
If selectedEntry < 1 Then Exit Sub
Set thismessage = SelectedMessages.Item(selectedEntry)
lblSender.Caption = " " & thismessage.SenderName
lblSent.Caption = " " & thismessage.SentOn
lblRecvd.Caption = " " & thismessage.ReceivedTime
txtBody.Text = " " & thismessage.Body
Set MessageAttachments = thismessage.Attachments
If MessageAttachments.Count = 0 Then
Command4.Enabled = False
Else
Command4.Enabled = True
End If
End Sub
Откройте проект Messages в Visual Basic, чтобы исследовать текст программы и ознакомиться с тем, как программа объединяет объекты папки Contacts и использует их для получения информации о E-mail-объектах из папки InBox. Теперь можно изменять программу с целью добавления большего количества критериев выбора или обеспечения возможности работы с различными папками (например, папкой OutBox или подпапками в папке InBox).
Предупреждение
В проекте Messages для отображения имен возможных отправителей почтового сообщения используется свойство контактов FullName. Если имена, использованные в папке Contacts, не соответствуют именам отправителей во входящих сообщениях, то программа не будет выбирать все сообщения, которые ожидались. Имеется много методов установления соответствия контактов и сообщений, но они требуют дополнительных затрат. Например, можно использовать адрес электронной почты каждого контакта, поскольку это общий признак, имеющийся у документа, находящегося как в папке Contacts, так и папке InBox. Но контакт может иметь несколько адресов электронной почты, поэтому следует удостовериться, что поиск выполняется по всем адресам электронной почты выбранного контакта.
VB6 в действии : проект AutoMssg
Приложение AutoMssg демонстрирует процесс создания сообщения электронной почты с помощью VB-приложения и рассылки его с помощью Outlook. Кроме того, в нем демонстрируется альтернативный способ получения информации о контактах и организации хранения этой информации. Сначала приложение отыскивает только названия компаний и отображает их в списке Companies. Пользователь может выбрать компанию и просмотреть ее контакты, используя список Contacts. Чтобы добавить новые имена в список получателей, пользователь должен выполнить двойной щелчок в окне списка Contacts. Список получателей отсортирован, но допускает повторяющиеся пункты. Это связано с тем, что человека с фамилией, например, Смит, можно обнаружить почти в каждой второй компании, поэтому удаление повторяющихся элементов на основании информации о фамилиях получателей — не самая удачная идея Вывод дополнительной информации, делающей каждый пункт списка уникальным, привел бы к загромождению экрана. Поэтому в данном проекте используется сортируемый элемент управления ListBox, в котором содержатся повторяющиеся имена, а пользователю предоставлена возможность выбора.
Программа проекта AutoMssg достаточно проста и здесь не приводится. Можно открыть проект в Visual Basic и ознакомиться с тем, как выполняется обработка сообщения.
Использование гиперссылок в приложениях
Visual Basic
Одна из наиболее привлекательных возможностей Web-страниц — гиперссылки, позволяющие соединять страницы, находящиеся в World Wide Web. Ниже приведен пример использования гиперссылок, как части интерфейса пользователя приложения Visual Basic.
VB6 в действии: проект DemoPage
Приложение DemoPage показано на рис. 21.5 и находится на прилагаемом компакт-диске. Оно состоит из двух форм:
• VBForm;
• WebForm.
Основная форма - VBForm - используется для построения простых фигур методами Visual Basic WebForm воспроизводит HTML-документ, который содержит команды Visual Basic (методы для рисования). HTML-документ содержит команды и несколько гиперссылок. При активизации гиперссылки новый документ не воспроизводится. Вместо этого рисуется фигура на первой форме.
Разработаем две формы (см. рис. 21.5). Основная форма содержит вверху элемент управления Label, на котором отображается команда. Вторая форма (WebForm) -элемент управления WebBrowser, на котором воспроизводится страница Demo.htm.
После загрузки первая форма загружает вторую и воспроизводит HTML-документ на элементе управления WebBrowser. Весь код формы VBForm размещен в событии Load.
Программа 21.5. Событие Load
Private Sub Form_Load()
Dim target
target = App.Path & "\Demo.htm"
WEBForm.WebBrowser1.Navigate.target
WEBForm.Show
End Sub
Рис. 21.5. Две формы приложения DemoPage
Чтобы избежать абсолютных ссылок, предполагается, что HTML-документ (файл Demo.htm) сохранен в папке проекта. Полная страница Demo htm показана на рис. 21.6.
Рис. 21.6. Страница Demo htm в Internet Explorer
Программа 21.6. Приложение Demo Page
Demo Page
Graphics Demo Page
The hyperlinks on this page contact the VBForm and draw various shapes on it.
< P>
Circles
The Visual Basic method for drawing circles on a Form or
PictureBox control is called Circle and its syntax is:
Circle(X, Y), R
X and Y are the center's coordinates and R is the circle's
radius.
Draw A Circle
Squares
To draw squares use the Line method, whose syntax is:
Line(X1, Yl) - Step(X, Y)
X1 and Y1 are the coordinates of the upper left corner of the
square and X and Y are the square's dimension.
Draw A Square
Приложение использует событие BeforeNavigate2 для определения активизированной гиперссылки, затем отменяет переход к этой ссылке и выполняет некоторое действие на первой форме (отображает команду на элементе управления Label и рисует фигуру). Гиперссылки могут быть неверными. Однако событие BeforeNavigate2 не наступает до тех пор, пока гиперссылка не укажет на допустимый URL.
Далее показано определение двух гиперсвязей. Адреса гиперссылок содержат информацию о виде отображаемой формы.
Draw A Circle
<А HREF="http: //127.0.0.1/demo.htm#box">Draw A Square
HTML-документ не содержит никаких указаний на имена "circle" и "box", но они и не нужны. Элемент управления WebBrowser генерирует сообщение об ошибке, но все, что действительно нужно получить - это имя точки привязки. Адрес сервера – это IP-адрес локальной машины (127.0.0.1), который является допустимым именем сервера. Посмотрим, как код события BeforeNavigate2 вызывает действия, происходящие на другой форме.
Программа 21.7. Событие BeforeNavigate2
Private Sub WebBrowser1_BeforeNavigate2(ByVal pDisp As Object,_
URL As Variant, Flags As Variant, _
TargetFrameName As Variant, PostData As Variant, _
Headers As Variant, Cancel As Boolean)
Dim Position As Integer, Shape As String
On Error Resume Next
If UCase(Right$(URL,8)) <> "DEMO.HTM" Then Cancel = True
Position = InStr(URL, "#")
Shape = Mid$(URL, Position + 1)
If Shape = "circle" Then
VBForm.CIs
VBForm.Circle(VBForm.Width / 2, VBForm.Height / 2), _
VBForm.Height / 3
VBForm.Label1.Caption = "Circle(Width / 2, Height / 2),
_
Height / 3"
End If
If Shape = "box" Then
VBForm.Cls
VBForm.Line(VBForm.Width / 4, VBForm.Height / 4) _
-Step(VBForm.Width / 2, VBForm.Height / 2), , В VBForm.Label1.Caption = "Line(Width / 4, Height / 4) _
-Step(Width / 4, Height / 4), , В"
End If
End Sub
Первый оператор отслеживает ошибку и указывает Visual Basic проигнорировать ошибки и продолжать выполнение со следующего оператора. Понятно, что ошибка непременно произойдет, так как обе привязки гиперссылок неправильные. Поэтому установка значения параметра Cancel в True отменяет передвижение. Условный оператор If проверяет, что другие (возможно допустимые) гиперссылки не отменены. Затем программа исследует последнюю часть адреса URL (правее символа #). Если это строка - "circle", то программа рисует окружность на форме VBForm и воспроизводит команду для рисования окружности на элементе управления Label. Если строка - "box", то рисует квадрат на форме и воспроизводит соответствующую команду на Labell.
Можно изменить приложение, добавив другие возможности, поместив подробную справочную информацию в HTML-документ и включив демонстрацию примеров. Описанный подход нельзя считать элегантным, поскольку гиперссылки не стали частью интерфейса Visual Basic. Приложение, тем не менее, показывает, как включить функциональные возможности гиперссылок в приложения Visual Basic.
Использование элемента управления
Script
Элемент управления Script работает очень просто: запоминает процедуры и выполняет их в любое время. Также он вычисляет произвольные выражения и возвращает результат. Напишем несколько простых программ, в которых используется этот элемент управления
Чтобы использовать элемент управления Script в проекте, необходимо добавить его на панель элементов управления. Для этого выполните следующие действия.
1 . Откройте новый проект.
2 . Щелкните правой кнопкой мыши на панели элементов управления и из контекстного меню выберите команду Components для открытия соответствующего диалогового окна.
3 . Установите флажок Microsof Script Control 1.0 (или более новую версию, если она доступна) и щелкните на кнопке ОК.
4 . Как только элемент будет добавлен на панель элементов управления, поместите его экземпляр на форму.
Перечислим наиболее важные компоненты элемента управления
Script, которые используются в наших примерах.
Метод ExecuteStatement
Этот метод выполняет один оператор и возвращает результат Он принимает единственный аргумент - оператор, который будет выполняться. Имеется оператор VBScript.
MsgBox "Programmers of the world unite!"
'(Программисты всех стран, объединяйтесь!)
Чтобы выполнить его (и вывести сообщение на экран), в метод ExecuteStatement передается строка statement, задающая этот оператор.
statement =
"MsgBox " & Chr(34) &
"Программисты всех стран, объединяйтесь!" & Chr(34)
ScriptControll.ExecuteStatement statement
Выражение Chr(34) добавляет двойные кавычки в строковую переменную. Другой подход — использовать две двойные кавычки подряд и объединить два оператора в один.
ScriptControll.ExecuteStatement _
"MsgBox "" Welcome to VBScript!"""
Возможности метода ExecuteStatement
не ограничиваются вызовом одной функции. VBScript позволяет поместить несколько операторов в одну строку, разделяя их двоеточием. Вот небольшой код на VBScript (пригодный для VB).
X=InputBox ("Enter a value from 0 to 5")
WebBrowser
Элемент управления WebBrowser предназначен для создания собственных броузеров, так как он обладает всеми функциональными возможностями просмотра, присущими Internet Explorer. Можно задействовать кнопки Back и Forward, управлять доступом пользователя к узлам и многое другое.
Конечно же, элемент управления WebBrowser не обладает всеми возможностями Internet Explorer. Наиболее значительное ограничение — невозможность доступа к воспроизводимому документу и сохранение HTML-документа из кода программы. Хотя пользователь может открыть контекстное меню документа и выбрать View Source.
Рассмотрим два приложения, которые демонстрируют использование элемента управления WebBrowser в приложениях Visual Basic. Первое приложение является Web-броузером, во втором приложении показано, как использовать HTML-документ в приложениях Visual Basic и добавлять гипертекстовые ссылки.
VB6 в действии: пользовательский Web-броузер
На рис. 21.4 продемонстрирован интересный подход к построению броузеров. Форма содержит элемент управления TabStrip с несколькими страницами, отображающими различные URL - локальные файлы или страницы с удаленных серверов. Можно использовать локальные файлы подсказки для вашего приложения или подсоединить пользователей приложения к Web-серверу для обеспечения их оперативной информацией.
Чтобы создать приложение SuperBrowser, выполните следующие действия.
1 . Откройте новый Standart ЕХЕ-проект и добавьте элемент управления TabStrip к форме. Увеличьте размер формы, и растяните элемент управления TabStrip, чтобы он занял как можно большую часть формы. Можно оставить немного места для нескольких кнопок, например, Back и Forward (которые в этом примере не используются).
2 . Если панель элементов управления не содержит значок WebBrowser, то добавьте его, используя диалоговое окно Components (выберите элемент управления Internet Controls из списка доступных элементов управления). Придется также добавить элемент управления TabStrip к панели элементов управления, используя диалоговое окно Component.
Rates
Перед исследованием кода элемента управления, рассмотрим его использование в тестовом проекте. Тестовый проект состоит из одиночной формы, которая содержит образец элемента управления Rates и кнопку Get Rates. Когда кнопка нажата, элемент управления связывается с Web-сервером и запрашивает курсы обмена различных валют. Код обработчика щелчка на кнопке Get Rates вызывает метод DownLoadRates, передавая URL текстового файла в качестве параметра.
Private Sub bttnGetRates_Click()
RateControll.DownloadRates ("http://127.0.0.I/rates.txt")
End Sub
Файл Rates.txt, используемый в этом примере, находится в корневой папке Web-сервера, который установлен на компьютере. Если на используемом компьютере или другом компьютере в локальной вычислительной сети установлен Internet Information Server или Personal Web Server, то необходимо поместить туда файл Rates.txt и соединится с сервером для его загрузки. Адрес 127.0.0.1 является адресом локальной машины. Если Web-сервер отсутствует, то чтобы узнать, как записать файл на сервер провайдера интернета смотрите инструкции, приведенные в параграфе " Тестирование элемента управления Rates".
Примечание
Не пытайтесь пока проверять проект Rates. Этот элемент управления должен найти информацию на HTTP-сервере: необходимо обеспечить наличие URL для метода DownloadRates. В параграфе " Тестирование элемента управления Rates"
в конце главы показано, как поместить файл Rates.txt на сервере. Выполните инструкции, приведенные в этом параграфе, а затем запустите проект Rates.
Использование элементов управления
ActiveX в других проектах
Добавляя тестовый проект в проект элемента управления, можно конструировать и испытывать элемент управления в одной и той же среде. Это, действительно, очень удобно, однако в таком виде элемент управления не может использоваться в других проектах. После запуска другого экземпляра Visual Basic и попытки добавить созданный элемент управления в панель элементов управления, элемент FLEXLabel в диалоговом окне Component просто не виден. Обычный проект видит только те компоненты, которые были зарегистрированы в системе.
Чтобы зарегистрировать созданный элемент управления, необходимо создать соответствующий ОСХ-файл. Выберите команду Make FIxLabel ocx меню File ОСХ-файл - это все, что необходимо, чтобы включать элемент управления в другие проекты ОСХ-файлы могут быть расположены в любом месте на диске, но чаще всего находятся в подпапке System папки Windows. Можно создать ОСХ-файл в той же самой папке, в которой находится проект. При создании ОСХ-файла Visual Basic регистрирует его в системном реестре. Следовательно, не следует в дальнейшем перемещать созданный ОСХ-файл. Для того чтобы получить возможность использования элемента управления в новых проектах, выполните следующие действия.
1 . Откройте новый Standard ЕХЕ-проект и добавьте новый элемент управления в панель элементов управления.
2 . Щелкните правой кнопкой на панели элементов управления и выберите из появившегося меню пункт Components для вывода одноименного диалогового окна.
3 . Отметьте флажок FLEXLABEL и щелкните на кнопке ОК. На панели элементов управления появится пиктограмма специального элемента управления. Обратите внимание, что имя элемента управления то же, что и имя проекта.
Если, используя эту пиктограмму, поместить элемент управления FLEXLabel на форму. Visual Basic автоматически назовет его Label3Dl (если это первый элемент управления на форме; второй будет назван Label3D2 и т. д.).
Созданный элемент управления был зарегистрирован в системном реестре на данном компьютере, но как быть с другими компьютерами? При распространении приложения, которое использует элемент управления, он должен быть установлен на компьютере до того, как приложение сможет его использовать. Для инсталляции элементов управления на других компьютерах можно использовать утилиту Regsvr32, передавая ей имя ОСХ-файла в качестве параметра. Предполагается, что файл FLXLABEL.OCX скопирован в подпапку System папки Windows. Используйте следующую DOS-команду для установки элемента управления на компьютер:
REGSVR32 FLXLABEL.OCX
Если ОСХ-файл располагается в иной папке, перейдите в эту папку и выполните следующую команду:
С:\WINDOWS\SYSTEM\REGSVR32 FLXLABEL.OCX
Чтобы удалить элемент управления из реестра Windows, используйте утилиту REGSVR32 с ключом /U. Следующая команда удаляет элемент управления FLXLabel из реестра:
С:\WINDOWS\SYSTEM\REGSVR32 FLXLABEL.OCX /U
Использование конструктора
ActiveX DataReport
Имеется еще одна важная операция, выполняемая при создании приложений для работы с базами данных - генерация отчетов. Генерация иерархических отчетов с вычислением итогов (например, отчетов для данных, возвращаемых иерархией объектов Command, созданных в предыдущем параграфе) и их распечатка - одна из основных задач разработчика. Понятно, что хотелось бы работать с утилитой, которая генерирует для нас отчеты только с помощью мыши и позволяет корректно их распечатывать. Второй конструктор ActiveX в Visual Basic 6 — DataReport Designer — предназначен именно для этого. Посмотрим, как конструктор DataReport создает отчет, основанный на иерархии объектов Command. Выполните следующие действия.
1 . Сделайте активным проект Report и дважды щелкните на DataReport Designer в окне проводника проекта, чтобы открыть его. На экране появится шаблон отчета, который не соответствует созданной структуре иерархии объектов Command.
2 . Откройте окно DataReport, чтобы подключить объект DataReport к объекту Command 1.
3 . В окне Properties найдите свойства DataSource и DataMember и установите их в DataEnvironment 1 и Command-1 соответственно.
4 . Щелкните правой кнопкой на объекте DataReport 1 и из контекстного меню выберите команду Retrieve Structure.
Структура иерархии объектов Command отобразится на объекте DataReport (рис. 18.11).
Рис. 18.11. Объект DataReport после чтения структуры объектов Commandl
Полученный шаблон содержит отчет и заголовок страницы. Затем следуют заголовки двух групп для объектов Command 1 и Command2. Как видно, деталями отчета являются поля объекта Commands. После секции Detail следуют соответствующие нижние колонтитулы.
Оставьте заголовок отчета (Report header) пустым (позже можно поместить в него любые строки) и выполните следующие действия.
1 . Чтобы удалить место, в котором обычно размещается Report header (даже если он пуст), щелкните на серой панели под секцией Report header (панель Page header), чтобы выделить ее.
2 . Перемещайте указатель у верхней части панели, пока он не примет форму двойной стрелки.
3 . Нажмите кнопку мыши и переместите панель Page header вверх, чтобы удалить зазор между панелями.
Примечание
Секция Page header содержит номера страниц (и, возможно, другие пункты).
4 . Чтобы показать в этом заголовке номер текущей страницы, щелкните правой кнопкой мыши в области Page header (пустое место под панелью с заголовком "Page Header").
5 . Из контекстного меню выберите пункт Insert Control, чтобы открыть следующее подменю (рис. 18.12).
Рис. 18.12. Элементы управления, добавляемые в объект Report
6 . Добавьте элемент управления Label, а затем - элемент управления Current Page Number.
На рис. 18.13 показан объект Report на последней стадии разработки. Можете использовать этот рисунок в качестве руководства в процессе конструирования вашего отчета.
Элемент управления Label, добавленный в отчет, напоминает стандартный элемент управления Label. Называется он rptLabel,
и у него не так много свойств, как у обычного элемента управления Label. Но их достаточно для того, чтобы определить его внешний вид в отчете. Можно перемещать его с помощью мыши, изменять размер и задавать основные свойства (Font и Caption), используя окно Properties. Это справедливо и для элемента управления Current Page Number. Можно задавать его свойства Font, ForeColor и Caption. По умолчанию Caption установлен в %р — специальное значение, указывающее Visual Basic подставить номер текущей страницы.
Рис. 18.13. Проектирование отчета с помощью конструктора DataReport (окончательный вид отчета показан на рис. 18.14)
Первый заголовок группы (Group Header), соответствует полям объекта Command 1. Очевидно, что здесь необходимо поместить название компании (контактное имя и номер телефона) или другое поле, уникальное для каждого заказчика. Здесь же находятся итоговые поля TotalOrders и CustomerTotal.
Выполните следующие действия.
1 . Поместите два больших элемента управления Label в область первого заголовка группы и установите их заголовки соответственно в Total Orders и Customer Total.
2 . Откройте конструктор DataEnvironment1 и перетащите поля TotalOrders и CustomerTotal, расположенные под объектом Command 1, к двум элементам Label на первом заголовке группы. Выберите подходящий шрифт и выровняйте их.
Следующий заголовок соответствует объекту Command2. Этот объект содержит идентификаторы счетов (поле OrderID) и их итоги (поле OrderTotal). Разместите эти два поля в области второго заголовка группы. Переместите соответствующие поля под объектом Command2 в конструкторе DataEnvironmentI в область второго заголовка.
Если хотите печатать заголовки столбцов для этих двух полей, то поместите их в предыдущий заголовок группы (иначе они будут появляться перед каждым счетом). Разместите два других элемента управления Label и установите их заголовки соответственно в "Order ID" и "Order Total" (см. рис. 18.13).
Перейдем к секции Detail (Детали). Здесь должны быть поля объекта Command3 (этот объект использовался для вычисления итогов), но пока поля объекта Commands нас не интересуют. Поэтому в нашем отчете не будет секции Detail. Второй заголовок группы представляет собой суть секции Detail отчета (эта ситуация достаточно типична при разработке отчетов). Чтобы поэкспериментировать с секцией Detail, поместите в нее подробные сведения о счетах.
Установите высоту секции Detail в 0, передвинув разделитель этой секции вверх. В этом примере мы не используем нижние колонтитулы, но их можно настроить так же, как и заголовки. Вообще, можно поместить любой элемент управления, используя меню Insert, и манипулировать его свойствами с помощью окна Properties.
Чтобы вывести отчет на экран, вызовите метод Show объекта DataReportl. Разместите на форме командную кнопку, назовите ее Report
и введите код обработчика ее события Click.
Private Sub Command1_Click()
DataReport1.Show
End Sub
Запустите проект снова, нажмите кнопку Report и вы увидите разработанный отчет в отдельном окне на экране (рис. 18.14). Две кнопки вверху окна DataReport позволяют распечатать его на любом принтере или экспортировать его в текстовый формат или формат HTML. Практически, конструктор DataReport сделал всю работу. Наиболее важный аспект этого процесса состоит в том, что распечатка отчета создавалась без написания какого-либо кода.
Рис. 18.14. Окончательный вид отчета сгенерирован конструктором ActiveX DataReport
Использование мастера страницы свойств
Для использования мастера страницы свойств выполните следующие действия.
1 . Откройте проект FLEXLabel, если он еще не активен.
2 . Выберите команду Property Page Wizard в меню Add-Ins, чтобы открыть диалоговое окно Add Property Page.
3 . Выберите VB Property Page Wizard.
Мастер страницы свойств поможет по шагам создать страницы свойств элемента управления.
Введение
Это вводное окно, которое, в дальнейшем, можно пропускать, отметив флажок Skip This Screen in Future.
Выбор страниц свойств
В этом окне можно выбрать, какие из стандартных страниц свойств нужны конструируемому элементу управления. Сюда входят следующие страницы.
• StandardFont. Позволяет устанавливать шрифт.
• StandardPicture. Позволяет устанавливать свойства изображения.
• StandardColor. Позволяет устанавливать цвет.
Для нашего элемента управления нужна страница
StandardColor, плюс специальная страница, которую можно добавить, нажав кнопку Add. Мастер при этом запрашивает имя новой страницы. Введите TextProperties и нажмите кнопку Next.
Понятно, почему мастер выбрал страницу StandardColor? Элемент управления имеет свойства Backcolor и ForeColor, которые устанавливаются через страницу свойств StandardColor. Если страница свойств для этих свойств не нужна, очистите флажок, который стоит перед именем страницы свойств. Но нам она нужна для установки цвета, поэтому оставьте эту страницу отмеченной. Кроме того, можно также переименовывать страницы свойств с помощью кнопки Rename.
Связывание свойств со страницами свойств
В этом окне задаются свойства, которые необходимо отобразить на каждой странице свойств. Мастер уже связал свойства цвета со страницей StandardColor, свойства шрифтов со страницей StandardFont, а свойство Picture со страницей StandardPicture. Но специальные свойства не были связаны ни с одной страницей, потому что мастер не знает, кому они принадлежат. Добавить свойство Caption к странице Text можно следующим образом.
1 . Выберите вкладку Text.
2 . Выберите свойство Caption из списка слева и нажмите кнопку с одиночной стрелкой вправо, чтобы добавить свойство к странице свойств Text
3 . Щелкните на кнопке Next, чтобы перейти на последнюю страницу мастера, и затем щелкните на кнопке Finish.
При более тщательном рассмотрении этого окна мастера можно обратить внимание на некоторую странность. В списке доступных свойств появились не все специальные свойства. Вместо этого появились имена других свойств. Мастер не может обрабатывать свойства нестандартного типа. TextAlignment и Effect — специальные (пользовательские) типы данных (перечислимые типы AJign и Effects, которые определены в коде), поэтому они пропущены. Если нужна страница свойств, на которой разработчик может задавать вид элемента управления, нужно добавить свойства TextAlignment и Effect на страницу Text. К сожалению, нет возможности добавить эти свойства посредством мастера. Придется сделать это вручную.
Но сначала давайте посмотрим, что сделал для нас мастер. Выполните следующие действия.
1 . Переключитесь на тестовую форму и щелкните правой кнопкой мыши на элементе управления FLEXLabel.
2 . Из меню выберите Properties (Свойства), чтобы просмотреть две страницы свойств, показанные на рис. 16.10 и 16.11.
Рис. 16.10. Страница свойства Color элемента управления FLEXLabel
Рис. 16.11. Страница свойства Text Properties элемента управления FLEXLabel
Страница Color выглядит хорошо, а вот страница Text Properties нуждается в улучшении. Мастер только поместил на страницу элемент Label и элемент TextBox, a теперь необходимо помимо настройки этих элементов написать соответствующий код.
Вкладка Color имеет список свойств, который содержит имена свойств, связанных с цветом. Если создать еще несколько таких свойств, то они появятся на этой же странице. Чтобы назначить новое значение свойству, сделайте одно из двух:
• выберите свойство, а затем выберите стандартный цвет из палитры Windows, или
• создайте свой цвет нажатием кнопки Edit Custom Color.
Новый цвет появляется перед именем свойства в списке. При нажатии кнопки Apply соответствующая часть элемента управления будет перерисована в соответствии с новой установкой. Страница Text Properties позволяет определять значение свойства Caption, вводя значение в элемент управления TextBox. Поэкспериментируйте с другими вкладками страниц свойств, чтобы посмотреть, как они себя ведут.
В окно Project мастер добавил другую папку - Property Pages. Эта новая папка содержит файл свойств Caption. Выполните на ней двойной щелчок и страницы откроются в режиме конструирования. Обратите внимание, что кнопки OK, Cancel и Apply не являются частью формы. Они принадлежат элементу управления TabStrip, который отображает страницы свойств во время выполнения (этот элемент управления не доступен и не может быть даже настроен). Кроме того, нет формы для свойств Font, Color и Picture. Это стандартные страницы свойств и они управляются Visual Basic. Модифицировать страницы, сгенерированные мастером, нельзя, однако можно создать свою страницу для выбора цвета, если уж не нравится имеющаяся.
Итак, исследуем код, созданный мастером для страницы свойств CaptionProperties.
Программа 16.10. Станица свойств CaptionProperties
Private Sub txtCaption_Change()
Changed =
True
End Sub
Private Sub PropertyPage_ApplyChanges ()
SelectedControls(0).Caption = txtCaption.Text
End Sub
Private Sub PropertyPage_SelectionChanged ()
txtCaption.Text = SelectedControls(0).Caption
End Sub
Подпрограмма txtCaption_Change() вызывается каждый раз, когда пользователь что-либо печатает в поле txtCaption. Устанавливая переменную Changed в Тruе, код разблокирует кнопку Apply (которая заблокирована до тех пор, пока свойство Caption не изменится). Visual Basic использует свойство Changed для определения момента разблокирования кнопки Apply.
Конечно, новые установки не применяются к элементу управления автоматически. Код, который фактически производит изменения, должен быть вставлен в обработчик события PropertyPages_ApplyChanges, которое вызывается каждый раз, когда нажимается кнопка Apply. Это событие и модифицирует свойства элемента управления. Поскольку страница свойств является отдельной формой, она не может знать, какой элемент управления выбран в данный момент (поскольку на форме может присутствовать несколько экземпляров одного элемента управления). Из-за этого для доступа к выбранному элементу управления код использует объект SelectedControls() - семейство, которое представляет собой все выбранные элементы управления на форме. Заметим, что элемент семейства с индексом 0 является первым выбранным элементом управления. И, наконец, событие PropertyPage_SelectionChanged() вызывается всякий раз, когда пользователь выбирает другую вкладку страницы свойств. Это хорошее место для размещения кода инициализации. Код обработчика процедуры PropertyPage_SelectionChanged() присваивает текущие установки свойству Caption выбранного элемента управления элементу TextBox, в котором пользователю предлагается ввести новое значение свойства.
Использование метода
HitTest
Для работы с различными элементами управления можно использовать метод HitTest, который позволяет обнаруживать объект, заданный координатами точки. Этот метод использовался в проекте LVWDemo (см. гл. 8). Сейчас же рассмотрим метод HitTest подробнее, чтобы увидеть, как он использован совместно с функцией GetCursorPos().
Метод HitTest применяется только по отношению к некоторым элементам управления, являющимся контейнерами. Например, объект
ListView может содержать несколько объектов Listltem. Когда пользователь выполняет двойной щелчок в окне объекта ListView, вызывается событие DblClick,
но с его помощью нельзя определить место, где был выполнен щелчок. Чтобы выяснять, на каком именно объекте был выполнен двойной щелчок, следует использовать функцию GetCursorPos(). Она позволяет определить координаты указателя и передать их методу HitTest, который возвратит ссылку на объект, расположенный в указанном месте.
Вернемся к проекту LVWDemo и рассмотрим обработчик события DblClick в объекте ListView. Окно объекта ListView заполнено названиями компаний и связанными с ними данными. Поскольку эти объекты отображаются в виде значков (рис. 13.6), то нужно определить, на каком именно значке был выполнен щелчок (или двойной щелчок). Об отслеживании одиночного щелчка "беспокоится" обработчик события ItemClick,
генерирующий соответствующее сообщение. Обработчик события ItemClick объявляется следующим образом.
Private Sub ListViewl_ItemClick(ByVal Item As ComctLib.Listltem)
Однако обработчик события ItemDblClick отсутствует, вместо него объявлен обработчик события DblClick.
Private Sub ListViewl_DblClick()
Хотя обработчик события DblClick не позволяет получить сообщение об объекте, на котором он выполнен, обычной практикой является использование элемента управления ListView для реакции на двойной щелчок. При этом программа может косвенно обнаруживать объект, на котором выполнен двойной щелчок с помощью функции GetCursorPos() и метода HitTest. Чтобы определить координаты точки, в которой был выполнен двойной щелчок, выполните следующее.
Рис. 13.6. Приложение LVWDemo использование функции GetCursorPos() для получения информации об объекте, на котором выполнен щелчок.
Сначала объявите в модуле функцию GetCursorPos() и структуру данных POINTAPI.
Type POINTAPI
х As Long
у As Long
End Type
Declare Function GetCursorPos Lib "user32" Alias "GetCursorPos" _
(IpPoint As POINTAPI) As Long
В обработчике события DblClick необходимо организовать вызов функции GetCursorPosQ, чтобы выяснить координаты указателя в момент выполнения двойного щелчка.
GetCursorPos dPoint
Членами структуры dPoint являются координаты Х и Y указателя мыши, выраженные в пикселях в системе координат экрана. Другими словами, если функция GetCursorPosQ вызывается из обработчика события DblClick элемента управления ListView, то в результате она возвращает пару координат. Если после этого пользователь переместит форму (приложение) в другое место экрана, а затем выполнит двойной щелчок на том же значке, то координаты точки, в которой выполняется щелчок, изменятся. Следовательно, необходимо предусмотреть процедуру преобразования координат экрана в координаты окна приложения. Для этого нужно вычесть значения свойств Left и Тор окна приложения и элемента управления ListView в этом окне из значений соответствующих координат, возвращаемых функцией GetCursorPos().
X = dPoint.X - Me.Left – ListViewl.Left
Y = dPoint Y - Me.Top – ListViewl.Top
Однако данные действия не вполне корректны, поскольку координаты dPoint. Х и dPoint.Y заданы в пикселях, а все остальные координаты - в твипах (twips). Перед нахождением разности все координаты необходимо преобразовать в пиксели с помощью методов ScaleX и ScaleY. Ниже приведены выражения, позволяющие преобразовать экранные координаты во внутренние координаты элемента управления ListView
Х = dPoint.X - ScaleX(Me.Left + ListViewl.Left,
vbTwips, vbPixels) Y = dPoint.
Y = ScaleY(Me.Top + ListViewl.Top, _
vbTwips, vbPixels)
где Х и Y - координаты указателя в пикселях в момент выполнения двойного щелчка. Координаты (0, 0) соответствуют левому верхнему углу окна приложения. Значения переменных Х и Y должны быть переданы методу HitTest, возвращающему ссылку на объект, на котором выполнен двойной щелчок. Однако для обращения к методу HitTest требуется, чтобы координаты были определены в твипах. Вызов метода HitTest показан ниже.
Set LItem = ListViewl.HitTest(ScaleX(X, vbPixels, vbTwips),
ScaleY(Y, vbPixels, vbTwips))
Значения переменных Х и Y сначала преобразуются в твипы, а затем передаются методу HitTest. В результате возвращается хранящаяся в переменной LItem ссылка на объект, на котором выполнен двойной щелчок. Эта переменная объявляется как Listitem.
Dim LItem As Listltem
Используя переменную LItem, можно получить доступ к свойствам объекта, на котором был выполнен двойной щелчок. Например, можно организовать подсветку этого элемента непосредственно из программы
LItem.Selected = True
или организовать чтение элементов нижнего уровня как членов семейства.
LItem.ListSubItems
Если двойной щелчок выполнен в пределах элемента управления ListView в месте, не содержащем объектов, то переменная LItem получит значение Nothing. В этом случае попытка обратиться к свойствам элемента управления приведет к ошибке выполнения. Чтобы избежать этого, используйте оператор
On Error Resume Next
и организуйте проверку значения переменной LItem.
On Error Resume Next
Set LItem = ListViewl.HitTest(ScaleX(X, vbPixels, vbTwips), _
ScaleY(Y, vbPixels, vbTwips))
If LItem Is Nothing Then Exit Sub
(набор операторов, обеспечивающих доступ к значениям свойств LItem)
Ниже приведен текст программы обработчика события
DblClick элемента управления ListView. Этот фрагмент программы (без операторов, с помощью которых выполняется обработка членов переменной LItem} можно использовать непосредственно в пользовательской программе, если требуется организовать реагирование программы на двойной щелчок на ListView.
Программа 13.8. Обработчик события DblClick элемента управления ListView
Private Sub ListViewl_DblClick()
Dim dPoint As POINTAPI
Dim LItem As Listltem
GetCursorPos dPoint
X = dPoint.X - ScaleX(Me.Left + ListViewl.Left, vbTwips,
vbPixels)
Y = dPoint.Y - ScaleY(Me.Top + ListViewl.Top, vbTwips, vbPixels)
On Error Resume Next
Set LItem = ListViewl.HitTest(ScaleX(X, vbPixels, vbTwips), _
ScaleY(Y, vbPixels, vbTwips))
If LItem Is Nothing Then Exit Sub
If ListViewl.View = Ivwicon Or ListViewl.View = IvwSmalllcon Then
LItem.Selected = True
msg = LItem.Text & vbCrLf
For i = 1 To LItem.ListSubItems.Count
msg = msg & " " & LItem.ListSubItems(i).Text & vbCrLf
Next
MsgBox msg
End If
End Sub
Приведенный пример — не единственный способ использования метода HitTest (и даже не самый типичный). Впрочем, этот пример нетривиален, именно поэтому он столь подробно рассматривался. Этот метод был разработан в основном для обработки события DragDrop. Обработчик события DragDrop сообщает координаты точки, в которую помещен объект. Если объект операции перенести-и-оставить (drag-and-drop) находится в окнах элементов управления типа ListView или TreeView, то требуется знать элемент управления, на который был перемещен объект Ниже приведено объявление обработчика события DragDrop.
Private Sub TreeViewl _ DragDrop(Source As Control, x As Single,_
у As Single)
Поскольку координаты точки, в которую перенесен объект, известны, их можно передать в метод HitTest. чтобы выяснить, на какой из элементов управления был перенесен объект. Заметьте: при этом не требуется преобразовывать или пересчитывать значения координат, поскольку обработчик события DragDrop возвращает их значения, выраженные во внутренней системе координат (в твипах).
Использование модуля класса
Реализуем этот же проект, но с использованием модуля класса. Модуль класса полностью скрывает детали реализации. Он предоставляет через свой интерфейс некоторые функциональные возможности, и разработчику больше не нужно просматривать или редактировать его исходный программный код.
Предупреждение
При попытке открыть проекты примеров с компакт-диска (или из папки диска, куда они были скопированы), появится сообщение об ошибке, означающее, что проект ссылается на компонент, который недоступен. Каждый проект из этой главы создает новый класс, который неизвестен системе. Проигнорируйте это сообщение, откройте проект и добавьте к нему ссылку на класс.
Сохраните существующий проект и начните новый (это будет проект CTIMER из папки для этой главы на компакт-диске). Чтобы создать новый класс сделайте следующее:
1 . В диалоговом окне New Project выберите ActiveX DLL. Visual Basic добавит папку Class Modules в окно Project Explorer, а в нее - модуль класса. Модуль класса называется по умолчанию Class 1. Проект ActiveX DLL не имеет форм.
2 . Измените свойство Name модуля класса на CTimer.
3 . Для нового компонента будет отображено окно Code, так как модуль класса не имеет визуального интерфейса.
4 . Введите строки программного кода 15.3 в окно Code модуля классов.
Программа 15.3. Код класса CTimer
Dim totallnterval As Double
Dim Tl As Double
Public Sub StartCounting ()
Tl = Time
End Sub
Public Sub StopCounting()
totallnterval = totallnterval + Time - Tl
End Sub
Property Get ElapsedTime () As Double
ElapsedTime = totallnterval
End Property
Public Sub ResetTimer()
totallnterval - 0
End Sub
Содержимое модуля классов очень напоминает содержимое обычного модуля, но не имеет общедоступных переменных. Переменная totallnterval не должна быть доступной из какой-либо процедуры за пределами модуля класса. Ее значение может быть прочитано только с использованием процедуры ElapsedTime(). Необходимо отметить, что это специальный тип процедуры, называемый Property Get (Получить свойство). Каждый раз, когда приложение пытается прочитать значение переменной totallnterval, вызывается процедура ElapsedTime(). Ее код считывает значение локальной переменной totallnterval
и назначает его процедуре ElapsedTime(). Затем это значение передается в вызывающее приложение.
Когда приложение пытается установить значение свойства, вызывается похожая процедура
Property Let (Установить свойство).
Рассматриваемый класс не имеет свойств, которые можно установить таким образом, и в нем нет процедур Property Let. Обе процедуры (Property Let и Property Get) обсуждаются далее после рассмотрения небольшого примера. Они действуют подобно буферам обмена между классом и приложением, которое его использует. Поэтому приложение не может установить значение свойства непосредственно.
Примечание
Класс CTimer не предоставляет процедуру Property Let для свойства totallnterval. Как результат, это свойство доступно только для чтения.
Методы модуля класса идентичны методам модуля. Добавление метода к классу является таким же простым, как объявление общедоступной функции или процедуры. Любая процедура может стать методом класса, если она определена в модуле класса и объявлена как Public.
Примечание
Некоторые члены класса могут быть реализованы как методы или как свойства, и не всегда легко сказать, какой путь выбрать. К счастью, это не является настолько важным. Необходимо пытаться придерживаться парадигмы встроенных элементов управления или элементов управления "от третьего лица". Например, если класс является элементом управления ActiveX, то член, который хотелось бы видеть в окне Properties, должен быть реализован как свойство (обратное верно не всегда). Методы должны соответствовать действиям, а свойства — атрибутам. Схема наименований также важна. Имя, имеющее вид GetElapsedTime, наводит на мысль о методе, а имя ElapsedTime - ближе к свойству.
Использование набора записей
В ASP-приложениях Recordset (Набор записей) используется для извлечения и отображения информации, а не изменения содержимого базы данных. Объект Recordset имеет два важных свойства:
• CursorType, указывающий на тип курсора (cursor), используемого с данным объектом;
• LockType, задающий тип блокировки при редактировании набора записей.
Описание этих свойств смотрите в гл. 18. Для перемещения по набору записей используются методы MoveNext (Перейти к следующей), MovePrevious (Перейти к предыдущей), MoveFirst (Перейти к первой), MoveLast (Перейти к последней). Можно создавать закладки для определенных записей, чтобы обращаться к ним незамедлительно. Для отображения всех записей данного набора используется следующий цикл.
<%
Do While Not SelRecords.EOF
{обработка полей}
SelRecords.MoveNext Loop
%>
Чтобы получить доступ к полям Recordset, используйте имя набора и поля или порядковый номер поля в наборе. Например, для доступа к полю ProductName набора записей SelRecords используется такое выражение.
SelRecords ("ProductName")
Если поле ProductName является первым (это определяется предложением SELECT SQL-оператора), то используйте следующее выражение.
SelRecords(1)
Информации, предлагаемой в этой главе, достаточно для построения интерактивных ASP-приложений, которым доступны базы данных на сервере и отображающих выбранные записи. Далее мы покажем, как использовать эти объекты при построении активных серверных страниц. В наших примерах используется база данных NWIND и предполагается, что источник данных для нее настроен надлежащим образом.
Использование операций перетащить-и-опустить в
OLE
В гл. 4 рассматривалось программирование операций перетащить-и-опустить. С их помощью пользователь может "взять" элемент управления в форме и "положить" его в окно другого элемента управления (находящегося на той же или другой форме). Объект-получатель "знает", когда на него опушен другой объект, а его реакция на событие программируется. И все же разработчику необходимо добавить несколько строк в обработчик события Drag Drop.
Во многих приложениях допускается перетаскивание не только элементов управления, но и документов или их частей. Например, можно выделить блок ячеек рабочего листа Excel и перенести его в документ Word. Если для этой операции используется правая кнопка мыши, то можно выполнить связывание данных, содержащихся в документе-источнике, с документом-получателем. Эта операция называется OLE-операцией, так как она выполнима только между приложениями, поддерживающими OLE.
Чтобы добавить возможности OLE-переноса к некоторым элементам управления, размещенным на форме, необходимо установить значения следующих свойств элементов управления.
• OLEDragMode. Определяет, может ли элемент управления инициализировать операцию перетащить-и-опустить (подобно свойству DragMode). Может иметь значения 0 — Manual (Вручную) (элемент управления перемещается только под управлением программы) или 1 — Automatic (Автоматически) (элемент управления перемещается автоматически).
• OLEDropMode. Свойство эквивалентное свойству DropMode Определяет, может ли элемент управления выступать в качестве адресата OLE-операции перетащить-и-опустить. Принимает следующие значения: 0 - None (Нет) (элемент управления не может быть адресатом), 1 - Manual (Вручную) (элемент управления должен быть запрограммирован для реагирования на OLE-операции перетащить-и-опустить) или 2 — Automatic (Автоматически) (элемент управления автоматически становится адресатом).
Простейший способ включения операции перетащить и-опустить в прило жение - это установка значения 1 (Automatic) для свойства OLEDragMode и значения 2 (Automatic) для свойства OLEDropMode.
На рис. 14. 13 показано окно проекта OLEDDAUTO (см. папку Oledd на компакт-диске). Главная форма проекта содержит элементы управления RichTextBox, TextBox и PictureBox. Щелкните на кнопке Load Image, чтобы загрузить изображение в окно элемента PictureBox, и введите какой нибудь текст в окна элементов RichTextBox и TextBox. Можете открыть текстовый файл в окне элемента управления TextBox, щелкнув на кнопке Load Text File.
Рис. 14.13. Проект OLEDDAUTO автоматическое выполнение OLE-перетаскивания
Если изображение переносится в окно элемента управления RichTextBox, то оно будет вставлено в текст в позиции расположения курсора. Можно взять часть текста из окна элемента TextBox и поместить его в окно RichTextBox: он также будет вставлен в место расположения курсора. Таким образом, используя установки Automatic для значений свойств OLEDragMode и OLEDropMode, можно вставить OLE операции перетащить и опустить непосредственно в приложение, не написав при этом ни одной строки кода.
Объект получатель OLE-операции должен быть в состоянии определять и отображать разнообразную информацию. С этой точки зрения, использование элемента управления RichTextBox представляется оправданным. В данном приложении также демонстрируется очень важное свойство элемента управления RichTextBox – OLEObjects. Свойство OLEObjects элемента управления RichTextBox является семейством, в которое входят все объекты данного элемента управления, кроме текста. Перетащите одно или два изображения в окно элемента управления RichTextBox приложения OLEDDAUTO. Затем перетащите несколько файлов с рабочего стола или из любой папки. Проверьте, что приложение и окно папки, содержащее требуемый файл, отображается на экране, а затем перетащите значок файла в окно элемента управления RichTextBox. Чтобы поместить текст в окно элемента управления TextBox, выделите его с помощью мыши и перетащите в окно элемента управления RichTextBox.
После того как объекты помещены в окно элемента управления RichTextBox, щелкните на кнопке List All Object Files. Вы увидите описание каждого объекта, находящегося в окне элемента управления. Программа обслуживания командной кнопки просматривает семейство OLEObjects и выводит в окне проверки значение свойства Class каждого элемента. Для растровых изображений значением свойства Class является StaticDIB. Элементы семейства OLEObjects имеют и другие свойства, например, свойство DisplayType
(определяет, в каком виде объект отображается в окне элемента управления — в виде значка или содержимого) и семейство ObjectVerbs (содержащий все команды-глаголы, распознаваемые объектом). Чтобы узнать, какие действия может выполнять встроенный объект, вызовите метод Fetch Verbs.
Set AllVerbs = RichTextBoxl.OLEObjects (1).FetchVerbs
For i = 1 to AliVerbs.Count
{перечисление всех команд}
(на каждой итерации выводится значение AllVerbs(i)}
Next
Следующий оператор используется для выполнения специфического действия (например, Play для мультимедиа-файла) над одним объектом.
RichTextBoxl.OLEObjects(1).DoVerb("Play")
Использование сценариев
Поначалу роль броузера сводилась к воспроизведению Web-страницы на компьютере клиента. Web-страницы — это простые текстовые файлы с текстом и информацией о том, как текст появляется в окне броузера. HTML — это такой же язык форматирования документов, как и RTF (Rich Text Format — расширенный текстовый формат). Он не является языком программирования. Отображение на экране Web-страницы в окне броузера напоминает воспроизведение RTF файла в элементе управления RichTextBox. Нельзя использовать HTML для выполнения даже простых вычислений, например, для сложения или отображения названия дня недели в окне броузера.
Большинство клиентских компьютеров обладает мощностью гораздо большей, чем требуется для простого отображения документов на экране. Для использования вычислительной мощности клиентов были введены языки написания сценариев, наиболее простым из которых является VBScript. Написание сценариев позволяет Web-разработчикам создавать динамические структуры, вставляя исполняемый сценарий прямо в HTML-страницу. Можно использовать VBScript для программирования элементов Web-страницы так же, как и приложения сервера (используя Сервер активных страниц (CGI)). Позже мы расскажем, как Web-страница может взаимодействовать с броузером, используя сценарии, и как некоторые вычисления, обычно выполняющиеся на сервере, выполняются клиентом.
Использование SQL-операторов
Теперь, когда основные SQL-операторы известны, извлечем данные из баз, используя приложение SQLExec (см. параграф " VB6 в действии: проект SQLExec" этой главы). Как использовать SQL-операторы в собственном приложении?
SQL операторы — это определения объектов RecordSet. Свойство RecordSet элемента управления Data не обязательно должно быть именем таблицы. Как правило, оно содержит только определенные строки таблицы или объединяет данные более чем одной таблицы. Набор записей, который выбирает SQL-оператор из базы данных, назначается элементу управления Data. Рассмотрим простой пример.
Приложение Data1, рассмотренное ранее в главе, отображает несколько полей из таблицы Customers базы данных NWIND. Свойство RecordSource элемента управления Data установлено на имени таблицы Customers, выбранном из раскрывающегося списка. Список рядом с именем свойства RecordSource в окне Properties — комбинированный список. В него можно вводить данные.
Предположим, необходимо, чтобы приложение Datal отобразило имена заказчиков только из Германии. Чтобы выбрать часть таблицы, задайте SQL-оператор, который создаст соответствующий RecordSet в свойстве RecordSource. Выполните следующие действия.
1 . Откройте приложение Datal и выберите элемент управления Data.
2 . В окне Properties найдите свойство RecordSource и введите следующий SQL-оператор (рис. 17.17).
SELECT * FROM Customers WHERE Country = "Germany"
3 . Запустите приложение и используйте кнопки элемента управления Data для перемещения по именам заказчиков из Германии.
Рис. 17.17. Чтобы получить RecordSet (часть таблицы или объединение нескольких таблиц), присвоите свойству RecordSource SOL-оператор
Так как SQL-операторы распространены при работе с базами данных, допускается их непосредственное включение в базы данных. Если открыть список свойства RecordSource элемента управления Data, соединенного с базой данных NWIND, то видно, что он содержит не только имена таблиц. Он содержит имена SQL операторов, сохраненных непосредственно в базе данных. Например, элемент Category Sales for 1995 (категории товаров, проданных в 1995г.) не является именем таблицы. Это — имя запроса, который возвращает уровень продаж за 1995 год, сгруппированный по категории изделия. Если назначить этот объект свойству RecordSource, то поля результирующего RecordSet появятся в списке свойства DataField элемента управления, связанного с данными. В запросе Category Sales for 1995 имена полей, отображаемых в связанных с данными элементах управления — это CategoryName и CategorySales.
Использование связанного с данными элемента управления
List
Элемент управления List связан с определенным столбцом RecordSet и используется как поисковая таблица. Он может использоваться как таблица просмотра для упрощения передвижения по RecordSet (рис. 17.21).
Рис. 17.21. Приложение DBList: элемент управления List используется для просмотра
Этот список содержит имена всех товаров в списке
Products базы данных NWIND, загруженных во время запуска программы. Каждый раз, когда выбирается новый элемент, программа обновляет связанные с данными элементы управления, размещенные на форме, чтобы отобразить поля выбранной записи.
Элемент управления List отличается от элементов управления, связанных с данными, которые были рассмотрены ранее: его можно подсоединить к двум элементам управления Data. Он имеет стандартные свойства DataSource/DataField, которые используются как любой другой элемент управления, связанный с данными, и свойства RowSource и List Field, которые определяют, как заполняется элемент управления.
• RowSource задает источник (RecordSet или элемент управления Data) для начальной загрузки списка.
• ListFieId задает поле, которое используется для заполнения списка.
VB6 в действии: проект DBList
Приложение DBList демонстрирует использование связанного с данными элемента управления List в качестве инструмента перемещения. Форма, показанная на рис. 17.21, содержит ряд полей из таблицы Products базы данных NWIND. Создайте ее, связывая различные текстовые поля с соответствующими полями таблицы элементом управления Data, будто вы собираетесь перемещаться по списку товаров с помощью кнопок перемещения, размещенных на элементе управления Data.
Проблема с элементом управления Data состоит в том, что невозможно реально использовать его для перемещения по RecordSet, даже если он проиндексирован, потому что в каждый момент видима только одна запись. Если бы было можно помещать ключевые значения в элемент управления ListBox и использовать его как инструмент перемещения, то пользовательский интерфейс стал бы удобнее.
ComboBox
Элемент управления ComboBox используется как поисковая таблица (см. приложение Data Entry, рассмотренное ранее в этой главе). Чтобы заполнить список элемента управления ComboBox, необходимо установить свойство RowSource на элемент управления Data, соединенный с базой данных и таблицей, из которой выбираются данные.
Приложение Data Entry (папка DEntry на компакт-диске) содержит скрытый элемент управления Data (называемый Data2), который соединен с таблицей Publishers базы данных BIBLIO. Свойство ListField элемента управления ComboBox — это имя поля, использующееся для заполнения списка. В приложении Data Entry это свойство установлено на поле Name таблицы Publishers. При запуске программы элемент управления ComboBox автоматически заполняется именами издателей из базы данных (рис. 17.22).
Рис. 17.22. Элемент управления ComboBox на форме приложения Data Entry содержит имена всех издателей из базы данных
Элемент управления ComboBox имеет обычные свойства DataSource и Data Field, как и другие элементы управления, связанные с данными. Необходимо, чтобы в приложении Data Entry элемент управления ComboBox функционировал следующим образом.
1 . При запуске программы элемент управления заполняется именами всех издателей.
2 . При перемещении по таблице Titles элемент управления ComboBox извлекает идентификаторы издателей из таблицы Titles, ищет это значение в таблице Publishers и отображает значение поля Name соответствующей записи в окне редактирования.
3 . При добавлении новой записи пользователь определяет издателя книги, выбирая имя в элементе управления ComboBox, а элемент управления сообщает соответствующий идентификатор первому элементу управления Data.
Это выглядит сложно, но все это встроено в элемент управления ComboBox. Уже известно, как реализовать первый пункт с помощью свойств RowSource и ListField. Два других пункта типичны для элементов управления, связанных с данными. Необходимо использовать окно редактирования элемента управления ComboBox как обычное текстовое поле, связанное с полем PubID таблицы Titles. Для этого выполните следующие действия.
Grid
Элемент управления Grid - один из наиболее гибких и мощных элементов управления Visual Basic. Пользователи Microsoft Access знакомы с этим элементом управления. Связываемый с данными элемент управления Grid похож на элемент управления MSFlexGrid (см. гл.9), но имеет два отличия:
• заполняется автоматически из RecordSet,
• имеет встроенные механизмы ввода данных, с помощью которых можно редактировать RecordSet (если он может модифицироваться).
Все, что нужно сделать для заполнения элемента Grid из RecordSet — это установить его свойство DataSource на элемент управления Data. Сетка будет заполнена строками из RecordSet. Ввиду двумерного расположения данных в элементе управления Grid можно увидеть реальную структуру и содержание всего RecordSet. Этот элемент управления использовался для отображения RecordSet на некоторых рисунках в начале главы. Также он использовался для отображения результатов SQL-операторов в приложении SQLExec (которое мы сейчас рассмотрим).
VB6 в действии: проект SQLExec
Ранее в этой главе для экспериментов с SQL-операторами использовалось приложение SQLExec. Создадим это приложение. Для этого выполните следующие действия.
1 . Откройте новый Standard EXE проект.
2 . Чтобы добавить связанный с данными элемент управления Grid на панель Toolbox, выполните щелчок правой кнопкой мыши на Toolbox и выберите команду Components.
3 . В диалоговом окне Components установите переключатель Microsoft Data Bound Grid Control. В этом проекте используется элемент управления Common Dialogs, поэтому установите переключатель Microsoft Common Dialogs Control 5.0 и щелкните на кнопке Close.
4 . Создайте элементы управления (рис. 17.23). Кроме видимых элементов управления, на форме расположен элемент управления Common Dialogs (невидимый во время выполнения) и элемент управления Datal, у которого свойство Visible установлено в False
Рис. 17.23. Приложение SQLExec запросы к базе данных с помощью SQL-операторов и отображение результатов в элементе управления Grid.
Поместите элемент управления List на форму и установите его свойство RowSource на имя элемента управления Datal, а свойство ListFieId — на имя поля, которое необходимо отобразить в списке. Для приложения DBList - это поле ProductName. Свойства DataSource и DataField элемента управления List пусты.
Если запустить приложение сейчас, то ничего не случится, потому что не определено, как элемент управления List реагирует на событие Click. Обработчик события должен переместить элемент управления Data на строку RecordSet, которая содержит в поле ProductName то, же значение, что и строка элемента управления List, на которой выполнен щелчок. Для этого добавьте следующий код в обработчик события Click элемента управления List.
Private Sub DBListl_Click()
Datal.Recordset.Bookmark = DBList1.SelectedItem
End Sub
Свойство Bookmark определяет строку в RecordSet. Установка значения этого свойства вынуждает элемент управления Data размещаться на определенной строке. Свойство Selectedltem (Выбранный пункт) элемента управления - это не текст, отображаемый в окне редактирования элемента управления, а закладка записи, которой принадлежит выбранное поле. Этот код позиционирует элемент управления Data в RecordSet и обновляет связанные с данными метки на форме. Учитывая размер этого приложения, можно сказать, что оно действительно выполняет очень много.
1 . Выберите элемент управления ComboBox и установите его свойство DataSource на Datal (элемент управления Data, связанный с таблицей Titles).
2 . Установите свойство DataField на имя поля, которое необходимо обновить в базе данных. Это поле - PubID.
Поле PubID отображается в элементе управления
ComboBox. Но пользователь видит в ComboBox идентификаторы, а не имена.
Связанный с данными элемент управления ComboBox имеет еще одно свойство — BoundColumn, которое является именем поля в его собственном RowSource и связывает поле, отображаемое в списке, с фактическим полем. Значение свойства BoundColumn должно быть индексным полем, чтобы механизм JET мог быстро его найти. Установите свойство BoundColumn на поле PubID и выполните приложение снова На этот раз в ComboBox появится имя издателя текущей книги. Если выбрать в списке имя другого издателя, то в текущей записи сохранится идентификатор нового издателя.
С помощью свойств DataSource, DataField и BoundColumn можно использовать элемент управления ComboBox как поисковую таблицу. Это позволяет выбрать значения содержательных полей и сохранить значения ключей в базе данных. И все это без единой строки кода! Обратите внимание: имена издателей не отсортированы. Связанный с данными элемент управления ComboBox не имеет свойства Sorted для автоматической сортировки элементов. В случае необходимости сортировки нужно создать новый (соответственно, отсортированный) RecordSet и использовать его для заполнения элемента управления ComboBox.
5. Элемент управления TextBox, с помощью которого вводятся SQL-операторы, называется txtSQL. Установите его свойство MultiLine в True, а свойство Scrollbars - в 2-Vertical
6. Запрограммируем кнопки. Код кнопки Open Database открывает стандартное диалоговое окно File Open (напомню, мы используем элемент управления Common Dialogs), в котором можно выбрать базу данных. Имя базы отображается на элементе управления Label рядом с кнопкой Command.
Программа 17.13. Кнопка Open Database
Private Sub DBOpen_Click()
On Error GoTo NoDatabase
CommonDialog1.CancelError = True
CommonDialog1.Filter = "Databases | *.MDB"
CommonDialogI.ShowOpen
Data1.DatabaseName = CommonDialog1.FileName
Data1.Refresh
If Err = 0 Then
Label1.Caption = CommonDialog1.FileName
Else
MsgBox Err.Description
End If
NoDatabase:
On Error GoTo 0
End Sub
7. Кнопка Execute SQL (выполнить запрос) выбирает SQL-оператор из текстового поля txtSQL и присваивает его свойству RecordSource элемента управления Datal.
Private Sub ExecuteSQL_Click()
On Error GoTo SQLError
Data1.RecordSource = txtSQL
Data1.Refresh
Exit Sub
SQLError:
MsgBox Err.Description
End Sub
Оператор ОnЕггог определяет любую ошибку при выполнении SQL-оператора и отображает информацию о ней в окне сообщений. Присваивание нового значения свойству RecordSource элемента управления не модифицирует его содержимое. Чтобы прочитать новые данные из базы данных и принудительно выполнить модификацию, вызывается метод Refresh элемента управления Data.
Использование
Excel для вычисления математических выражений
В одном из предыдущих параграфов ("Проверка орфографии документов") рассматривался способ заимствования функций проверки орфографии " из Word. Теперь нечто подобное будет проделано с Excel. Excel — превосходное средство для выполнения математических операций. В то же время Visual Basic не содержит функций и методов, позволяющих выполнять вычисления математических выражений (заданных в виде строки — прим. ред.). Если Excel установлен на хост-компьютере, можно обратиться к нему непосредственно из приложения Visual Basic и использовать его для вычисления сложного математического выражения.
Самый простой способ вычисления математического выражения заключается в вызове метода Evaluate объекта Excel.Application. Пусть имеется инициализированная объектная переменная ExcelApp, тогда можно, например, вычислить математическое выражение:
1/cos(0.335) * cos(12.45)
Для этого следует вызвать метод Evaluate объекта ExcelApp и передать ему это выражение в виде параметра (строки):
у = ExcelApp.Evaluate "1/cos(0.335) * cos(12.45)"
Именно это происходит при выполнении щелчка на кнопке
Calculate Expression (Вычислить выражение) в форме ExcelVBA. Ниже приводится текст программы обработчика команды Calculate Expression.
Программа 14.17. Команда Calculate Expression
Private Sub bttnCalculate_Click()
Dim wSheet As Worksheet
Dim wBook As Workbook
Dim expression
StartExcel
expression = InputBox ("Enter math expression to evaluate _
i.e., 1/cos(3.45) * log (19.004)")
'(Введите вычисляемое выражение, например...)
On Error GoTo CalcError
If Trim(expression)
<> "" Then
MsgBox AppExcel.Evaluate(expression)
End If
GoTo Terminate
Exit Sub
CalcError:
MsgBox "Excel returned the following error" & vbCrLf & _
Err.Description
' (Excel возвратил сообщение об ошибке...)
Terminate:
AppExcel.Quit
Set AppExcel = Nothing
End Sub
Программа предлагает пользователю ввести любое математическое выражение. Организовать вычисление произвольных математических выражений, используя программные средства Visual Basic затруднительно. В гл. 20 "Объекты, используемые в сценариях" будет рассматриваться использование элемента управления Script, позволяющего реализовывать вычисление математических выражений.
Visual Data Manager
Visual Data Manager (Визуальный диспетчер баз данных) - инструмент Visual Basic для проектирования баз данных. С некоторыми издержками можно использовать Visual Data Manager для модификации таблиц, обеспечения безопасности данных и экспериментов с SQL. Когда открывается существующая база данных, Visual Data Manager отображает окно базы данных со списком таблиц и свойств этой базы. На рис. 17.7 показано окно Visual Data Manager с базой данных BIBLIO, открытой в режиме разработки. Мы рассмотрим структуру базы данных BIBLIO, но сначала исследуем основные операции приложения Visual Data Manager.
Щелкните правой кнопкой мыши в окне базы данных, чтобы открыть контекстное меню, и выберите пункт New Table. В появившемся диалоговом окне Table Structure задайте необходимые поля.
Рис. 17.7. Visual Data Manager: изменение структуры базы данных
Когда вы добавляете новое поле к таблице щелчком на кнопке Add Field, открывается диалоговое окно Add Field (рис. 17.8).
Рис. 17.8. Visual Data Manager: добавление таблиц в базу данных и полей в таблицы
Опции диалогового окна Add Field приведены в табл. 17.5. На рисунке некоторые из опций заблокированы — их нельзя прочесть. Откройте диалоговое окно Add Field и просмотрите его опции.
Таблица 17.5. Опции в диалоговом окне Add Field
Опция
Описание
Name
Имя поля
OrdinalPosition
Позиция поля в пределах списка полей
Type
Тип поля. Поле может иметь любой стандартный тип VB и два дополнительных: Binary и Memo. Поля типа Binary хранят двоичные данные — звуки и изображения. Поля Memo хранят длинные сегменты текста. Размер полей Memo не могут быть определены на этапе разработки базы данных. (Текстовые поля имеют только определенную длину )
ValidationText
Текст, отображаемый при попытке ввода недопустимых данных
Size
Размер поля в байтах
FixedField
Поле имеет фиксированную длину
VariableField
Поле имеет переменную длину
ValidationRule
Простые правила, используемые для проверки правильности вводимых значений
DefaultValue
Начальное значение, присваиваемое при создании записи
AutoIncrField
Если поле используется в качестве ключа, то нужно установить для него тип Long и проверить поле. При каждом добавлении в таблицу новой записи полю присваивается значение, на единицу больше значения последней записи
AllowZero Length
Выберите эту опцию, если пустая строка является допустимым значением
Required
Выберите эту опцию, если поле не может быть опущено. В таблице со счетами, например, идентификатор заказчика ID так же, как и дата, является необходимым полем
конструктора DataEnvironment при работе с элементом управления DataGrid
Использование конструктора DataEnvironment упрощает подключение к базе данных и создание иерархии объектов Command, сводя их к технологии "укажи и щелкни". Записи, возвращаемые объектом Command можно переместить на форму и подключить к элементам управления связанным с данными. Если переместить по несколько полей из каждого объекта Command на форму, то останется лишь написать код для перемещения по записям объекта Command 1. Каждый раз при перемещении к другому заказчику поля дочернего объекта Command будет обновляться, отражая, таким образом, итоги для выбранного заказчика.
В этом параграфе показано, как добавить поля в элемент управления DataGrid. Новая форма показана на рис. 18.9. Эта форма не является частью проекта, поэтому перечислим действия, необходимые для создания новой формы.
Рис. 18.9. Отображение полей иерархии объектов Command в элементе управления DataGrid
1 . Откройте проект Report (в папке данной главы на компакт диске) и из меню Project выберите команду Add Form, чтобы добавить в проект новую форму Если вы не изменяли имя первой формы, то имя второй формы — Form2.
2 . Снова откройте меню Project, выберите команду Project Properties и сделайте добавленную форму стартовой.
3 . При открытых окне DataEnvironment 1 и форме Form2 щелкните правой кнопкой на объекте Command 1 и перенесите его на новую форму. После отпускания кнопки мыши появится контекстное меню с приглашением выбрать размещение полей объекта Command 1 на форме. Выберите один из вариантов.
• DataGrid - выбранные поля размещаются в элементе управления DataGnd,
• Hierarchical FlexGrid - поля размещаются в элементе MSHFlexGrid,
• Bound Controls - поля размещаются в отдельных элементах управления, связанных с данными (тип этих элементов определяется в поле type).
4 . В открытом меню выберите элемент управления DataGrid и поместите его на форму. По умолчанию DataGrid имеет только два столбца.
5 . Щелкните правой кнопкой на элементе управления DataGrid и выберите команду Edit для выполнения необходимых настроек.
конструктора DataEnvironment при работе с элементом управления MSHFIexGrid
Один из новых и самых интересных элементов управления
Visual Basic 6 -элемент управления FlexGrid (или MSHFlexGnd) Он похож на элемент управления MSFlexGnd (см гл 9), но предназначен для использования с иерархическими объектами ADO. Каждый объект автоматически размещается в своей собственной группе, причем можно развернуть и свернуть строки иерархического элемента управления FlexGrid, как узлы элемента управления TreeView. В параграфе "Проектирование иерархии объектов Command" были показаны записи, возвращенные иерархией объектов (см. рис. 18.2). Обратите внимание: имя каждой компании, отображенное в первой колонке, имеет перед собой знак "+" или "-" Этот знак показывает, что подробности о соответствующих компаниях можно показать или скрыть.
Построим форму, показанную ранее на рис. 18.2. Для этого выполните следующие действия.
1 . Переименуйте форму проекта в DetailsForm и сделайте ее достаточно широкой, чтобы поместились все столбцы.
2 . Откройте окно DataEnvironmentI и убедитесь, что оба окна видимы на экране.
Элемент управления MSHFlexGrid по умолчанию на панели элементов управления проекта отсутствует. Он появляется при создании проекта Data. Если значок объекта MsHFlexGrid не виден, то откройте диалоговое окно Components и добавьте компонент Microsoft Hierarchical FlexGrid Control 6.0 (OLEDB). Поместите экземпляр этого компонента на форму.
3 . Выберите элемент управления MSHFlexGrid и найдите его свойство DataSource в окне Properties.
4 . Установите свойство DataSource в DataEnvironmentI (выберите его из раскрывающегося списка), а свойство DataMember в Command 1 (подключив, таким образом, иерархию элементов управления из окна DataEnvironmentI к элементу Command I).
5 . Щелкните правой кнопкой мыши и выберите из контекстного меню команду Retrieve Structure (Получить структуру). Все поля, перечисленные в окне DataEnvironmentI, добавятся к элементу управления в качестве заголовков. Понятно, что нет надобности отображать все поля определите, какие поля появятся в столбцах и как они будут выглядеть.
ADO
Одним из важнейших компонентов ASP является Database (База данных), представляющий собой ADO-компонент. Использование компонента Database позволяет разработать более сложные и близкие к реальным приложениям сценарии. Хотя для доступа к базам данных на сервере можно использовать и другие компоненты, большинство Web-разработчиков использует ADO-компонент.
ADO является простейшим объектом для доступа к базам данных (см. гл. 18). Его объектная модель много проще, чем у DAO или даже RDO. При этом ADO является мощным инструментом и наиболее часто применяется при создании Web-узлов, использующих активные серверные страницы. Разумеется, вы можете
использовать для этих целей компонент DAO или свои собственные компоненты ActiveX. Но целесообразнее при создании нового Web-узла использовать ADO. Этот компонент работает быстрее упомянутых выше и потребляет меньше ресурсов сервера (что важно для серверов, работающих с большой нагрузкой).
Элемент управления
OLE Container
Рассмотрим, как OLE-технология используется в VB-приложениях. Чтобы включить функциональные возможности OLE в VB-приложения, необходим элемент управления OLE Container, позволяющий вставлять в программу объекты из других приложений. В элемент управления OLE Container можно поместить только один объект. На форму можно поместить несколько элементов OLE Container, каждый из которых может содержать собственный объект.
Элемент управления OLE Container — это доступ к различным объектам операционной системы, которые Visual Basic не в состоянии использовать самостоятельно (например, документы Word, звуковые файлы, растровые изображения или электронные таблицы Excel). Элемент управления OLE Container может содержать любой из объектов, перечисленных в диалоговом окне Insert Object (Вставка объекта), и сделать вашу программу на Visual Basic приложением-контейнером. Преимуществом использования OLE Container является то, что он скрывает сложности, связанные с применение OLE. Встраивать объекты в OLE Container можно как при разработке приложения, так и при выполнении.
FLEXLabel
Начнем наше исследование элементов управления ActiveX с простого примера. Первый элемент, который будет сконструирован в этой главе — это элемент управления FLEXLabel (улучшенный элемент управления Label), показанный на рис. 16.1. Он реализует все возможности элемента управления Label плюс несколько весьма интересных особенностей, таких как выравнивание текста во всех возможных направлениях и трехмерное изображение.
Рис. 16.1. Элемент управления FLEXLabel является улучшенным вариантом элемента управления Label, который может отображать трехмерный текст и выравнивать его по вертикали и горизонтали.
Для построения элемента управления FLEXLabel следует выполнить следующие действия.
1 . Включить все компоненты стандартного элемента управления Label.
2 . Добавить дополнительные члены и написать код для их реализации.
3 . Испытать элемент на форме.
Сейчас, скорее всего, стоит задуматься о программе, которая выравнивает текст и выводит его в виде вдавленного или выпуклого изображения. Начнем со стандартного проекта, который отображает строку на форме и выравнивает ее всеми возможными способами. Элемент управления — это приложение, созданное таким образом, что позволяет ему отображаться на форме, а не на рабочем столе. В большинстве случаев такой элемент может быть реализован с помощью обычной формы. На рис. 16.2 показана форма проекта FLabel, которая делает в точности то же, что должен делать элемент управления FLEXLabel. Этот проект находится в папке с одноименным названием на компакт-диске. Откройте его и посмотрите, как он работает.
Рис. 16.2. Проект FLabel отображает строку в трехмерном представлении, выравнивая ее по вертикали и горизонтали, подобно элементу управления FLEXLabel.
В общем случае, создавать элемент управления как
Standard ЕХЕ-приложение не следует, но, для начала, это, возможно, может помочь. Получив код, управляющий видимым интерфейсом разрабатываемого элемента управления, можно сосредоточиться на процедурах, специфичных для разработки элементов управления ActiveX. Есть еще одна веская причина, по которой выбран этот подход, а именно, возможность сопоставления подходов к конструированию обычных приложений и элементов управления ActiveX.
Data
Наборы RecordSet являются основой программирования баз данных. Рассмотрим пример, который поможет представить, что такое набор RecordSet, и исследовать элемент управления Data Приложение Datal (рис 17 3) — это интерфейс для доступа к таблице в базе данных.
Рис. 17.3. Приложение Datal позволяет просматривать строки таблицы без написания строк кода
VB6 в действии: проект Data1
Для создания данного приложения выполните следующие действия.
1 . Откроите новый проект типа Standard EXE и разработайте форму (см. рис. 17.3). Начните с размещения в нижней части формы элемента Data - это ваши "двери" к базе данных.
2 . Выбрав Data, откройте окно свойств, найдите свойство DatabaseName (Имя базы данных) и нажмите кнопку с многоточием, чтобы открыть диалоговое окно Open.
3 . Выберите базу данных NWIND, которая поставляется вместе с Visual Basic.
4 . В окне свойств найдите свойство RecordSource (Источник записей) и откройте список доступных источников записей. Вы увидите список всех таблиц в базе данных NWIND. Выберите таблицу Customers.
5 . Разместите на форме четыре элемента управления Textbox (см. рис. 17.3).
6 . Выберите первый элемент Textbox и в окне свойств найдите свойство DataSource (Источник данных). Установите его значение в Data1.
7 . Установите значение свойства DataField (Поле) элемента Textbox в CompanyName. Свойство DataField — это раскрывающийся список с названиями всех полей таблицы Customers.
8 . Установите в свойствах DataSource (Источник данных) остальных элементов Textbox значение Data1, а в свойствах DataField (Поле) выберите Country (Страна), Phone (Телефон) и Fax (Факс), соответственно.
Запустите приложение. Элементы управления Textbox отобразят содержимое соответствующих полей таблицы Customers базы данных NWIND. Используя кнопки элемента Data, можно двигаться по записям (строкам) таблицы. При нажатии крайней левой кнопки отображается первая запись таблицы, а при нажатии кнопки, расположенной правее и рядом с ней — предыдущая запись. Соответственно, при нажатии крайней правой кнопки отображается последняя запись таблицы, а при нажатии кнопки, расположенной левее и рядом с ней — следующая запись.
ADO Data
Визуальные инструменты для работы с базами данных не являются единственным средством работы с DAO. Одним из новых элементов управления, добавленных на панель элементов управления, является ADO Data (сходный с элементом Data). Он позволяет подключаться к большим базам данных различных типов, причем с помощью одного приложения и используя один интерфейс
Простейший путь применения ADO в проекте — добавление на форму элемента управления ADO Data и использование его подобно элементу управления Data. Чтобы использовать элемент управления ADO Data со стандартным ЕХЕ-проектом, добавьте его на панель элементов управления.
Откройте меню Project и выберите команду Components для вызова одноименного диалогового окна Components. Отметьте опцию Microsoft ADO Control 6.0 (OLEDB). Для использования усовершенствованных связанных с данными элементов управления (например. List и ComboBox) отметьте также опцию Microsoft Data List Control 6.0 (OLEDB). Щелкните на кнопке ОК для возврата в среду разработки Visual Basic.
Теперь панель элементов управления содержит элементы управления ADO — Data Control, DataList и DataCombo Элементы управления DataList и DataCombo подобны элементам управления DBList и DBCombo, только они предназначены для объектов ADO Data, а не Data.
Приведем пример использования элемента управления ADO Data. Разработаем очень простую форму, которая позволит просматривать заказчиков в базе данных NWIND. Проект ADODC (см. рис. 18.15) состоит из формы с несколькими текстовыми полями, отображающими поля таблицы Customer базы данных NWIND. Текстовые поля связаны с элементом управления ADO Data, который подключает их к текущей записи в таблице Написание кода не требуется.
Рис. 18.15. Проект ADODC: основные свойства элемента ADO Data идентичны свойствам элемента Data
Чтобы создать проект ADODC, выполните следующие действия.
1 . Откройте новый проект и добавьте элемент управления ADO Data на панель инструментов проекта.
2 . Поместите экземпляр элемента управления ADO Data на форму.
Script
В дополнение к построению сценариев Web-страниц,
VBScript можно использовать для написания сценария в приложениях Visual Basic. Функциональные возможности VBScript встраиваются в приложения с помощью элемента управления Script, выпущенного несколькими месяцами раньше Visual Basic 6. В этой книге элемент Script получен из Web-узла http://www.microsoft.com/scripting. По этому адресу можно найти дополнительную документацию по элементу управления Script и примеры его использования. Что касается версии VBScript, использовавшейся при написании книги, то документация по нему скупа, сам элемент управления содержал несколько ошибок, но разработка сценариев с помощью Visual Basic - занятие настолько захватывающее, что на указанные недостатки можно не обращать внимания.
Что может сделать элемент управления Script для приложения? Он может вычислять выражения во время выполнения (имеются в виду выражения, которые передаются приложению в виде строки - прим. ред.). А поскольку элементом управления Script можно управлять из кода приложения, то и само приложение приобретает эту возможность.
Предположим, необходимо разработать калькулятор, который вычисляет математические выражения. Visual Basic вычисляет любое математическое выражение, если оно является частью кода. Например, пользователю во время выполнения необходимо вычислить математическое выражение типа 99,9/log(2,5) или нарисовать график кривой 9*Sin(x)/Cos(x).
Как разрешить эту задачу средствами Visual Basic? Единственный способ — создать собственный элемент управления, способный воспринимать и вычислять выражения в ходе выполнения программы. В гл. 6 рассмотрено приложение Graph, которое рисует график функции, определение которой является частью кода приложения. Этот подход имеет очень ограниченную сферу применения.
В этой главе мы модифицируем приложение Graph так, чтобы оно могло рисовать любую функцию, задаваемую пользователем во время выполнения. Такую возможность предоставляет элемент управления Script. Элемент управления Script вычисляет не только математические, но и логические выражения, выполняя те или иные действия на основе полученного результата, например, организацию цикла. Он позволяет использовать все разнообразие операторов и функций VBScript. Ниже приведен код на VBScript, который определяет, какая из двух функций имеет большее значение для текущего аргумента x.
WebBrowser
Элемент управления WebBrowser попросту является окном Internet Explorer. Любой HTML-документ, который отображается в Internet Explorer, может отображаться на элементе управление WebBrowser. Элемент управления WebBrowser добавляет возможности броузера в приложения. Он позволяет пользователю просматривать узлы в World Wide Web, локальные файлы или ActiveX-документы, например документы Word или Excel из приложения Visual Basic.
Поскольку WebBrowser — элемент управления ActiveX, его можно установить на любой форме Visual Basic. Перед использованием необходимо добавить этот элемент на панель элементов управления. Для этого выполните следующее.
1 . Щелкните правой кнопкой мыши на панели элементов управления и из контекстного меню выберите Components чтобы открыть диалоговое окно Components.
2 . Выберите Microsoft Internet Controls и щелкните на кнопке ОК. На панели инструментов появятся два новых значка WebBrowser и ShelFolderViewOC.
3. Выберите значок WebBrowser и поместите элемент управления на форму.
Размеры элемента управления WebBrowser можно изменять. Поскольку размеры элемента управления нельзя изменять во время работы программы необходимо их отрегулировать по размерам контейнера которым является форма Visual Basic. Когда пользователь меняет размеры формы элемент управления WebBrowser также меняет свои размеры.
Для отображения Web страницы на элементе управления WebBrowser используется метод Navigate. Можно переместиться по списку URL. Элемент управления WebBrowser автоматически создает список посещенных URL. Далее будут рассмотрены свойства, методы и события элементов управления. Начнем с разработки простого приложения которое демонстрирует основные характеристики элементов управления.
VB6 в действии: проект Browser
В этом параграфе разработано приложение, основанное на элементе управления WebBrowser и демонстрирующее как добавить возможности Web броузера в приложения Visual Basic (проект Browser на компакт диске), На рис, 21,1 показано приложение Browser, отображающее Web-узел Sybex. Пользователь может выбрать URL из комбинированного списка или локальный HTML-файл, щелкнув на кнопке Open HTML File.
Класс
String
Последний пример в этом разделе — это очень простой класс, который реализует несколько полезных операций со строками. Класс String предусматривает три метода, реализованных в виде общедоступных функций.
• Integer2Binary(number As Long). Преобразует свой числовой аргумент в двоичное число и возвращает двоичное значение в виде строки.
• Number2String(number As integer). Преобразует свой числовой аргумент в строку и возвращает ее. Если число 395 передать этому методу в качестве аргумента, то возвращаемым значением будет строка "триста девяносто пять".
• LowerCaps(str As String). Преобразует свой аргумент в нижний регистр, причем первые буквы всех слов становятся заглавными, и возвращает новую строку. Если значение "триста девяносто пять" передать в качестве аргумента этому методу, то возвращаемым значением будет строка "Триста Девяносто Пять".
Члены класса String довольно просты, но они могут служить в качестве отправной точки при создании класса с функциями для манипуляции строками и числами, которые часто используются, но не реализованы в Visual Basic в чистом виде.
Три метода класса String реализованы в виде общедоступных функций, и показаны ниже.
Программа 15.17. Методы класса String
Public Function Number2String(Number)
Dim tenth As Integer
Dim leftover As Integer
Dim hundred As Integer
Dim thousand As Integer
If Number < 20 Then ' Чтение чисел меньших 20
NumString = ReadSingle(Number)
Elself Number < 100 Then ' Чтение чисел меньших 100
tenth = Fix(Number / 10)
NumString ReadTenths(tenth * 10)
leftover = Number (tenth * 10)
If leftover > 0 Then
NumString = NumString & " " & ReadSingle(leftover)
End If
Elself Number < 1000 Then ' Чтение чисел между 100 и 999
hundred = Fix(Number / 100)
NumString =
ReadSingle(hundred) & " hundred"
leftover = Number - (hundred * 100)
If leftover > 0 Then
tenth = Fix(leftover / 10)
If tenth > 0 Then NumString = _
NumString & " " & ReadTenths(tenth * 10)
leftover = Number - (hundred * 100) - (tenth * 10)
If leftover > 0 Then
NumString = NumString & " " & _
ReadSingle(leftover)
End If
End If
Else ' Чтение чисел между 1000 и 9999
thousand = Fix(Number / 1000)
NumString = ReadSingle(thousand) & " thousand"
leftover
= Number - (thousand * 1000)
If leftover > 0 Then
hundred
= Fix(leftover / 100)
If hundred > 0 Then
NumString
= NumString & " " &_
ReadSingle(hundred) & " hundred"
End If
leftover
= Number – (thousand * 1000)- _
(hundred *100)
If leftover > 0 Then
tenth Fix(leftover / 10)
If tenth > 0 Then
NumString = NumString & " " & _
ReadTenths(tenth * 10)
End If
leftover = Number - (thousand * 1000) - _
(hundred * 100)
- (tenth * 10)
If leftover > 0 Then
NumString
= NumString & " " & _
ReadSingle(leftover)
End If
End If
End If
End If
Number2String = NumString
End Function
Public Function LowerCaps( str As String) As String
Dim newWord As String, newStr As String
Dim tempStr As String
Dim WDelimiter As Integer
tempStr = Trim(str)
WDelimiter = InStr(tempStr, " ")
While WDelimiter > 0
newWord = Left(tempStr, WDelimiter)
tempStr = Right(tempStr, Len(tempStr) - WDelimiter)
newStr = newStr & UCase(Left(newWord, 1)) & _
Mid(newWord, 2, Len(newWord) - 1)
WDelimiter = InStr(tempStr, " ")
Wend
newWord = tempStr
newStr = newStr & UCase(Left(newWord, 1)) & _
Mid(newWord, 2, Len(newWord) - 1)
LowerCaps = newStr
End Function
Public Function Integer2Binary(ByVal Number As Long) As String
HexNum = Hex(Number)
For i = 1 To Len(HexNum)
BinNum = BinNum & BinaryDigits("&H" & Mid(HexNum, i, 1))
Next
Integer2Binary = BinNum
End Function
Функция Number2Stnng() наиболее сложная. Она похожа на функцию, которая используется проектом READNUM в приложении С (на компакт-диске) для считывания числовых значений. Функция Number2Stnng() может преобразовывать целые значения в диапазоне от 0 до 9999, но можно легко добавить код для работы с большими и нецелыми значениями. Функция Number2Stnng() вызывает функции ReadTenths() и ReadSingle(), которые являются закрытыми членами класса, т.е. их можно вызывать из компонентов класса, но внешние программы не имеют к ним доступа. Если просмотреть члены класса StringClass в броузере объектов, то можно увидеть закрытые члены класса. Однако они будут представлены как Private, напоминая о том, что к ним нет доступа из их приложений.
Тестовая форма класса StringClass показана на рисунке 15.10. Пользователь может ввести числовое значение в текстовое окно наверху формы и щелкнуть кнопки Convert to String или Convert to Binary для преобразования значения в строку или двоичное значение соответственно. Когда текстовое окно под кнопкой Convert to String содержит строку (строка, соответствующая числовому значению или значению, введенному пользователем), то пользователь может щелкнуть кнопку Convert to LCaps для преобразования строки в нижний регистр.
Рис. 15.10. Тестовая форма класса String
Код тестовой формы достаточно прост. Вначале объявляется объектная перeменная, которая будет использоваться для доступа к классу String:
Dim NS As New NumStrings.StringClass
NumStrings это имя проекта, a StringClass — имя модуля класса. Код, соответствующий трем командным кнопкам, показан ниже.
Private Sub Command1.Click()
Text2.Text = NS.Number2String(Text1.Text)
End Sub
Private Sub Command2_Click ()
Dim NStr As String
NStr = NS.Number2String(Text1.Text)
Text3.Text = NS.LowerCaps(NStr)
End Sub
Private Sub Command3_Click()
Text4.Text =
NS.Integer2Binary(Text1.Text)
End Sub
Каждая кнопка вызывает различные методы переменной NS.
Код, соответствующий кнопке Command2, вызывает два метода друг за другом. Вначале он преобразует числовое значение из поля Textl в строку, а затем вызывает метод LowerCaps для преобразования строки в нижний регистр. Два вызова можно объединить в один оператор, как показано ниже:
Text3.TextNStr =
NS.LowerCaps(NS.Number2String(Text1.Text))
В папке этой главы на компакт-диске находится проект NumStr. Откройте его в Visual Basic, исследуйте код или добавьте к нему новые члены. Сейчас самое время для регистрации этого класса в системе, чтобы его можно было использовать в примерах главы 22, где будет создана страница активного сервера, которая использует этот компонент для создания HTML-страниц.
В следующей главе внимание будет сосредоточено на второй категории компонентов ActiveX — элементах управления ActiveX. Элементы управления ActiveX намного проще, чем ActiveX DLL, и несколько интереснее, поскольку они имеют видимый интерфейс пользователя. Программирование интерфейса элементов управления ActiveX такое же, как и для программных компонентов ActiveX. Процесс реализации свойств и методов для элементов управления ActiveX также идентичен описанному в этой главе. В дополнение, необходимо создавать видимый интерфейс элементов управления, что очень похоже на создание форм.
Глава 16 . Конструирование элементов управления ActiveX
• Конструирование элементов управления ActiveX
• Конструирование элемента управления FLEXLabel
• Взаимодействие с объектом-контейнером
• Конструирование страниц свойств
• Построение базового элемента управления
• Улучшение существующих элементов управления
Если и есть хоть одна возможность Visual Basic, которая привлекает всех без исключения разработчиков, так это — ActiveX. Сейчас Visual Basic является простым, легким в изучении и наиболее популярным языком конструирования элементов ActiveX. Элемент управления ActiveX - это то, что раньше называлось элементом управления OLE. Можно предположить, что элементы управления ActiveX являются расширением Visual Basic. Это объекты, представленные на панели элементов управления Visual Basic маленькими значками, которые можно добавлять в любые формы разрабатываемого приложения для расширения его функциональных возможностей.
Первый вопрос, который возникает: почему они называются элементами управления ActiveX? Скорее всего, это вопрос коммерции. OLE-элементы ассоциировались с тяжелым и кропотливым программированием на С. Название, вроде «ActiveX» должно помочь среднему программисту преодолеть робость. И действительно, эта часть VB была так хорошо реализована, что даже для среднего программиста теперь доступна разработка элементов управления ActiveX. Речь идет не только о том, что с помощью Visual Basic 6 можно создавать элементы управления ActiveX, а и о том, как легко это можно сделать. Кроме того, появилась возможность использования ActiveX на Web-страницах — одной из самой быстро растущих арен для разработки программ на Visual Basic.
Кто должен конструировать элементы управления
ActiveX? Если можно было обойтись без ActiveX раньше, почему их необходимо использовать сейчас? Действительно, еще некоторое время многие пользователи VB смогут не заниматься разработкой собственных элементов управления ActiveX. Но, рано или поздно, все же придется этим заняться. Если разрабатывается интересная утилита, которая может использоваться в нескольких приложениях, почему бы ни сделать ее элементом управления ActiveX? Кроме того, зачем отказывать себе в удовольствии попробовать что-нибудь новое? ActiveX помогут программисту на VB расширить диапазон собственных возможностей. Быть способным конструировать элементы для использования их и на вашем компьютере, и в Internet представляется прекрасной перспективой для тех, кто зарабатывает себе на жизнь программированием на Visual Basic.
Ключевые свойства элемента управления
Как уже известно, объект UserControl, вообще говоря, представляет собой форму, на которую можно помещать другие элементы управления, рисовать фигуры, отображать текст и обнаруживать события. Он даже имеет свойства, такие как AutoRedraw и ScaleMode, которые облегчают рисование во время выполнения. Но он не называется формой — он называется UserControl. Кроме того, он имеет несколько уникальных свойств для элементов управления ActiveX, которые будут рассмотрены в этом разделе.
CanGetFocus. Установите это свойство в True, если элемент управления может получать фокус либо с помощью мыши, либо с использованием клавиши табуляции. Специальный элемент управления может получить фокус, если получает фокус объект UserControl либо один из конституэнтных элементов управления. Если элемент управления способен получать фокус, события EnterFocus и Exit Focus инициируются всякий раз, когда элемент управления получает или теряет фокус.
Установите свойство CanGetFocus прототипа элемента управления в True и затем введите следующие строки в обработчики событий EnterFocus и ExitFocus.
Private Sub UserControl EnterPocus()
UserControl.Backcolor = vbRed
End Sub
Private Sub UserControl_ExitFocus()
UserControl.Backcolor = vbGreen
End Sub
Затем переключитесь на тестовую форму и найдите на ней два экземпляра нового элемента управления (или один экземпляр элемента управления ActiveX и пару стандартных элементов управления). Запустите приложение и перемещайте фокус от одного элемент управления к другому. Прототип элемента управления, который имеет фокус, заполняется красным цветом, в то время как стандартные элементы управления заполняются зеленым цветом.
Специальные элементы управления с видимым интерфейсом должны иметь возможность получать и обрабатывать фокус. Если элемент управления содержит несколько конституэнтных элементов управления, то нужно также решить, какой из них получит фокус. По умолчанию получит фокус тот конституэнтный элемент, который был первым помещен на специальный элемент управления. Чтобы установить фокус на другой конституэнтный элемент, используйте метод
SetFocus следующим образом.
1 . Вернитесь к базовому прототипу элемента управления и поместите две кнопки Command на UserControl. He меняйте их имена.
2 . Добавьте следующие строки, чтобы переместить фокус на кнопку Command2 в событии EnterFocus.
Private Sub UserControl _EnterFocus()
UserControl.Backcolor = vbRed
Command2.SetFocus
End Sub
3 . Переключитесь на тестовую форму, удалите все элементы управления на форме и поместите на нее экземпляр нового элемента управления (достаточно большой, чтобы отобразить обе кнопки) и еще одну кнопку Command.
4 . Запустите проект и посмотрите, как фокус перемещается от одного элемента управления к другому. Обратите внимание: когда специальный (заказной) элемент управления получает фокус, он передает его кнопке Command2. Нельзя переместить фокус на кнопку Command1 с помощью клавиши табуляции. Заказной элемент управления представляет собой атомарный объект, и он получает фокус один раз.
ControlContainer.
Если это свойство установлено в True, то заказной элемент управления может быть контейнером для других элементов управления. Обычно, элементы управления, помещенные в контейнер, образуют группу, и они все перемещаются вместе. При перемещении элемента-контейнера по форме все элементы управления, содержащиеся в нем, также перемещаются.
По умолчанию заказной элемент управления не является контейнером. Другими словами, можно нарисовать кнопку Command, которая находится наполовину на заказном элементе управления и наполовину вне его. Для изменения такого поведения нужно установить свойство ControlContainer равным True.
Alignable. Если это свойство установлено в True, то заказной элемент управления во время конструирования имеет свойство Align. Свойство Align определяет, где и как элемент управления выравнивается на форме. Возможные значения свойства Align показаны в табл. 16.3.
Таблица 16.3. Значения свойства Align
Значение
Описание
VbAlignNone
Элемент управления выравнивается вручную (установлено по умолчанию)
VbAlignTop
Элемент управления выравнивается по верхнему краю формы
VbAlignLeft
Элемент управления выравнивается по левому краю формы
VbAlign Right
Элемент управления выравнивается по правому краю формы
VbAlignBottom
Элемент управления выравнивается по нижнему краю формы
<
Совет
Свойство Align не доступно во время конструирования, если свойство Alignable специального элемента управления равно False. Рекомендуется устанавливать свойство Alignable равным True для таких элементов управления, как, например, панель инструментов, которые должны всегда располагаться у края контейнера (даже при изменении его размеров).
InvisibleAtRuntime.
Некоторые элементы управления, наиболее типичным примером которых является элемент Timer, во время выполнения невидимы. Если пользовательский элемент управления не имеет интерфейса пользователя и не должен появляться на форме, установите свойство InvisibleAtRuntime равным True.
ToolboxBitmap.
Используйте это свойство для отображения BMP-файла на панели инструментов вместо стандартной пиктограммы элемента управления ActiveX Значение свойства ToolboxBitmap - это путь к BMP-файлу, но изображение хранится в элементе управления и переносится вместе с ним.
AccessKeys.
Свойство AccessKeys используется для задания комбинаций клавиш, которые будут "горячими" клавишами для быстрого перемещения на элемент управления. Если хотите, чтобы пользователь, нажимая комбинацию "горячих" клавиш (Alt+клавиша), мог сразу перемещать фокус на пользовательский элемент управления, присвойте свойству AccessKeys значение какой-либо клавиши. Например, выполните следующие действия.
1 . Присвойте свойству AccessKeys пользовательского элемента управления значение "А" (без кавычек).
2 . Переключитесь на тестовую форму и запустите ее. Обратите внимание, что можно переместить фокус на пользовательский элемент управления, нажав комбинацию клавиш Alt+A.
3 . Теперь остановите приложение, возвратитесь к заказному элементу управления и откройте событие AccessKeyPress. Это событие вызывается каждый раз, когда нажимается "горячая" клавиша. Добавьте следующие строки, чтобы событие отображало ASCII-код клавиши.
Private Sub UserControl_AccessKeyPress(KeyAscii As Integer)
Debug.Print "Access key pressed" & KeyAscii
End Sub
Чтобы переместить фокус на определенный конституэнтный элемент управления или выполнить некоторое действие, когда фокус перемещается на заказной элемент управления, введите соответствующий код в событие AccessKeyPress. Давайте добавим "горячие" клавиши к двум кнопкам Command из последнего примера. Для этого выполните следующие действия.
1 . Переключитесь на объект UserControl и добавьте две кнопки - Command1 и Command2, как показано на рис. 16.15. (Если был выполнен пример при рассмотрении свойства CanGetFocus двумя страницами ранее, то эти две кнопки уже находятся на форме.)
Рис. 16.15. Когда фокус перемещается на заказной элемент управления, он, на самом деле, перемещается на один из конституэнтных элементов управления
2 . Переключитесь на тестовую форму и поместите на форму экземпляр нового элемента управления, кнопку или другой элемент управления.
3 . Запустите тестовый проект и перемещайте фокус между элементами. Обратите внимание на следующее.
• При перемещении фокуса на заказной элемент управления с помощью мыши, фокус устанавливается на кнопке Command1.
• При перемещении фокуса на заказной элемент управления с помощью клавиши Tab в окне проверки отображается ASCII-код "горячей" клавиши.
4 . Теперь переключитесь обратно на объект UserControl и назначьте "горячие" клавиши двум кнопкам Command. Измените их свойства Caption на Command&l и Command&2, чтобы клавиши 1 и 2 стали их "горячими" клавишами.
5 . Запустите тестовый проект и поэкспериментируйте с перемещением фокуса на элементы управления, размещенные на форме.
Можно использовать комбинацию "горячих" клавиш, чтобы обратиться не только к указному элементу управления, но также и к отдельным его компонентам. Чтобы активизировать определенный конституэнтный элемент каждый раз, когда фокус перемещается на заказной элемент управления, добавьте метод SetFocus в подпрограмму UserControl_AccessKeyPress(). Если заказной элемент управления содержит текстовое поле как свою составную часть, то можно с помощью следующей подпрограммы перевести фокус и на это поле:
Private Sub UserControl
AccessKeyPress(KeyAscii As Integer)
Textl.SetFocus
End Sub
VB6 в действии: элемент управления ActiveX Alarm
Следующий пример демонстрирует элемент управления ActiveX, который содержит все три типа элементов — свойства, методы и события. Это простой сигнал оповещения, который может быть предварительно установлен, чтобы сработать в определенное время, а когда это происходит, то генерируется событие TimeOut. Кроме того, пока таймер включен, элемент управления обновляет изображение на экране, показывая время, истекшее с момента запуска таймера (свойство CountDown должно быть False), или время, оставшееся до момента срабатывания сигнала (свойство CountDown должно быть True). На рис. 16.16 показана тестовая форма для элемента управления Alarm. Первый экземпляр элемента управления Alarm (Process А) подсчитывает время с момента запуска таймера, а второй экземпляр (Process В) подсчитывает время, оставшееся до момента срабатывания таймера.
Совет
При первой загрузке проекта Alarm Visual Basic выдает предупреждение о том, что он не смог загрузить элемент управления Alarm. Это означает, что элемент управления Alarm еще не был установлен в системе, и тестовая форма, которая их использует, не может быть загружена. Продолжайте загрузку проекта, а затем откройте тестовую форму. Два экземпляра элемента управления Alarm будут заменены двумя элементами управления PictureBox. Удалите эти два элемента управления и поместите два экземпляра элемента управления Alarm на тестовую форму (см. рис. 16.16).
Рис. 16.16. Тестовая форма для специального элемента управления Alarm
Интерфейс элемента управления Alarm
Элемент управления Alarm имеет два специальных свойства:
• AJarmTime и
• Count Down.
AlarmTime - это время срабатывания сигнала, выраженное в 12-ти часовом формате. CountDown — это свойство типа True/False, которое определяет, что отображается на элементе управления. Если CountDown равно True, то Alarm показывает оставшееся время. Если установить время срабатывания сигнала на 8:00 вечера и запустить таймер в 7:46 вечера, то элемент управления отобразит 0:14.00, затем 0:13.59 и т.д., пока сигнал не сработает через 14 минут. Если CountDown установить в False, то элемент управления начинает отсчет с 00:00.00 и будет считать, пока не будет достигнуто значение AlarmTime. Если значение свойства AlarmTime меньше текущего времени, элемент управления Alarm предполагает, что сигнал должен сработать в заданное время на следующий день. Например, если текущее время 8:00.00 вечера 1 апреля, a AlarmTime равно 6:30.00 вечера, то сигнал сработает в 6:30.00 вечера 2 апреля (сигнал произойдет через 22 часа 30 минут).
Элемент управления Alarm имеет два метода для запуска и остановки таймера:
• StartTimer запускает таймер и
• StopTimer останавливает таймер.
Наконец, элемент управления Alarm имеет событие TimeOut, которое сообщает приложению, что сигнал уже сработал (это происходит тогда, когда время достигло значения AlarmTime). Приложение может использовать это событие, чтобы выполнить другое действие или просто проинформировать пользователя.
Тестирование элемента управления Alarm
Тестовая форма элемента управления Alarm показана на рис. 16.16. Она содержит два экземпляра элемента управления и можно менять их свойство CountDown во время выполнения. Свойство AlarmTime элементов управления устанавливается в случайное значение в обработчике события Load тестовой формы с помощью следующих операторов:
Private Sub Form_Load()
Randomize Time
AlarmCtl1.AlarmTime = Rnd()
AlarmCtl2.AlarmTime = Rnd()
End Sub
Для тестирования проекта Alarm закомментируйте строки в событии Load формы и установите время сигнала на несколько минут вперед относительно текущего времени, чтобы не пришлось долго ждать момента срабатывания сигнала.
Когда два элемента управления Check 1 и Check2 отмечены, свойство Count Down изменяется с помощью следующего кода:
Private Sub Checkl_Click()
If Checkl.Value Then
AlarmCtll.Count Down = True Else
AlarmCtll.CountDown = False
End If
End Sub
Код для события Click элемента управления Check2 идентичен, только он применяется к элементу управления AlarmCtl2. Наконец, когда у элемента управления Alarm подходит время срабатывания сигнала, выполняется следующий код.
Private Sub AlarmCtll_TimeOut()
MsgBox "The Alarm" & AlarmCtll.Tag & "has Timed out"
End Sub
Нужно присвоить свойству Tag элемента управления подходящее имя, так как программа использует это свойство для различения двух элементов управления. Тестовый проект использует тэги ProcessA и ProcessB.
Кнопка Start Timer под каждым элементом управления запускает таймер соответствующего элемента управления. После этого она изменяет свое название на Stop Timer, чтобы пользователь в любой момент мог остановить отсчет. Код первой кнопки Start Timer показан ниже.
Программа 16.14. Запуск и остановка сигнала
Private Sub StartButtonl_Click()
If StartButtonI.Caption = "Start Timer" Then
AlarmCtl1.StartTimer
StartButtonI.Caption = "Stop Timer"
Else
StartButtonI.Caption = "Start Timer"
AlarmCtl1.StopTimer
End If
End Sub
И, наконец, кнопки Alarm Time с помощью следующего кода отображают время, когда соответствующий сигнал должен сработать.
Private Sub AlarmButtonl_Click()
MsgBox "The alarm will go off at" & AlarmCtll.AlarmTime
End Sub
Загрузите проект Alarm (продолжайте загрузку даже после того, как появится предупреждение) и замените два элемента управления PictureBox, которые появятся вместо элементов управления Alarm, на два экземпляра элементов управления Alarm. Поэкспериментируйте с интерфейсом элемента управления и исследуйте код тестового проекта.
Откройте тестовый проект, закомментируйтс операторы в событии Load формы (которые устанавливают значение свойства AlarmTime равным случайным значениям) и установите свойство AlarmTime на минуту больше, чем системное время (текущее время, отображаемое в нижнем правом углу панели задач). Запустите проект и затем отметьте флажок CountDown. Alarm начнет отсчитывать в обратном направлении разность между текущим временем и временем срабатывания сигнала. Когда эта разница достигнет нуля, окно сообщений сообщит, что время прошло. Если флажок CountDown не отмечен, то вы увидите, сколько времени прошло с момента запуска таймера. Чтобы отобразить время сигнала, нажмите кнопку Alarm Time.
Код элемента управления
Rates
Стандартные свойства элемента управления добавлены с помощью мастера интерфейса ActiveX. Остановимся на процедурах, которые загружают текстовый файл и выводят его в элемент управления ListBox.
Программа 21.10. Метод DownloadRates
Public Function DownloadRates(RatesURL As String)
On Error GoTo DLoadError
AsyncRead RatesURL, vbAsyncTypeFile, "Rates"
Exit Function
DLoadError:
RaiseEvent DLoadError(1024, "Could not download currency _
rates.")
' (He удалось загрузить курсы валют)
End Function
Метод, вызывающий функцию AsyncRead, передает ей URL Web-сервера в качестве параметра. Загруженная информация сохранится в файле с именем Rates.
Интересное действие выполняется, когда происходит событие
AsyncReadComplete объекта UserControl.
Private Sub UserControl_AsyncReadComplete(AsyncProp As AsyncProperty)
Dim FileName As String
On Error GoTo DLoadError
If AsyncProp.PropertyName = "Rates" Then
FileName = AsyncProp.Value
ReadRates FileName
End If
Exit Sub
DLoadError:
RaiseEvent DLoadError(1025, "Error in Downloading rates")
' (Ошибка при загрузке курсов)
End Sub
Код начинается с проверки значения свойства
PropertyName объекта AsyncProp. В элементе управления Rates это свойство принимает только значение Rates. Если элемент управления загружает несколько файлов сразу, то свойство укажет, загрузка какого файла уже завершена, чтобы его можно было обработать. Когда метод AsyncRead загружает файл, свойство Value объекта AsyncProp содержит имя файла и путь на локальном диске. Это имя не имеет никакого отношения к фактическому имени файла на сервере. Оно является уникальным именем файла, созданным системой во временной папке файлов Интернет. Имя файла используется подпрограммой ReadRates() для отображения курсов в элементе управления ListBox.
Программа 21.11. Подпрограмма ReadRates()
Private Sub ReadRates(FileName As String)
Dim FNum As Integer
Dim currencyName As String, currencyValue As Currency
FNum = FreeFile
CurrencyList.Clear
On Error GoTo ReadError
Open FileName For Input As FNum
Input ttFNum, m_LastUpdate
i=1
While Not EOF(FNum)
Input #FNum, currencyName, currencyValue
CurrencyList.AddItem currencyName & Chr(9) & _
Format(currencyValue, "#.000")
CurrencyNames(i) = currencyName
AllRates.Add Str(currencyValue), currencyName
i = i + 1
Wend
RaiseEvent RatesRead
Exit Sub
ReadError:
RaiseEvent DLoadError(1025, "Unkown data format")
' (Неизвестный формат данных)
End Sub
Это прямолинейный VB-код, который открывает текстовый файл и помещает его строки в элемент управления CurrencyList типа ListBox. Он сохраняет курсы валюты в списке AllRates, используя имя валюты в качестве ключа. Эта методика упрощает поиск курса обмена валюты. Подпрограмма ReadRates(), описанная в параграфе Private объекта UserControl, не может вызываться из основного приложения.
Обратите внимание на код обработки события ошибки во всех подпрограммах. При разгрузке информации из Интернет может произойти любое количество ошибок. HTTP-сервер может выключиться, файлы на сервере — реорганизоваться, может произойти ошибка передачи. Все это нужно отследить, продолжив работу программы надлежащим образом.
Возможность, которую можно добавить к проекту — сделать так, чтобы программа следила за загружаемым свойством и не допускала инициализации другой загрузки того же свойства хост-приложением, в то время как первое свойство загружается. Приведенный код выдаст общее сообщение об ошибке
"Error in downloading rates" ("Ошибка в загрузке курсов"). Метод AsyncRead может вызываться для загрузки файла, пока загружается другой файл, но он не может загружать один и тот же файл дважды.
Тестирование элемента управления Rates
Тестирование элемента управления, который загружает значения свойства с HTTP-сервера, требует, чтобы приложение было соединено с сервером, а документ, используемый для тестирования, находился на сервере. Если имеется собственный Web-сервер (Internet Information или Server Personal Web Server), то можно только скопировать Rates, txt файл в виртуальный каталог Web-сервера. Или просто скопировать файл в корневой каталог и соединиться с сервером, используя следующий URL.
http://127.0.0.1/RatesPage.htm
Адрес 127.0.0.1 — адрес компьютера в сети. Фактически, нет необходимости в реальной сети. Если на компьютере установлен Web-сервер, то можно использовать этот URL, чтобы соединиться с файлом. Если Web-сервер находится на другом компьютере той же сети, замените "127.0.0.1" фактическим именем компьютера.
В большинстве случаев собственного Web-сервера нет. Тогда используется сервер провайдера услуг Интернет, если есть разрешение помещать файлы на этот сервер (большинство ISP предоставляет абонентам несколько мегабайт для пользовательских страниц). Чтобы проверить элемент управления Rates с ISP-сервера, поместите Rates.txt файл в каталог на сервере. Для этого выполните следующие действия.
1 . Создайте новую папку на жестком диске и поместите туда файл Rates.txt (если есть другие HTML-файлы, которые необходимо поместить на сервер, также перепишите их в эту папку).
2 . Запустите Web Publishing Wizard (утилита, поставляемая с Windows и FrontPage).
3 . Первая страница Web Publishing Wizard - экран приглашения. Щелкните на кнопке Next, чтобы перейти к выбору файлов или папок.
4 . Введите имя созданной папки в поле File Name Box или Folder Name Box. Щелкните на кнопке Next.
5 . В следующем окне определите имя Web-сервера и щелкните на кнопке Advanced. Появится другое окно, в котором необходимо выбрать протокол, используемый для пересылки файла.
6 . Выберите FTP и щелкните на кнопке Next.
В следующем окне установите URL провайдера услуг Интернет. Необходимо определить имя сервера, чтобы ISP поместил страницы пользователя (имя локального каталога изменять не нужно). Для большинства ISP этот URL выглядит примерно так.
users.ISPname.com/yourname
Часть
yourname — имя пользователя, которое используется для входа в систему. Если адрес пользователя — jdoe@usa1.com, то имя входа в систему — jdoe, a URL каталога на ISP-сервере следующий.
users.usa1.com/jdoe
Многие ISP используют символ тильды перед именем пользователя (users.usa1.com ~ jdoe). Если поискать "user pages" на ISP Web-узле, то будет найдена вся необходимая информация.
Чтобы увидеть последнее окно мастера, щелкните на кнопке Next. Затем щелкните на кнопке Finish, чтобы поместить файлы на сервер.
Чтобы проверить каталог на сервере, запустите Internet Explorer и введите URL файла Rates.txt, находящегося на сервере.
Http://users.usa1.com/jdoe/rates.txt
Содержимое файла Rates.txt отобразится в окне броузера. Это значит, что файл на сервере успешно размещен и элемент управления Rates будет видеть его на сервере (и загружать с него). Необходимо скопировать URL из поля Address броузера и вставить его в код (передать как параметр в метод DownloadRates элемента управления Rates).
Описанный процесс работает со многими ISP, но так можно обратиться не ко всем ISP. Если возникают проблемы при помещении файлов на сервер, необходимо выяснить у Internet провайдера, что необходимо выполнить для размещения персонального Web-узла. Вместо Web-узла поместите файл Rates.txt. Или, если собственный Web-узел уже есть, поместите файл Rates.txt в тот же каталог. Это не повлияет на Web-узел, так как ни одна из его страниц не содержит гиперсвязи к этому файлу.
Если курсы валют были загружены, а через некоторое время вы снова щелкнули на кнопке Download Rate, то возможно появление на элементе управления тех же значений. Можно разместить новые файлы на сервере несколько раз, но курсы не будут меняться. Опытные Web-пользователи уже сообразили, в чем дело AsyncRead метод не запрашивает сервер, чтобы загрузить Rates.txt файл снова он восстанавливает файл из кэша, сохраняет информацию в другом временном файле, а код элемента управления считывает его. В действительности, метод AsyncRead входит в класс IntemetExplorer и использует тот же кэш, что и Internet Explorer.
Там, где Internet Explorer 4 позволяет обновить страницу, метод AsyncRead не поддерживает параметр, заставляющий считывать данные с сервера вместо кэша. Для решения этой проблемы измените установки кэша Internet Explorer Выполните следующие действия.
1 . Запустите Internet Explorer и выберите команду Internet Options в меню View
2 . Щелкните на кнопке Settings (Установки), чтобы открыть диалоговое окно Settings.
3 . Чтобы заставить Internet Explorer перезагружать страницу с сервера (вместо чтения из кэша), установите флажок Eveiy visit to the page.
Теперь Internet Explorer не будет использовать кэш, и при каждом возврате к предыдущей странице, даже с интервалом в несколько секунд, страница будет перезагружаться с сервера. Когда эта книга была подготовлена к печати, Microsoft анонсировала первую бета-версию Internet Explorer 5. Возможно, новый AsyncRead метод позволит выбирать, загружать страницу или просто регенерировать кэш.
Другой интересный подход включить класс IntemetExplorer в элемент управления, вызвать его метод Refresh2 и вынудить загрузку файла. Когда метод AsyncRead вызывается снова, он обращается за данными в кэш, который будет содержать уже обновленные данные.
Загрузка свойств изображения
Метод AsyncRead может загружать свойства изображения. Изображения загружаются в виде двоичных файлов и отображаются с помощью метода LoadPicture. Visual Basic может создать контекст устройства для сохранения загруженного битового изображения. Чтобы загрузить изображение, нужно вызвать функцию AsyncRead.
AsyncRead URL, vbAsyncTypePicture, "Image"
Константа
vbAsyncTypePicture
сообщает Visual Basic, что загружаемый объект -изображение. Файлы не создаются на хост-компьютере, поэтому считать значения пикселей нет возможности. Чтобы работать с изображением, необходимо контролировать его загрузку с помощью функции AsyncReadComplete. Когда загрузка свойства Image (или др. имени, назначенного свойству в методе AsyncRead) завершается, необходимо прочесть значение свойства и сохранить его в объекте Picture с помощью следующего оператора.
Set Bitmap = AsyncProp.Value
Если загружаются несколько изображений, то для идентификации свойств используются различные имена. Можно использовать такие свойства объекта Bitmap, как Height (Высота) и Width (Ширина). Следующий фрагмент кода создает объект Picture с загруженным растровым изображением и вызывает подпрограмму Showlmage(), чтобы отобразить его в элементе управления PictureBox.
Private Sub UserControl_AsyncReadCornplete (AsyncProp As AsyncProperty)
On Error GoTo DloadError
If AsyncProp.PropertyName = "Image" Then
Set Bitmap = AsyncProp.Value
Showlmage Bitmap
' Ширина Bitmap задается в твипсах,
' для преобразования ее в пиксели используйте оператор
' Int(ScaleX(Bitmap.Width, vbHimetric, vbPixels))
End If
Exit Sub
DLoadError:
' сброс события ошибки
End Sub
Подпрограмма ShowImage() использует метод PaintPicture, чтобы скопировать битовое изображение из переменной Bitmap в элемент управления PictureBox.
Picture1.PaintPicture Image, 0, 0, _
Picture1.ScaleWidth, Picture1.ScaleHeight, _
0, 0, Picture1.ScaleWidth,Picture1.ScaleHeight
Подведем итог: загрузка свойств изображения с HTTP-сервера аналогична загрузке текстовых файлов. Необходимо определить тип данных, загружаемых в функцию AsyncRead (константа vbAsyncTypePicture
используется вместо vbAsyncTypeFile). Когда изображение загружено, объект Picture создается автоматически. В нем и сохраняется битовое изображение (так же, как автоматически генерировался текстовый файл). Можно использовать метод PaintPicture, чтобы передать растровое изображение от объекта Picture элементу PictureBox или непосредственно объекту UserControl.
Наконец, можно загрузить данные в формате массива, определяя константу vbAsyncTypeArray в функции AsyncRead. При этом Visual Basic создает байтовый массив, который можно обрабатывать с помощью кода.
Глава 22 . Активные серверные страницы
• Взаимодействие клиент-сервер
• Использование активных серверных страниц
• Передача данных на сервер
• Обработка данных клиента
• Использование объекта Server
• Разработка Web-приложений
Мы уже знаем, как Web-cepep пересылает информацию клиенту в форме HTML-документов и как клиент взаимодействует с сервером с помощью гиперссылок (см. гл. 19), как создавать Web-страницы, позволяющие пользователю вводить данные на клиентском компьютере, и пересылать их вместе с URL на сервер. Кода сервер получает данные (так называемые значения параметров) от клиента, он обрабатывает их и возвращает результат в HTML-формате. В этой главе мы узнаем, как сервер извлекает параметры из сообщения клиента и обрабатывает их. Это самая важная часть механизма взаимодействия клиент-сервер и (во всяком случае, до появления ASP) наиболее сложная для реализации.
Параметры, передаваемые клиентом, разнообразны. Это может быть регистрационная информация, аргументы для поиска, параметры настройки. Компанию может интересовать информация из баз данных, извлекаемая по мере поступления запросов. Для получения самых "свежих" данных с Web-сервера переслать на сервер имя гиперссылки недостаточно. Представьте, что пользователю нужны данные о продажах некоторого товара в штате Северная Каролина или список наиболее активных заказчиков из Техаса. Данные получают из базы данных при поступлении запроса. Это не может быть документ, подготовленный загодя и находящийся на диске сервера в ожидании запроса. После запроса сервер должен извлечь необходимую информацию из базы, преобразовать ее в HTML-формат и передать клиенту.
Многие компании (крупные и не очень) осуществляют сделки, используя Web. Стало быть, коммерческий Web-узел должен предоставлять пользователю информацию о товарах и принимать заказы (товары, их количество, адрес получателя и т.п ) Требования к коммерческим Web-узлам — одна из тем, рассматриваемых в этой главе.
Примечание
В этой главе не рассмотрены вопросы, связанные с передачей конфиденциальной информации, например, номера кредитной карточки. Подобную информацию можно найти в документации к соответствующим продуктам
Microsoft, например, к Commerce Server.
Компонентное программное обеспечение
Сущность технологии OLE состоит в использовании компонентов программного обеспечения.
Компонент — это объект (элемент управления или приложение) который кто-то уже разработал, и его можно использовать в вашей программе. Если компонент поддерживает OLE, то можно "позаимствовать" его функциональные возможности для собственных целей. Например, Microsoft Word содержит средства проверки правописания. Зачем же покупать другую программу проверки, или писать собственную, если можно позаимствовать эти функциональные возможности из Word?
Разработчик компонентного программного обеспечения рассматривает программу как совокупность работающих вместе компонентов, что позволяет обеспечить общий стандарт интерфейса для OLE-приложений. Например, функциональные возможности электронной таблицы могут быть доступными в текстовом процессоре, и наоборот. Прикладная программа, созданная средствами Visual Basic, может обладать функциональными возможностями и текстового процессора, и электронной таблицы.
Компоненты-члены элемента управления
Rates
Rates имеет много стандартных компонентов-членов.
BackColor
ForeColor
MouseMove
Click
Key Down
MouseUp
DblClick
KeyPress
Refresh
Enabled
KeyUp
Font
Mouse Down
Эти компоненты добавлены в элемент управления с помощью мастера. Все они соответствуют эквивалентным элементам управления ListBox.
В дополнение к стандартным, элемент управления
Rates реализует следующие пользовательские компоненты.
Метод DownloadRates (Загрузить курсы обмена). Метод DownloadRates соединяется с сервером и загружает документ, содержащий курсы валюты. Ниже приведен синтаксис этого метода.
DownloadRates (RatesURL As String)
RatesURL - это URL текстового файла, имеющий следующую структуру.
,
,
,
Первая строка содержит дату последней модификации файла, чтобы клиент знал, когда изменялись данные по курсам. Следующие строки содержат обозначения валюты и курса, отделяемые запятыми. Так выглядит файл, содержимое которого приведено в виде списка (см. рис. 21.12).
"5:31 РМ 5/18/96"
US$, 1.00
С$, 1.483
ВР, 0.867
FFr, 2.143
ECU, 1.103
DM, 1.780
ESP, 13.203
YEN, 143.300
LIR, 2340.500
GDr, 328.405
BFR, 25.403
Так как код использует запятую, чтобы отделить два элемента каждой строки, нельзя использовать тот же самый символ как разделитель тысяч. Значение 2340.500 не может быть представлено в Rates.txt файле как 2,340.500. Его не пропустит код, который анализирует файл и заполняет элемент управления ListBox.
Событие RatesRead (Чтение курсов). Инициируется, как только данные разгружены.
Свойство LastUpdate (Последняя модификация).
Возвращает дату и время последней модификации курсов. Значение свойства считывается с сервера вместе с курсами валюты.
Свойства Count (Счетчик). Возвращает число различных типов валют, загруженных с сервера.
GetCurrencyValue (Получить курс). Возвращает обменный курс определенной валюты. Чтобы узнать обменный курс, например, для немецкой марки, вызовите метод GetCurrencyValue.
DMRate = GetCurrencyValue("DM") ,
Аргумент метода должен иметь тип String
Метод GetCurrencyName (Получить имя валюты). Возвращает имя валюты в поле index элемента управления ListBox.
Событие DLoadError (ErrNumber As Long, ErrDescription As String). Вызывается из события AsyncReadComplete, чтобы сообщить приложению, что произошла ошибка. Главное приложение может узнать номер и описание ошибки, чтобы предпринять соответствующие действия.
Конструирование базовых прототипов элемента управления
В первом разделе этой главы изучалось конструирование элементов управления средствами мастера ActiveX пользовательского интерфейса. Даже при том, что мастер позаботился о многих деталях реализации и создал полностью работоспособный элемент управления, необходимо было знать несколько вещей о режимах работы элемента управления для придания ему нужной функциональности. Мастер создает скелет элемента управления, но необходимо его наполнить.
Ранее не упоминалось о некоторых важных моментах. Рассмотрим их в этом параграфе, включая инициализацию и уничтожение элемента управления, использование уникальных свойств, методов и событий. В целях упрощения, не будем создавать другой элемент управления, а используем базовый прототип. На этот раз не будем использовать мастер, а создадим все свойства и методы вручную, чтобы получить некоторый опыт редактирования элементов управления.
Конструирование элемента управления ActiveX
Откройте новый проект ActiveX, выполнив следующие действия:
1 . Выберите команду New Project меню File.
2 . В окне New Project выберите пиктограмму ActiveX Control. Visual Basic создаст новый проект под названием Project!, который содержит элемент управления с именем UserControll.
Начальные установки для элемента управления ActiveX показаны на рис. 16.3 (имена в окне проекта отличаются, ниже будет показано, как их изменить).
Рис 16.3. Проект элемента управления ActiveX содержит вместо формы элемент управления.
Давайте переименуем проект и элемент управления. Эти два имени будут использованы для регистрации данного элемента в системе, поэтому они должны быть содержательными. Выполните следующее.
1 . Выберите Project1 в окне Project и, когда появятся его свойства, измените свойство Name на FLEXLabel.
2 . Выберите UserControll в окне Project и, когда появятся его свойства, измените свойство Name на Label3D.
Совет
Каждый раз, когда элемент управления ActiveX помещается на форму, его имя представляет собой соединение названия элемента управления и соответствующей цифры. Первый экземпляр элемента управления, помещенного на форму, будет назван Label3D1, следующий будет назван Label3D2 и так далее.
Только что вы познакомились с новым объектом —
UserControl. Как вскоре станет ясно, UserControl - это некий аналог формы, на которой конструируется элемент управления. Объекты UserControl обладают дополнительными уникальными свойствами, которых нет у обыкновенной формы, но на этом этапе можно думать о них как об обычных формах. В то время как приложение FLabel выравнивает и отображает надпись на форме, элемент Label3D использует тот же код для отображения надписи на объекте UserControl.
Таким образом, подготовлена сцена для нового элемента управления ActiveX. Прежде чем вставлять собственный код, запустим мастер, чтобы он сгенерировал как можно больше кода для элемента управления. Среди прочего, он разработает и структуру элемента управления.
Мастер интерфейса элемента управления ActiveX
Выберите меню Add-Ins и в открывшемся диалоговом окне выберите строку ActiveX Control Interface Wisard, чтобы открыть мастер. Этот мастер поможет создать новый элемент управления ActiveX. Он создаст интерфейс элемента управления (свойства, методы и события) и приготовит его основной код. Останется только подготовить код, который рисует надпись и реализует еще несколько возможностей, которые не могут быть автоматизированы. Мастер сделает большую часть работы. Он имеет шесть окон, назначение которых будет вскоре объяснено.
Если мастер в меню Add-Ins отсутствует, выберите меню Add-In Manager и в диалоговом окне сделайте двойной щелчок на строке VB6 ActiveX Control Interface Wisard. Напротив, в колонке Load Behavior, появится, как показано на рис. 16.4, слово Loaded. Теперь нажмите ОК., и данный мастер появится в меню Add-Ins.
Мастер интерфейса элемента управления ActiveX будет сопровождать разработчика при проектировании скелета элемента. Мастер, естественно, не добавит код, выравнивающий или, даже, отображающий надпись, но создаст элемент управления с большинством стандартных частей типичного элемента управления ActiveX.
Рис. 16.4. Диалоговое окно Add In Manager
Введение
Первый экран мастера — приглашение, появление которого можно потом отключить, отметив флажок "Skip this screen in future". Для начала процесса конструирования интерфейса создаваемого элемента управления нажмите кнопку Next.
Выбор элементов интерфейса
Следующее окно мастера предлагает выбрать стандартные части элемента управления ActiveX Слева — список стандартных свойств, методов и событий, которые можно включить в конструируемый элемент. Справа — список уже выбранных свойств, методов и событий интерфейса. Visual Basic предполагает, что конструируемый элемет управления должен поддерживать выбранные свойства.
Для добавления нового свойства, метода или события элемента управления выберите его из списка и щелкните кнопку с одинарной стрелкой вправо. Добавьте, таким образом, следующие компоненты:
Appearance
Font
MouseMove
OLEGive Feedback
Backcolor
ForeColor
Mouse Pointer
OLESetData
Backstyle
HOC
Mouse Up
OLEStartDrag
BoiderStyle
HWnd
OLEDrag
Picture
Click
Key Down
OLEDragDrop
Resize
DblClick
KeyPress
OLEDragOver
Enabled
Key Up
OLEDropMode
Как видно, включены все стандартные свойства, события и методы, которые должны быть у типичного элемента управления. Свойства для установления связи с данными пропущены, поскольку элемент управления FLEXLabel не будет связан с полями какой-либо базы данных. Нажмите кнопку Next.
Создание специальных частей интерфейса
В этом окне, можно добавить свойства, события и методы, которые являются уникальными для данного элемента управления. Для этого выполните следующие действия.
1 . Нажмите кнопку New, чтобы отобразить диалоговое окно Add Custom Member.
2 . В поле Name введите Caption (это название свойства) и включите флажок Property.
3 . Нажмите ОК. Имя первого заказного свойства теперь отображено в окне My Custom Members.
4 . Повторите шаги 1—3, чтобы добавить свойства Effect и TextAlignmem.
Если была допущена орфографическая ошибка в имени свойства или нужно удалить одно и ввести другое свойство, используйте кнопки Edit и Delete. В конце нажмите кнопку Next.
Установка соответствия компонентов интерфейса
Это окно используется для установки соответствия между некоторыми свойствами специального элемента управления и свойствами так называемых конституэнтных (constituent) элементов управления. Конституэнтными являются стандартные элементы управления VB, используемые при конструировании специального элемента управления ActiveX. Предположим, что элемент управления содержит элемент Label, и желательно, чтобы фон элемента управления Label стал фоном конструируемого элемента управления (или цвет символа, например).
В этом окне свойства конструируемого элемента управления отображаются на свойства любого из элементов управления, которые он использует. Поэтому обращение к таким отображенным свойствам, на самом деле, является обращением к свойствам конституэнтного элемента управления.
Следует установить соответствие между всеми компонентами (свойствами, методами и событиями), которые вы не желаете обрабатывать собственным кодом, и соответствующими компонентами объекта
UserControl. Событие Click — типичный пример. Нет необходимости в определении какой-либо реакции на щелчок внутри самого элемента управления, нужно передать событие главному приложению, чтобы обработать его соответствующим образом. Для отображения свойства выполните следующие действия.
1 . Из списка Public Name выберите свойство или событие.
2 . Щелкните на раскрывающемся списке и выберите UserControl Мастер немедленно выберет компонент объекта UserControl с тем же именем.
3 . Отобразите все элементы нового элемента управления (исключая уникальные для данного элемента управления части) на эквивалентные компоненты объекта UserControl.
4 . Нажмите кнопку Next.
Установка атрибутов
В этом окне можно установить атрибуты новых компонентов (или, если это необходимо, изменить атрибуты, заданные по умолчанию, хотя это и не рекомендуется). Компоненты, которые уже были отображены, не будут показаны в этом списке. Мастер объявляет все новые свойства как Variant, поскольку невозможно установить их типы только по именам. Однако свойства TextAlignment и Effects должны быть целыми числами, a Caption — строкой.
Для того чтобы установить атрибуты, выполните следующие действия.
1 . В поле Public Name выберите TextAlignment.
2 . Выберите из раскрывающегося списка Data Type тип Integer.
Обратите внимание на возможность устанавливать значение свойств по умолчанию.
3 . В поле Default Value введите значение 4. Это — значение, которое отображается по умолчанию в окне свойств для элемента управления FLEXLabel. Как будет показано ниже, можно назначить пользовательские типы данных для свойств.
4 . Повторите шаги 1—3 для свойства Effects. Установите тип данных Integer и значение по умолчанию 2 (тисненый).
Совет
Не забудьте снабдить коротким описанием каждое свойство в поле Description. Эти описания отображаются внизу окна свойств, когда пользователь выбирает свойство. Стандартные элементы уже имеют описание, а для пользовательских свойств необходимо его составить.
В поле Arguments можно указать параметры событий. Этот проект не имеет никаких собственных событий, но пример таких событий будет приведен позже в этой главе
Обратите внимание, что свойства могут различаться в режиме выполнения и в режиме конструирования. Если предполагается, что разработчику не нужно выполнять выравнивание или применять какие-либо эффекты во время выполнения, то необходимо для соответствующих свойств установить атрибут Read-Only at runtime (Только для чтения во время выполнения).
Завершение
Чтобы сгенерировать элемент управления, в этом окне предлагается нажать кнопку Finish. Оставьте отмеченным флажок View Summary Report (Показать итоговый отчет).
Ваш жесткий диск будет работать в течение нескольких секунд, а затем отобрази гся итоговый отчет (который, в основном, говорит о том, что делать дальше). Закройте окно редактора или сохраните отчет.
Элемент управления FLEXLabel создан. Он делает не так много (нами ведь еще даже не введен код, отображающий надпись), но можно испытать его поведение как элемента управления. На данный момент элемент управления имеет собственную страницу свойств и может быть помещен на форму.
На экране нет ничего, за исключением формы. Эта — объект UserControl, который является формой во всех отношениях. Появилась также новая пиктограмма на панели элементов управления. Эта пиктограмма представляет новый элемент управления. Значок с изображением матрицы и ручки по умолчанию дается всем элементам управления ActiveX. Для того чтобы поменять значок, нарисуйте новую картинку (Bitmap) и свяжите ее со свойством ToolboxBitmap объекта UserContiol. Давайте сначала удостоверимся, что элемент управления работает, а затем настроим его. Пиктограмма элемента ActiveX заблокирована, поскольку элемент управления все еще конструируется. Он не может быть активизирован во время конструирования.
Конструирование элемента управления
FLEXLabel
Перед тем как создать элемент управления, хотелось бы обсудить выгоды от создания элементов ActiveX. Некоторые могут удивиться, зачем возиться с элементами ActiveX, если уже есть код для отображения трехмерной надписи на форме любым способом? Если захотеть, то можно модифицировать код для работы с элементом PictureBox, который можно расположить где угодно на форме.
Действительно, элементы управления, подобные FLEXLabel, не что иное, как обычное приложение, но завернутые в другую упаковку. Есть определенные преимущества компоновки приложения в виде элементов управления ActiveX. Вот некоторые из них.
• Код элемента управления не будет пересекаться с кодом основного приложения. Приложение даже не будет знать о коде элемента управления.
• Можно менять текст, стили выравнивания и специальные эффекты из окна свойств, не меняя исходного кода приложения. Кроме того, можно визуально менять свойства и наблюдать изменения без запуска всего проекта.
• Элемент управления может накрывать только часть формы. Кроме того, можно поместить на одной форме несколько элементов управления с различными надписями.
• Наконец, можно свободно распространять элемент управления, и другие разработчики могут использовать его, не затрагивая его код.
Первый шаг в конструировании элемента управления — это разработка его интерфейса, который определяет, как элемент будет выглядеть при помещении его на форму и как разработчики могут получить доступ к возможностям элемента управления через его компоненты. Уверен, что вы слышали этот совет не один раз, но многие пользователи все равно начинают кодирование элемента, не уделяя достаточно времени конструированию его интерфейса.
Элемент ActiveX должен предоставлять определенные свойства, которые автоматически отображаются в окне свойств. Разработчик должен иметь возможность настраивать каждый параметр, влияющий на отображение, посредством манипуляции его свойствами. В дополнение, разработчики ожидают увидеть стандартные свойства, присущие всем стандартным элементам (такие как цвет фона, шрифт текста и т.д.). Следует тщательно конструировать методы так, чтобы они обеспечивали все функциональные возможности элемента управления и были доступны из кода приложения. Кроме того, методы не должны перекрываться. Наконец, нужно предусмотреть события, необходимые для реакции на внешние воздействия. Можно кодировать обычные приложения без предварительного конструирования, но элементы ActiveX и приложения для работы с базами данных требуют тщательной подготовки. Не начинайте кодировать элемент управления до тех пор, пока не сформулируете абсолютно четко, что будет делать элемент и как он будет использоваться разработчиками во время конструирования их приложений.
Alarm
Первым шагом является конструирование интерфейса элемента управления. В отличие от элемента управления Timer из Visual Basic, элемент управления Alarm имеет видимый интерфейс. Его работа основана на двух конституэнтных элементах управления:
• Timer, который обновляет изображение каждую секунду, и
• Label, который отображает время.
Конструирование интерфейса пользователя
Для конструирования интерфейса элемента управления, выполните такие шаги.
1 . Поместите элемент управления Label на форму UserControl и установите в свойстве Font желаемые шрифт и размер.
2 . Выровняйте Label по верхнему левому углу элемента управления, и измените размеры элемента управления так, чтобы он полностью вмещал элемент Label. (Запомните значения свойств Width и Height элемента управления. Они понадобятся позже при написании кода для предотвращения изменения размеров этого элемента управления.)
3 . Поместите элемент управления Timer на объект UserControl He имеет значения, где поместить элемент управления Timer. Он будет невидим во время выполнения Можно поместить Timer вне видимой области пользовательского элемента управления или даже поверх элемента Label.
4 . Чтобы завершить разработку элемента управления и препятствовать изменению его размеров, добавьте следующий код в обработчик события Resize элемента управления:
Private Sub UserControl Resize()
UserControl.Size 1800, 500
End Sub
Метод Size заставляет элемент управления сохранять фиксированный размер Значения 1800 (ширина) и 500 (высота) размеров элемента управления нужно изменить согласно реальным размерам элемента управления Label.
Теперь можно проверить поведение нового элемента управления. Попробуйте изменить его размеры Даже при том, что можно перемещать органы управления этого элемента, его размеры изменить нельзя.
Реализация компонентов элемента управления
Теперь все готово для реализации свойств элемента управления, его методов и событий. Давайте начнем со свойств. Нам уже известно, как добавить свойства к элементу управления с помощью мастера интерфейса элемента управления ActiveX и как это сделать вручную. Теперь давайте рассмотрим еще один инструмент. Мы еще сделаем это с помощью мастера, но сейчас просто добавим одно свойство или метод.
Начнем с объявления переменных. Вставьте следующие строки в окно Code объекта UserControl:
Private startTime As Date
Private Running As Boolean
Private m_CountDown As Boolean
Private m_AlarmTime As Date
Уже можно догадаться, что m_CountDown
и m_Alarm Time — две закрытые переменные, которые содержат значения свойств CountDown и AlarmTime. Пока запущен Alarm, переменная Running равна True, и она объявлена вне всех процедур, чтобы все они могли обращаться к ее значению. Переменная startTime устанавливается равной времени начала отсчета и используется, когда элемент управления не считает в обратном направлении (дальше будет видно, как это используется).
Чтобы сделать заготовки для свойств элемента управления с помощью команды Add Procedure, выполните следующие действия.
1 . Переключитесь в окно UserControl и выполните двойной щелчок на форме, чтобы открыть окно Code.
2 . Выберите команду Add Procedure меню Tools, чтобы открыть диалоговое окно Add Procedure.
3 . Введите имя свойства CountDown и выберите тип Property. В окно кода будут вставлены следующие строки.
Public Property Get CountDown() As Variant
End Property
Public Property Let CountDown(ByVal vNewValue As Variant)
End Property
4. Измените тип свойства, чтобы он соответствовал объявлению, а затем введите строки кода для вставленных ранее процедур.
Public Property Get CountDown() As Boolean
CountDown = m_CountDown
End Property
Public Property Let CountDown(ByVal vNewValue As Boolean)
m_CountDown = vNewValue
End Property
Примечание
Приведенный код совершенно тривиален. Все процедуры Property ставят в соответствие закрытой переменной название свойства и имеют одинаковую структуру. Нужно не забывать только изменять их типы с Variant на требуемый.
5 . Сделайте то же самое для переменной AlarmTime. Процедуры для этого свойства имеют следующий вид.
Public Property Get AlarmTime() As Date
AlarmTime = m_AlarmTime
End Property
Public Property Let AlarmTime(ByVal vNewValue As Date)
If IsDate(vNewValue) Then m_AlarmTime = vNewValue
End Property
Последняя процедура проверяет правильность значения свойства, чтобы удостовериться, что введено допустимое время. Если введена дата, то программа предполагает, что время равно 00:00:00 (полночь).
6. Теперь можно добавить два метода. В окне Code выберите команду Add Procedure меню Tools. В открывшемся диалоговом окне Add Procedure введите название метода StartTimer, но на этот раз установите переключатель в Sub. В код будут вставлены следующие строки.
Public Sub StartTimer()
End Sub
7. В подпрограмме StartTimer() введите код для запуска таймера.
Public Sub StartTimer()
If Not Running Then
Timer1.Enabled = True
Running = True
startTime = Time
If Time = m_AlarmTime > 0 Then NextDay = True
Label1.Caption = "00:00:00"
End If
End Sub
Эта подпрограмма ничего не делает, если таймер уже запущен. Если таймер не запущен, то подпрограмма инициализирует элемент управления Timer и устанавливает значение переменной startTimer равным текущему времени, а изображение в "00:00:00". Переменная Running устанавливается в True, чтобы предотвратить повторное выполнение этой подпрограмм, когда таймер уже запущен. Переменная NextDay устанавливается в True, если время срабатывания сигнала меньше текущего времени. Это означает, что элемент управления должен сработать в заданное время на следующий день.
8 . Снова выберите команду Add Procedure меню Tools, чтобы создать еще одну общедоступную подпрограмму — метод StopTimer(). Ниже приведен код для этой подпрограммы.
Public Sub StopTimer()
If Running Then
Timer1.Enabled = False
Running = False
End If
End Sub
Так же как и в методе StartTimer, таймер останавливается только в том случае, если он был запушен. В этом случае код отключает элемент управления Timer и устанавливает переменную Running в False.
9 . Теперь добавьте событие элемента управления. Выберите команду Add Procedure меню Tools, чтобы открыть диалоговое окно Add Procedure.
10 . Введите имя TimeOut и выберите переключатель Event. После этого к коду добавится еще одна строка.
Event TimeOut()
Как заставить произойти это событие? С помощью оператора RaiseEvent из любого места кода. Всякий раз, когда таймер должен сработать, можно вызывать событие TimeOut с помощью следующего ниже оператора.
RaiseEvent TimeOut
Событие TimeOut вызывается из кода элемента управления
Timer (мы познакомимся с ним позже).
Только что был завершен костяк элемента управления
Alarm, нечто похожее было сделано ранее с помощью мастера интерфейса элемента управления ActiveX. На этот раз все элементы интерфейса элемента управления были добавлены вручную с помощью меню Tools. Проще позволить мастеру сформировать элемент управления автоматически, но знание того, как это можно сделать вручную, поможет добавить несколько свойств к существующему элементу управления без выполнения всех шагов мастера интерфейса элемента управления ActiveX.
Совет
Если запустить мастер интерфейса элемента управления
ActiveX для изменения существующего элемента управления, можно обнаружить, что мастер ставит символ комментария перед кодом пользователя. Поэтому всегда следует проверять свой код после обработки его мастером.
Команда Add Procedure не добавляет соответствующие строки в события ReadProperties и WriteProperties — их следует добавить вручную.
Программа 16.15. Сохранение и чтение свойств элемента правления Alarm
Private Sub UserControl ReadProperties(PropBag As PropertyBag)
CountDown = PropBag.ReadProperty ("CountDown", CountDown)
m_AlarmTime = PropBag.ReadProperty ("AlarmTime", AlarmTime)
End Sub
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
PropBag.WriteProperty "CountDown", m_CountDown, False
PropBag.WriteProperty "AlarmTime", m_AlarmTime, 0
End Sub __ ___ ___ ___ __
В заключение, нужно добавить следующий ниже код, также вручную, для инициализации значения свойства. Private Sub UserControl InitProperties()
m_CountDown = True
Running = False
End Sub
Конструирование элементов управления
ActiveX
В этом разделе будут рассмотрены сходства и различия между элементами управления ActiveX, компонентами ActiveX и стандартными проектами. Перед тем как приступить к конструированию элементов управления ActiveX, будет показано, как они связаны с другими типами проектов. Эта информация поможет составить цельную картину и собрать вместе все части последующих разделов.
Стандартное приложение содержит главную форму и несколько вспомогательных. Вспомогательные формы обычно поддерживают главную, получая данные, вводимые пользователем, которые обрабатываются кодом главной формы. Можно считать элемент управления ActiveX главной формой, а окно его свойств и страницы свойств — вспомогательными формами.
Приложение взаимодействует с пользователем через свой интерфейс. Проектировщик приложения решает, как приложение будет вести диалог с пользователем, и пользователю приходится следовать этим правилам. Подобное же происходит и с элементами управления ActiveX. Они предоставляют строго определенный интерфейс, который содержит свойства и методы. Это единственный способ управления элементом ActiveX. Так же, как и пользователь приложения не может модифицировать его исходный код, так и программист может получить доступ к элементу только через его интерфейс.
В предыдущей главе вы познакомились с вопросами реализации интерфейсов, состоящих из методов и свойств, и с инициированием событий в компонентах ActiveX. В этой главе мы узнаем, как строить интерфейс элемента управления ActiveX. В то время как компонент ActiveX предоставляет малое число свойств и методов, элемент управления должен обладать большим набором свойств. Когда разработчик помещает элемент управления на свою форму, он ожидает увидеть свойства, обычные для всех элементов управления, видимых во время выполнения (свойства для управления размером, цветом, положением, шрифтом и т.д.). Разработчик также ожидает возможности программировать все стандартные и уникальные для этого элемента управления события.
Конструирование элементов управления ActiveX похоже на конструирование формы. При этом элементы располагаются на объекте, называемом UserControl, который является формой элемента управления. Он предусматривает примерно те же методы, что и стандартная форма, например, методы Print, Line и др.
Формы приложения являются окнами, которые находятся на рабочем столе при запущенном приложении. При конструировании приложения можно переупорядочивать элементы управления на форме и программировать их реакцию на действия пользователя. Элементы управления ActiveX — также окна, но они не могут существовать сами по себе и не могут быть расположены на рабочем столе, а только на формах.
Главное отличие между обычными приложениями и элементами управления заключается в том, что элементы управления могут работать в двух разных режимах. Когда разработчик помещает элемент управления на форму, он запускается. При изменении свойства элемента управления с помощью окна свойств с элементом что-то происходит. Это означает, что код элемента управления работает даже тогда, когда проект, в котором он используется, находится на стадии конструирования. Когда разработчик запускает приложение, элемент также работает. Но при этом элемент управления должен обладать способностью определять, в каком из режимов находится проект, и соответственно себя вести.
Рассмотрим пример элемента управления TextBox в режиме конструирования. У него есть свойство Text со значением Textl. Если установить его свойство MultiLine в значение True, а свойство Scrollbar — в Vertical, то к элементу автоматически будет присоединена вертикальная полоса прокрутки. Значит, эти свойства имеют некоторые значения в режиме конструирования. Запустите приложение и введите некоторый текст в элемент TextBox. Если проект снова вернуть в режим конструирования, свойство Text опять примет значение Textl. Элемент управления сохраняет информацию о свойствах при переключении из режима конструирования в режим выполнения, а при переключении обратно - восстанавливает информацию.
Этот двойной режим — нечто новое для программистов на
Visual Basic, и следует к этому привыкнуть. При конструировании собственного элемента управления ActiveX нужно также переключаться между функциями разработчика элементов управления ActiveX (программист, который конструирует элемент) и разработчика приложения (программист, который использует этот элемент).
Одним словом, элемент управления ActiveX — это приложение с видимым пользовательским интерфейсом. Видимый пользовательский интерфейс - это то, что видит разработчик, когда помещает экземпляр элемента управления на форму, которая, в свою очередь, также есть то, что видит разработчик при запуске проекта. Разработчик может манипулировать элементом управления через свойства, предоставляемые элементом (во время конструирования) и методами (во время выполнения). Свойства и методы вместе образуют невидимый интерфейс. Таким образом, разработчик элементов управления ActiveX конструирует видимый интерфейс на объекте UserControl, который почти идентичен объекту формы. Этот процесс похож на создание обычного приложения. Конструирование же невидимого интерфейса подобно конструированию модуля класса.
Конструирование страниц свойств
Элементы ActiveX могут иметь страницы свойств. Страницы свойств подобны окну свойств, которое позволяет разработчику (программисту, который использует элемент управления в проекте VB) устанавливать новые значения свойств. Но в отличие от окна свойств, страницы свойств предлагают лучший и более гибкий интерфейс с пользователем для настройки элемента управления, включая мгновенную визуальную обратную связь.
Рис. 16.9. Страницы свойств для настройки TabStnp
Страницы свойств представляют собой набор инструментов конструирования Рис. 16.9 показывает страницу свойств для элемента управления TabStrip. Посредством этого интерфейса можно настраивать элемент управления TabStrip способами, которые просто невозможно реализовать, используя только окно свойств. Свойства, которые можно изменять посредством окна свойств, применяются ко всему элементу в целом, а возможности изменить заголовки и вид отдельных закладок, их номера и т.д. отсутствуют. Страницы свойств этого элемента управления содержат отдельные страницы (General, Tabs, Font, Picture), на которых сгруппированы связанные атрибуты.
Конструирование страниц свойств значительно упрощается использованием мастера страниц свойств. Давайте добавим несколько страниц свойств к элементу управления FLEXLabel. Элемент управления имеет три специальных свойства -два перечислимых и одно строковое, которые будут размещены на одной странице. Вдобавок, элемент управления имеет стандартные свойства, которые будут помещены на других страницах свойств. Свойство Font, например, должно быть расположено на отдельной странице, похожей на обычный диалог выбора шрифта. Аналогично, на отдельной странице должно появиться свойство Color, напоминающее обычный диалог выбора цвета.
Контекстное меню элемента управления
OLE
Существует еще один способ внедрения объектов в элемент управления OLE Container с помощью контекстного меню управления. Если выполнить правый щелчок на элементе управления OLE Container в процессе работы, то на экране появится контекстное меню (рис. 14.8). Его можно использовать для вставки нового объекта или редактирования уже встроенного документа (если элемент управления уже содержит объект). Чтобы встроить (или связать) другой объект в OLE Container, необходимо сначала удалить существующий объект.
Наличие тех или иных команд в контекстном меню зависит от состояния выбранного объекта. Контекстное меню, показанное на рис. 14.8, содержит команды Edit (Редактировать) и Open (Открыть), так как выбранный объект является документом Word. Если встроенный объект - звуковой файл, то контекстное меню будет содержать команды Edit (Редактировать) и Play (Воспроизведение). Если же элемент управления не содержит никаких объектов (поскольку разработчик щелкнул на кнопке Cancel в диалоговом окне Insert Object), то команды Edit (Редактировать) и Open (Открыть), наличие которых определяется содержимым окна элемента управления, в сокращенном меню будут отсутствовать.
Рис. 14.8. Чтобы вывести на экран контекстное меню элемента OLE Container во время разработки проекта, выполните на нем правый щелчок
Контекстное меню элемента OLE Container может содержать некоторые из перечисленных ниже команд (или все).
• Cut (Вырезать). Копировать объект, находящийся в контейнере, в буфер обмена и очистить контейнер.
• Copy (Копировать). Копировать объект, находящийся в контейнере, вбуфер обмена.
• Paste (Вставить). Вставить объект из буфера обмена в элемент управления.
• Delete (Удалить). Удалить OLE-объект из элемента управления.
• Insert Object (Вставка объекта). Удалить существующий объект и открыть диалоговое окно Insert Object (Вставка объекта), чтобы пользователь мог вставить новый или уже существующий объект в элемент OLE Container.
• Paste Special (Специальная вставка). Открыть диалоговое окно Paste Special, которое позволяет вставить объект, скопированный в буфер обмена из другого OLE-совместимого приложения. Команда Paste позволяет встроить объект в элемент управления, а команда Paste Special позволяет создать связь с объектом, находящимся в буфере обмена. Диалоговое окно Paste Special выглядит так же, как и диалоговое окно Insert Object (Вставка объекта) с той лишь разницей, что опции диалогового окна Paste Special воздействуют на объект, находящийся в данный момент в буфере обмена.
• Create Link (Создать связь). Создать связанный объект Доступно, если установлено свойство SourceDoc элемента управления OLE Container.
• Delete Link (Удалить связь). Удалить связь, преобразуя связанный объект во встроенный.
• Create Embedded Object (Создать встроенный объект). Создать встроенный объект. Появляется в том случае, если установлено значение свойства SourceDoc или Class.
Примечание
Чтобы другие пользователи могли работать с вашей программой, им необходима копия приложения, создавшего файл. Если элемент управления OLE содержит документ Word, то пользователи вашего приложения не смогут ни просмотреть, ни отредактировать документ, если на их системе Word не установлен. Кроме того, пути к связанным файлам должны быть указаны правильно. В противном случае, при запуске приложения другие пользователи смогут увидеть только изображение первоначальных данных.
Метод
Create TextFHe
Этот метод создает новый текстовый файл и возвращает объект TextStream, который используется для чтения текста из файла или записи его в файл. Синтаксис метода таков
Set TStream =
FSys.CreateTextFile(filename, overwrite, Unicode)
Аргумент
filename определяет имя создаваемого файла и является единственным обязательным аргументом; overwrite — булево значение, показывающее, можно ли обновлять (перезаписывать) существующий файл (True), или нет (False). Если опустить аргумент overwrite,
то существующий файл не обновляется. Последний аргумент Unicode определяет, будет файл создаваться в формате Unicode или в формате ASCII. Если аргумент Unicode – True, то новый файл создается в формате Unicode, в противном случае - как ASCII-файл. Если опустить аргумент Unicode,
то создается ASCII-файл.
Чтобы создать новый текстовый файл, необходимо создать переменную типа FileSystemObject, а затем вызвать метод CreateTextFile.
Set TStream =
FSys.CreateTextFile ("с:\testfile.txt")
Переменная
TStream представляет объект TextStream, методы которого позволяют писать в указанный файл или читать из него (см. параграф "Методы объекта TextStream" далее в этой главе).
OpenTextFile
Метод OpenTextFile предназначен для открытия существующего файла. Он имеет следующий синтаксис.
FSys.OpenTextFile(filename, lomode, create, format)
Данный метод открывает существующий файл и возвращает объект TextStream, который использоваться для чтения из файла или записи в него. Filename —
единственный обязательный аргумент. Аргументом iomode может быть одна из констант, перечисленных в таблице ниже.
Таблица 20.1. Допустимые значения аргумента iomode метода OpenTextFile
Константа
Значение
Описание
ForReading ForAppending
1
2
Файл открывается для чтения
Файл открывается для добавления новых данных
Необязательный аргумент create —
булево значение, показывающее, будет ли создан новый файл при отсутствии указанного в filename.
Если значение этого аргумента - True, новый файл создастся. Последний аргумент format
также необязателен и принимает значения True (файл открывается в Unicode-формате) или False (файл открывается в ASCII-формате). Если опустить аргумент format, то файл откроется в ASCII-формате.
Чтобы открыть объект TextStream для чтения, используйте следующий оператор.
Set TStream = FSys.OpenTextFile ("С:\testfile.txt", ForReading)
Метод OpenTextFile возвращает объект TextStream, методы которого позволяют писать в заданный файл или читать из него.
Теперь, когда уже ясно, как используется объект
FileSystemObject для открытия и создания файлов, ознакомимся с объектом TextStream, который позволяет читать из файла и писать в него. Объект FileSystemObject включает много других методов, позволяющих обращаться к различным устройствам, копировать и удалять файлы или целые папки и т.д. О методах объекта FileSystemObject мы расскажем чуть позже, а сейчас рассмотрим манипулирование текстовыми файлами с помощью объекта TextStream.
Методы элемента управления
Data
К встроенным функциональным возможностям элемента управления Data, которые действительно впечатляющи, можно обращаться из кода приложения, используя методы Data. Самые простые методы — это методы перемещения, соответствующие действиям четырех кнопок перемещения.
• MoveFirst. Перемещает элемент управления на первую запись.
• MoveLast. Перемещает элемент управления на последнюю запись.
• MovePrevious. Перемещает элемент управления на предыдущую запись.
• MoveNext. Перемещает элемент управления на следующую запись.
Эти методы используются для реализации кнопок перемещения. Однако, при этом, необходимо помнить о трех частных случаях: (1) когда Data позиционируется на первую или последнюю запись; (2) когда нажата кнопка Previous, в то время как Data находится на первой записи; (3) когда нажата кнопка Next, в то время как Data находится на последней записи.
VB6 в действии: проект Data2
Приложение Data2 подобно приложению Datal, но использует другую базу данных. База данных BIBLIO, поставляемая с Visual Basic, содержит названия книг, фамилии издателей и авторов. Структура этой базы показана далее в этой главе, а в этом приложении сформирован интерфейс для управления таблицей Titles, которая содержит поля Title (Название), ISBN (Издательский код), Description (Описание), Subject (Предмет), Comments (Примечания) и многое другое. Форма приложения Data2 изображена на рис. 17.5.
Рис. 17.5 Приложение Data2 методы Data для реализации кнопок прокрутки
Форма разрабатывается достаточно просто. Для этого выполните следующие действия:
1. Поместите элемент Data и соедините его с базой данных BIBLIO, задав в свойстве DatabaseName путь к базе данных в системе, а в свойстве RecordSource — таблицу Titles.
2 . Разместите на форме элементы управления, связанные с данными, и подключите их к Data, установив в их свойствах DataSource значение Datal и в свойствах Datafield - отображаемые поля.
Программа для кнопок First и Last вызывает соответствующий метод перемещения.
Программа 17.1. Кнопки First и Last
Private Sub FirstBttn_Click ()
Data1.Recordset MoveFirst
End Sub
Private Sub LastBttn Click()
Data1.Recordset.MoveLast
End Sub
Код для двух других кнопок немного сложнее, поскольку он написан с учетом свойства
EOF элемента управления.
Программа 17.2. Обработка щелчка на кнопке Next
Private Sub NextBttn_Click()
Data1.Recordset.MoveNext
If Data1.Recordset.EOF Then
MsgBox "You are on the last record"
'(Вы находитесь на последней записи)
Data1.Recordset.MoveLast
End If
End Sub
Программа перемещается на следующую запись, а затем проверяет свойство EOF. Если EOF равно True, то элемент управления Data переместился на запись, расположенную за последней. Программа отображает сообщение, что достигнута последняя запись, и затем возвращается на нее.
Примечание
Переход на запись, находящуюся за последней, допустим. Это пустая запись, которую можно отредактировать и добавить к таблице. Проблема возникнет, если снова щелкнуть на кнопке Next. Попытка переместиться далее вызовет ошибку исполнения программы. Именно поэтому необходимо обработать эту ситуацию сразу, если выполняется условие EOF = True. Заметьте: когда отображается сообщение, поля пусты. Обычно необходимо выдавать сообщение при перемещении на последнюю запись. Данный же пример показывает, что после последней записи в RecordSet действительно имеется пустая запись.
Код для кнопки Previous такой же. Он вызывает метод MovePrevious, а вместо свойства EOF проверяет свойство BOF элемента управления Data.
Программа 17.3. Кнопка Previous
Private Sub PreviousBttn_Click()
Data1.Recordset.MovePrevious
If Data1.Recordset.BOF Then
MsgBox "You are on the first record"
'(Вы находитесь на первой записи)
Data1.Recordset.MoveFirst
End If
End Sub
Методы поиска записей
В дополнение к методам перемещения элемент управления Data предоставляет четыре метода для поиска записей в RecordSet. Одна из основных операций, которые выполняются над базами данных — нахождение требуемых записей. Следующие методы осуществляют нахождение записей, удовлетворяющих заданным критериям.
• FindFirst. Находит первую запись;
• FindLast. Находит последнюю запись;
• FindNext. Находит следующую запись;
• FindPrevious. Находит предыдущую запись.
Эти методы находят в RecordSet любую запись на основе критериев, заданных пользователем. Синтаксис всех этих методов одинаков.
RecordSet.FindFirst criteria
Параметр
criteria — строковое выражение, определяющее отношение между значениями полей и константами. Следующее выражение находит первую запись в RecordSet, поле State которой равно NY.
Datal.RecordSet.FindFirst "State = 'NY' "
Обратите внимание: строковая константа в строке критерия заключена в одинарные кавычки. Определенные пользователем критерии могут содержать несколько полей, логические операции и операции отношении. Следующий оператор находит первый счет, выданный в 1997 году, с общей стоимостью 1000 $ или более.
Datal.RecordSet.FindFirst "InvoiceDate > '12/31/1996'._
And Invoice >= 1000"
В дополнение к обычным операциям отношений можно использовать оператор LIKE, который позволяет находить записи, удовлетворяющие шаблону. Например, чтобы найти любую книгу в базе данных BIBLIO со словом SQL в заголовке, используйте следующий метод Find.
Recordset.FindFirst "Title LIKE '*SQL*' "
Строка *SQL* — это шаблон для нахождения любого количества символов до и после символов SQL. Другими словами, он соответствует заголовкам типа:
Введение в SQL, Овладение SQL-методами или SQL: Руководство пользователя.
Как работает метод Find
В данном случае поиск методом Find был выполнен без учета регистра. Таким образом, параметр *SQL* соответствовал SQL, sql и Sql. Для изменения заданного по умолчанию режима поиска на сравнение без учета регистра используйте следующий оператор:
Option Compare Text
Для сравнения с учетом регистра используйте другой оператор:
Option Compare Binary
Выражение Option Compare помещается в объявлениях форм или в модуле.
При вызове метода Find (Поиск) Visual Basic находит запись, соответствующую заданным критериям и устанавливает элемент Data на эту запись. В программе, однако, необходимо сначала проверить значение свойства NoMatch, которое устанавливается в False, если запись найдена, и в True — в противном случае. Следующий фрагмент программы показывает, как используются методы Find.
Data1.RecordSet.FindFirst "City= ' Berlin' "
If Data1.Recordset.NoMatch Then
MsgBox "No such record found"
' (Запись не найдена)
Else
MsgBox Datal.Recordset.Fields ("Country")
End If
Этот фрагмент кода находит первую запись, значение поля City которой равно Berlin. Если такой записи нет, то программа выводит соответствующее сообщение. Если запись найдена, то отображается значение поля Country (Страна).
VB6 в действии: проект FindDemo
Приложение FindDemo демонстрирует поиск записей в RecordSet с помощью метода Find. Эту небольшую утилиту можно использовать в ваших приложениях. Первый элемент управления ComboBox позволяет выбрать таблицу, а второй элемент ComboBox — поле. Затем в текстовом поле Search For можно ввести параметры для операции поиска и, нажимая кнопки, найти записи, удовлетворяющие заданным критериям. (Программа, позволяющая извлекать имена таблиц из базы данных NWIND и имена полей из выбранной таблицы, приведена в параграфе "Отображение баз данных" далее в этой главе.)
Рис. 17.6. Приложение FindDemo: использование методов Find
Как видно из рис. 17.6, можно определить дополнительные поля в параметре поиска, помимо выбранного в ComboBox. Любые строковые константы в поле Search For должны быть заключены в одинарные кавычки. В качестве альтернативы можно написать процедуру, которая заменяет двойные кавычки в строке одинарными..
Если запустить приложение FindDemo, то появятся столбцы, отличающиеся от показанных на рис. 17.6. Указатель мыши на разделительной линии между двумя столбцами связанного с данными элемента управления Grid (Сетка) превращается в двойную стрелку, указывая, что можно изменять размеры столбца. На рис. 17.6 некоторые столбцы с ненужными данными удалены (их ширина равна нулю), а размеры остальных столбцов изменены, чтобы отобразить данные, представляющие интерес (контактные имена и города).
Форма приложения FindDemo содержит связанный с данными элемент управления Grid и невидимый элемент управления Data. Элемент управления Grid рассмотрен далее в этой главе. Вы увидели, что он может быть связан с элементом Data и отображает содержимое RecordSet в табличном виде. Код, обеспечивающий заполнение данными обоих элементов управления ComboBox, приведен в параграфе "Доступ к. полям в объекте RecordSet" этой главы.
Программа 17.4. Кнопка Find First
Private Sub firstBttn_Click()
On Error GoTo SQLError
Data1.Recordset.FindFirst GenerateSQL()
If Data1.Recordset.NoMatch Then
MsgBox "No such record found"
'( He найдено ни одной записи)
End If
Exit Sub
SQLError:
MsgBox Err.Description
End Sub
Функция GenerateSQL(). Эта функция генерирует параметр поиска для всех операций Find. Значение, возвращаемое функцией GenerateSQL(), используется совместно методами Find. После вызова метода FindFirst программа проверяет свойство NoMatch. Если оно равно True, то программа выводит сообщение. Если запись, соответствующая критерию, найдена, то элемент управления Data автоматически устанавливается на эту запись.
Функция GenerateSQL() извлекает строку из текстового поля txtsearchValue, присоединяет ее к выбранному полю и возвращает строку, использующуюся как параметр метода Find. Большая часть кода приложения обрабатывает потенциальные ошибки. Основная работа выполняется функцией GenerateSQL(), которая формирует критерии поиска, как показано ниже.
Программа 17.5. Функция GenerateSQL()
Private Function GenerateSQL() As String
GenerateSQL = cmbFields.Text & " " & txtsearchValue
End Function
Методы объекта TextStream
После создания объекта TextStream с помощью методов CreateTextFile
или OpenTextFile объекта FileSystemObject для чтения и записи в файл можно использовать следующие методы.
Примечание
Как следует из его имени, объект TextStream предназначен только для работы с текстовыми файлами.
Read. Этот метод считывает определенное число символов из объекта TextStream. Его синтаксис:
TStream.Read(characters)
Здесь
characters - количество символов, которые необходимо прочитать.
ReadAll. Этот метод считывает текстовый файл целиком и возвращает текст в виде строковой переменной. Его синтаксис таков.
fileText = TStream.ReadAll
Здесь
fileText - строковая переменная (или типа Variant).
ReadLine. Этот метод считывает одну строку текста за раз (до символа новой строки, не включая его) из текстового файла и возвращает результирующую строку. Его синтаксис показан ниже.
fileText = Т Stream.ReadLine
Skip. Этот метод пропускает определенное число символов при чтении из текстового файла. Синтаксис метода следующий.
TStream.Skip(characters)
Здесь
characters - число пропускаемых символов.
SkipLine. Этот метод пропускает следующую строку текстового файла. Его синтаксис таков.
TStream.SkipLine
Символы пропускаемой строки отбрасываются до символа новой строки включительно.
Write. Этот метод записывает строку в TextStream файл. Синтаксис метода:
TStream.Write(string)
Здесь
string — строка (типа String или Variant), записываемая в файл. Строки записываются в файл без вставки пробелов или разделителей между строками. Используйте метод WriteLine для записи символа новой строки или строки, заканчивающейся этим символом.
WriteLine. Этот метод записывает в файл строку, заканчивающуюся символом новой строки. Синтаксис метода:
TStream.WriteLine(string)
Здесь
string — текст, который необходимо записать в файл. Если вызывается метод WriteLine без аргумента, то запишется символ новой строки.
WriteBlankLines.
Этот метод записывает заданное число пустых строк (символов новой строки) в файл. Его синтаксис:
TStream.WriteBlankLines(lines)
Здесь
lines - число пустых строк, записываемых в файл.
Методы объекта
Wscript
Объект Wscript имеет несколько методов, большая часть которых подобна функциям VBScript. Наиболее важные методы — CreateObject и GetObject — аналогичны функциям VBScript с такими же именами Рассмотрим методы Wscript.
Echo. Отображает одно или более значений в окне сообщений. Можно отобразить синоним имени Windows Scripting Host, воспользовавшись функцией MsgBox().
Wscript.Echo Wscript.Name
Можно отобразить несколько значений, разделив их запятыми. Они отобразятся одно за другим с пробелом между ними. Следующий оператор отображает окно сообщений, показанное на рис. 20.10.
Wscript.Echo "string argument", Wscript.Name, 98.9+1
Свойство Name заменено его значением, а выражение 98, 9+1 - вычислено
Рис. 20.10. Метод Echo отображает несколько значений подряд
Echo — это простой метод и может использоваться в качестве примитивного инструмента отладки Функция
MsgBox() и метод Pop-Up (описан ниже) предоставляют гораздо больше возможностей.
Quit. Завершает выполнение сценария и может вернуть код ошибки. Его синтаксис:
Wscript.Quit errorCode
Необязательный аргумент errorCode - возвращаемый код ошибки. По умолчанию этот метод возвращает 0. Код ошибки может использоваться для контроля завершения приложения нормально или с ошибками.
InternetExplorer и элемента управления WebBrowser
Методы элемента управления WebBrowser и объекта InternetExplorer позволяют переместиться к новым или к уже посещенным URL.
GoBack, GoForward (Переместиться вперед. Переместиться назад). Эти методы управляют перемещением назад или вперед на один URL в списке посещенных узлов, который поддерживается автоматически элементом управления WebBrowser или объектом InternetExplorer. При попытке перемещения за пределы списка генерируется ошибка. Чтобы ее перехватить, необходимо включить код, обрабатывающий данную ошибку.
GoHome, GoSearch (Перейти к домашней странице. Перейти к поиску). GoHome — метод, который перемещает пользователя к домашней странице; GoSearch — метод, который перемещает пользователя к странице, определенной в диалоговом окне Internet Explorer Options.
Navigate (Переместиться).
Этот метод передвигается на URL или открывает HTML-файл, заданный в первом параметре метода. Его синтаксис:
Navigate URL [Flags], [TargetFrameName,] [PostData,] [Headers]
Все параметры, кроме первого, имеют значения по умолчанию. Параметр URL -адрес ресурса, который нужно показать на элементе управления. Параметр Flag — константа или значение, которое определяет, добавить ресурс к списку хронологии, читать или записывать из кэша, и отображать ли ресурс в новом окне. Его значения приведены в табл. 21.1.
Таблица 21.1. Значения параметра Flags
Константа
Значение
Описание
NavOpenlnNew Window
1
Открывать ресурс или файл в новом окне
NavNoHistory
2
Не добавлять ресурс или имя файла к списку хронологии
NavNoReadFrom Cache
4
Не читать из кэша жесткого диска при этом передвижении
NavNo Write To Cache
8
Не записывать результаты передвижения в кэш жесткого диска
Параметр Target FrameName - имя фрейма, в котором отображается документ. Если документ, отображенный на элементе управления WebBrowser, содержит фреймы, то можно отобразить новый документ в одном из существующих фреймов.
Document
Объект Document поддерживает несколько методов, которые позволяют работать с его содержимым.
Open (Открыть).
Открывает документ для вывода. Текущий документ очищается, а новые строки помещаются в документ с помощью методов Write и WriteLn.
Примечание
Метод Open объекта Document открывает текущий документ для вывода и не имеет ничего общего с методом Open объекта Window, который запускает новый экземпляр Internet Explorer и отображает в нем документ.
Write string (Записать строку). Записывает значение строковой
переменной в документ. Параметр метода помещается в текущий документ в текущую позицию, но не отображается до закрытия документа методом Close.
WriteLn string.
Записывает строковую переменную в текущий документ с управляющим символом "новая строка", добавленным в конец строки. Управляющий символ игнорируется броузером, так что строковый метод WriteLn работает так же, как метод Write string.
Close (Закрыть).
Закрывает документ и заставляет всю информацию, записанную в него с помощью методов Write и WriteLn, отображаться как в HTML-документе, загруженном в окне броузера.
Clear (Очистить).
Очищает содержимое документа.
Использование методов объекта Document
Описанные методы позволяют программисту (или Web-дизайнеру) с помощью сценария создать HTML-документ, что и показано в примере
Pagel.htm следующего параграфа. Методы объекта Document обычно вызываются в следующем порядке.
Document.open
Document.write string
........
Document.write string
Document.close
Переменная string или литеральная константа могут быть чем угодно, что обычно появляется в HTML-документе (текст, HTML-отметки, гиперсвязи и т.д.). Параметр метода Write может содержать HTML-теги, что позволяет создавать Web-страницы на лету. Следующие операторы отображают заголовок первого уровня, расположенный на странице по центру.
Document.write ""
Document.write "Welcome to our Active Pages "
' (Добро пожаловать на наши активные страницы)
History
Объект History из Scripting Model поддерживает список уже посещенных узлов и предоставляет возможность обращения к ним через методы объекта History, описанные ниже. Объект History не имеет собственных свойств или событий.
Back n (Назад).
Позволяет перемещаться обратно в списке хронологии на п шагов, как при нажатии кнопки Back n раз. Чтобы переместится на предыдущий URL, используется выражение
call Window.History.back(0)
или
call Window.History.back
Forward n (Вперед).
Приводит к перемещению вперед по списку хронологии на п шагов, как при нажатии кнопки Forward n раз.
Go n (Перейти к).
Позволяет переместиться на п-ый
элемент в списке хронологии. Следующее выражение осуществляет переход к первому URL в списке.
Window.History.gо 1
Методы объектов
Scripting
Объекты Scripting также имеют методы. Объект Document, например, имеет метод Write, который позволяет сценарию помещать текст непосредственно на Web-страницу — создавать Web-страницы на лету.
Метод Write воспроизводит строку на текущей странице. Следующий оператор выводит текущую дату на страницу.
Document.Write Date ()
Если использовать HTML, то необходимо жестко запрограммировать дату и модифицировать документ ежедневно. Функция VBScript Date() возвращает текущую дату, но VBScript не предусматривает методы для фактического отображения даты на странице. Чтобы отобразить что-либо на странице из сценария, используются объекты Scripting Model.
Предположим, имеется простой HTML-документ.
Welcome to Visual Basic and the Web
Этот документ воспроизводит страницу с зеленым фоном и заголовком первого уровня. Можно создать ту же страницу, используя код
VBScript.
В чем преимущества свойства Write для создания страницы? Гибкость. Эта страница фактически сгенерирована на клиентском компьютере. Если необходимо отображать дату и время открытия страницы, то надо добавить следующую строку кода VBScript.
Document.Write "This page was opened on " & date() & _
", at" & time()
'(Эта страница была открыта... в. . . )
Метод Write предусматривает большую гибкость. Можно написать более сложный VBScript-код для создания на лету сложных страниц. Например, можно запросить пользователя о его имени и индивидуализировать Web-страницу следующим образом.
UserNaine = InputBox("Please enter your name")
' (Введите, пожалуйста, ваше имя)
Document.Write "Welcome to our Active Pages," &
UserName & ""
Реальный заголовок будет отличаться на каждом клиентском компьютере в зависимости от ответа пользователя на запрос. Ниже показана типичная страница, сгенерированная на лету с помощью VBScnpt-кода, который управляет объектами IE Scripting.
Рис. 21.7. Создание HTML-документа на лету: использование метода Write объекта Document
Ниже показан HTML-файл, который создал страницу, приведенную на рис. 21.7.
Demo Page
SCRIPT LANGUAGE="VBSCRIPT">
UserName = InputBox ("Please enter your name")
'(Введите, пожалуйста, ваше имя)
Document-Write "Welcome to our Active Pages, " _
& UserName & ""
' (Добро пожаловать на наши активные страницы)
Document.Write " "
Document.Write "This page was opened on " & date() &
", at " & time()
' (Эта страница была открыта...)
Обратите внимание: этот документ не содержит тега HTML в разделе BODY. Весь документ сгенерирован из раздела сценария страницы командами VBScript.
В следующих параграфах исследуется объект Document из Scripting Model, как наиболее важный объект с точки зрения программиста на VB.
Модули и модули классов
Программные компоненты ActiveX реализованы в Visual Basic в виде модулей классов. Модули существуют в Visual Basic еще с его первой версии. Они содержат объявления переменных и подпрограмм (функций и процедур), которые доступны всем другим компонентам приложения. Многие примеры, приведенные в предыдущих главах, имеют собственные модули. Функция ConvertTemperature (degrees As Double) может быть вызвана из нескольких мест кода и из многих форм, если ее определить в модуле. Процедуры, хранимые в модуле, могут быть вызваны из любого места приложения. Это также справедливо и для переменных, которые должны быть доступны многим процедурам. Это один из способов, благодаря которому формы и процедуры различных форм могут обмениваться информацией.
Можно рассматривать процедуры, как методы модуля, однако нет потребности предварять их вызов суффиксом в виде имени модуля. Общедоступные (public) переменные, которые находятся в модуле, также могут рассматриваться как свойства модуля. Таким образом, модуль очень похож на класс. В Visual Basic классы реализованы как модули специального типа, называемые модулями классов.
Здесь может возникнуть вопрос: "Зачем беспокоиться о классах, если модуль может предоставить функциональные возможности, необходимые для создания приложения?" Если необходимо создать всего лишь несколько процедур и глобальных переменных для одного проекта, то, возможно, лучше разместить их в одном модуле. Однако, если планируется использовать эти же процедуры в
различных проектах, то необходимо конструирование модуля класса. Допустим, несколько функций были реализованы в модуле и протестированы в составе проекта А. Их реализация оказалась вполне удовлетворительной. Если потом создается другой проект — В, который использует тот же модуль, то логика подсказывает, что функциям модуля необходима некоторая переделка. Тогда модуль дополняется несколькими новыми переменными типа public, в результате чего с проектом В он уже работает прекрасно. Но при этом проект А, скорее всего, перестает быть работоспособным. Даже если приказать себе больше не трогать модуль, то как быть в случае групп разработчиков, работающих над общим проектом? Позволить многим программистам иметь доступ к одному модулю из своих проектов, значит ожидать катастрофы. Один из них неизбежно изменит программу и испортит некоторые из существующих проектов.
Другой потенциальной опасностью является конфликт имен. Если добавить в проект модуль с несколькими глобальными переменными, некоторые из них могут иметь имена, совпадающие с теми, которые используются в других проектах. В этом случае правила видимости определяют, какая переменная имеется в виду (она может не совпадать с той переменной, которую хотелось бы использовать). Свойства в модуле классов не могут быть доступны только по их имени. Они должны использоваться посредством выражения типа
ClassName.VariableName, которое делает свойство уникальным не только в текущем проекте, но и в операционной системе.
Модули VB: краткий обзор
Обычно легче понять новую концепцию, если ассоциировать ее с другой, уже освоенной. Начнем с обзора модулей Visual Basic, а затем посмотрим, как те же концепции могут быть применены к модулям классов. Разработаем небольшое приложение, подсчитывающее время (оно может стать частью другого приложения, которому необходимо вычислять время выполнения своих операций). Приложение должно иметь возможность запускать и останавливать таймер по своему желанию. Когда в приложении выполняется вспомогательный программный код, необходимо иметь возможность приостановить таймер, а затем продолжить отсчет времени. После завершения операции, продолжительность которой определяется, должна быть предусмотрена возможность считывания прошедшего времени. Поместим все необходимые переменные и функции в модуль. При этом его можно будет повторно использовать в других проектах. (Вообще, такая практика является хорошим тоном в программировании — изолировать механизм определения промежутков времени от остального кода и сделать его доступным приложению через вызов нескольких процедур). Приложение, которое будет разработано в этом разделе, называется TimerMod, и его можно найти в папке этой главы на компакт-диске.
Создайте новый проект и добавьте в него модуль. Затем введите в этот модуль следующие строки.
Программа 15.1. Код модуля TimerMod
Public TotalInterval As Double
Dim T1 As Double
Sub StartCounting()
Tl = Time
End Sub
Sub StopCounting ()
Totallnterval = Totallnterval + Time – Tl
End Sub
Sub ResetTimer()
Totallnterval = 0
End Sub
Процедура
StartCounting()
запускает таймер, а процедура StopCounting() — останавливает. Каждый раз после остановки таймера переменная Totallnterval
обновляется. Для получения затраченного времени приложение должно прочесть значение этой переменной. И, наконец, процедура ResetTlmer() переустанавливает таймер. Такой механизм отсчета времени не позволяет прочитать затраченное время во время работы таймера. Необходимо сначала вызвать метод StopCounting для обновления переменной Totallnterval,
затем считать значение переменной.
А сейчас перейдите к формам приложения и поместите две кнопки на форму. Установите их заголовки в Start Timing и Show Interval, как показано на рис. 15.1. Затем добавьте следующие строки в содержимое окна кода формы.
Программа 15.2. Код тестирования
TimerMod
Private Sub Commandl_Click()
If Coinmandl.Caption = "Start" Then
StartCounting
Command1.Caption = "Stop" ' (Остановка)
Else
StopCounting
Command1.Caption = "Start" ' (Запуск)
End If
End Sub
Private Sub Command2_Click ()
MsgBox "I've been counting for " & vbCrLf & _
Hour(TotalInterval) & "hours" & vbCrLf & _
Minute(TotalInterval) & " minutes and" & vbCrLf & _
Second(TotalInterval) & " seconds" & vbCrLf
' (С начала отсчета прошло... часов... минут и... секунд)
End Sub
Выполните приложение, запустите таймер, остановите и запустите его еще несколько раз. Затем нажмите кнопку Show Interval для оценки затраченного времени в часах, минутах и секундах.
Программа работает, но потенциально существуют несколько проблем. Если другой разработчик имеет доступ к этому же модулю, он может попытаться присвоить переменной
Totallnterval
какое-либо значение:
TotalInterval = 0.00453567
Такое присваивание допустимо для интервала времени, но что произойдет, если он попытается присвоить недопустимое значение, например:
TotalInterval = 99
Рис. 15.1. Форма проекта TimerMod
Вероятнее всего, программа будет работать, но она больше не будет правильно информировать о затраченном времени. Другой программист может проигнорировать процедуру ResetTimer() и попытаться переустановить переменную Totallnterval из процедуры StartCounting(). Возможно, его действительно не интересует остановка и возобновление процесса отсчета времени и ему удобно переустанавливать переменную Totallnterval каждый раз при вызове функции StartCounting(). Его проект будет работать (и с меньшим числом вызовов), но ваш нет. В этом и заключается наиболее важное преимущество в реализации вспомогательных процедур в виде модулей классов — создание компонентов, совместимых со многими приложениями. В дополнение, реализуя механизм отсчета времени отдельно от приложения, можно скрыть детали ее реализации от разработчиков, которые ее используют. Ведь на самом деле не надо знать, как Excel вычисляет сложное математическое выражение в процессе вызова его метода Evaluate.
Наборы записей
RecordSets
RecordSets — это объекты, содержащие множество (коллекцию, набор) записей, выбранных из одной или нескольких таблиц. В программировании базы данных RecordSets аналогичен переменным в обычном программировании. Нельзя обращаться к таблицам баз данных непосредственно. Единственный способ просматривать записи и управлять ими — использование объектов RecordSet. RecordSet состоит из столбцов и строк, похож на таблицу, но может содержать данные из нескольких таблиц. Содержимое сетки, приведенной на рис. 172, получено из одной таблицы, на основе которой и формируется RecordSet. Такой набор - результат запроса данных, например, просмотр имен заказчиков и суммы их заказов в данном месяце.
Рис. 17.2. Таблица Products базы данных NWIND: выделенная строка — запись в таблице Products
Примечание
RecordSets можно рассматривать как объектные переменные. Они хранят результаты запросов или всю таблицу базы данных, как числовые переменные хранят числа. Однако содержимое RecordSet имеет более сложную структуру (поскольку состоит из строк и столбцов), и каждая ячейка в этой структуре может иметь различный тип. Для обращения к содержимому RecordSet используются свойства и методы.
RecordSet позволяет просмотреть некоторые данные, отобранные из базы данных согласно критериям, определенным пользователем. Существует три типа RecordSets
• DynaSet (Динамический набор), предназначенный для изменения содержимого базы данных;
• SnapShot (Моментальный снимок), являющийся статическим набором записей (только для чтения);
• Table (Таблица), которая напрямую обеспечивает просмотр таблиц.
DynaSet и SnapShot обычно создаются с помощью SQL-операторов (Structured Query Language — язык структурированных запросов). SQL-операторы рассмотрены в этой главе позже, а пока запомните, что это — команды, использующиеся для определения критериев отбора данных из базы данных. (Можно использовать SQL-команды для редактирования и создания новых баз данных, но это в книге не рассмотрено). Изменения, вносимые пользователем с помощью DynaSet, находят отражение в исходных таблицах SnapShot позволяет осуществлять только просмотр данных.
Наиболее гибким и мощным типом коллекции записей является
DynaSet, хотя некоторые операции (такие, например, как поиск) могут быстрее выполняться в наборах типа Table. Однако тип Table требует значительных накладных расходов. Наименее гибкий тип - это SnapShot, хотя и наиболее эффективный в смысле накладных расходов (это справедливо только в случае, когда объем выборки невелик – прим. ред). Если модифицировать базу данных не надо - выберите тип SnapShot.
Существует разновидность типа SnapShot - forward-only SnapShot (просмотр вперед, более ограниченный, чем тип SnapShot, но и более быстрый). Forward-only SnapShot позволяет перемещаться по записям только вперед. Он используется в случаях, когда необходимо последовательно просматривать записи (использование их значений для вычислений, копирование выбранных записей в другую габлицу, и так далее). Не предоставляя методов возврата к записям, набор такого типа требует наименьших накладных расходов.
Набор типа Table - это ссылка на таблицу в базе данных. Table быстрее, чем другие типы наборов. Он синхронизируется с данными таблицы и используется для редактирования базы данных. Кроме того, при доступе к таблице посредством набора записей типа Table для выполнения быстрого поиска данных используются индексы. Недостаток записей этого типа - они могут содержать только записи, принадлежащие одной таблице.
Написание и выполнение сценариев
Напишем и выполним простейший сценарий. Сценарий — это текстовый файл с командами VBScript, выполняющий определенную задачу. Напишем сценарий, сообщающий, сколько дней осталось до конца столетия. Запустите Notepad и введите строки программы 20.12.
Программа 20.12. Сценарий YEAR2000.VBS
DaysLeft = #1/1/2000# - Date ()
Message = DaysLeft & " days left for the year 2000"
'(... дней осталось до 2000 года)
MsgBox(Message)
При записи файла YEAR2000.VBS не забудьте выбрать тип All Files в команде Save As Туре. Если этого не сделать, то файл запишется как YEARS2000.VBS.TXT.
Выражение #1/1/2000# — это дата. В VBScript даты заключаются в символы "#". Date() — функция VBScript, возвращающая текущую дату. Ее значение вычитается из первого дня 2000 года, а результат сохраняется в переменной DaysLeft.
Для запуска сценария найдите файл YEAR2000.VBS на рабочем столе и выполните двойной щелчок на его значке. Будет выведено следующее окно.
Чтобы закрыть окно, щелкните на кнопке ОК.
Следующий параграф содержит основную информацию о
VBScript: переменных, функциях, операторах управления выполнением программы. Практические примеры не приведены: необходимо изучить основные структуры языка перед написанием какого-либо сценария.
Написание сценариев для HTML-страницы
Написание сценариев позволяет контролировать содержимое страницы и управлять им с помощью программы. Первыми двумя языками написания сценариев были JavaScript и VBScript. JavaScript основан на языке Java для рабочих станций SUN, a VBScript — на Visual Basic. В нашей книге используется VBScript.
Сценарий — это короткая программа, которая управляет элементами на странице и вставляется в HTML-документ между тегами
. Обычно SCRIPT документа размещается в разделе HEAD. Простой сценарий, который устанавливает цвет фона страницы и отображает приветственное сообщение, имеет следующий вид.
VBScript Demo
VBScript Demo
Элемент
Document задает документ, отображаемый в окне броузера. Доступ к его свойствам можно получить с помощью объекта Document. Свойства fgColor и bgColor задают (или считывают) цвет фона и текста документа. Функция MsgBox() уже известна. Есть много сходства между Visual Basic и VBScript, поэтому нет необходимости подробно рассматривать особенности VBScript.
Предупреждение
И все же имеется существенное отличие: VBScript не является типизированным языком. Как бы вы не объявили переменные, все они будут иметь тип Variant. Это является препятствием при вызове функций Visual Basic (например, объектных методов) из VBScript. Следует использовать функции преобразования данных (см. гл. 2) или заключать аргументы в скобки с целью преобразования типов VBScript и Visual Basic.
Языки написания сценариев, подобные VBScript, позволяют Web-разработчикам создавать динамически изменяющееся содержание их Web-страниц. Но это еще не все. Менее чем через год после появления VBScript, компания Microsoft решила "активизировать" Web-страницы - вот откуда термин ActiveX. Если есть средства программирования Web-страниц, почему бы ни дополнить их программируемыми объектами? Программируемые объекты — не что иное, как элементы управления ActiveX. Если есть возможность разместить элементы управления ActiveX на странице, то можно получить доступ к их методам и свойствам из среды VBScript и, таким образом, создать активную страницу. Активная страница похожа на небольшое приложение, запускаемое из Internet Explorer.
Следующим шагом была разработка элементов управления
ActiveX, которые можно было использовать на Web-страницах. Microsoft выпустила их большое количество. Сейчас с использованием Visual Basic 6 можно создавать свои собственные элементы управления ActiveX для использования на Web-страницах. В следующем параграфе мы протестируем элементы управления, разработанные ранее в гл. 16. В последней части главы рассмотрены DHTML, которые являются теми же HTML, но усовершенствованными с помощью фрагментов VBScript-кода.
Написание сценариев для
Windows
Можно использовать VBScript и его объект FileSystemObject при написании сценариев непосредственно для Windows. В этом параграфе рассмотрено создание сценариев, запускаемых в Windows 98, и автоматизация многих рутинных задач: подключение принтеров и сетевых драйверов, очистка папок и обработка большого количества файлов в пакетном режиме.
Приведем простой пример пакетной обработки для тех, кто незнаком с командными файлами DOS. Имеются две папки (в терминологии DOS — каталоги) — С:\ТМР и C:\DOCS\TEMP, содержащие временные файлы, которые необходимо удалять раз в день или чаще. Для этого надо выполнить такие команды.
CD С:\ТМР
DEL *.*
CD C:\DOCS\TEMP
DEL *.*
Команда CD (Change Directory) задает переход в другой каталог, а команда DEL *.* - удаляет все файлы в текущем каталоге. Если каталог содержит подкаталоги, то команда DEL *.* не поможет. Придется воспользоваться командой DELTREE.
Синтаксис командных файлов dos особенный. Например, в нем нет команд записи информации в файл (или чтения из файла). Чтобы записать выходную информацию командного файла в текстовый файл, надо воспользоваться символом перенаправления потока ввода/вывода (>). Для сохранения сообщений об ошибках, сгенерированных предыдущим командным файлом, в текстовом файле можно воспользоваться следующей командой (имя командного файла DELTEMP.BAT).
DELTEMP > ERRMSG.TXT
Затем можно прочитать сообщения, открыв файл
ERRMSG.TXT в любом текстовом редакторе.
Командные файлы DOS позволяют инициализировать принтеры, выполнять сетевые соединения, обрабатывать группы файлов и т.д. Любые операции, которые можно задавать в командной строке DOS, можно закодировать в командном файле.
То же самое можно делать в Windows 98. Ранние версии Windows не поддерживали пакетную обработку или языки сценариев, хотя многие пользователи испытывали в них необходимость. Язык сценариев Windows 98 - это VBScript, позволяющий использовать все преимущества системы без дополнительных затрат. Программист на VB готов к разработке сценариев для Windows.
В этой главе рассмотрено использование VBScript для автоматизации выполнения повседневных задач. Приводятся примеры, которые могут служить отправной точкой для написания собственных сценариев. Сначала мы научимся писать и запускать простые сценарии. Затем перейдем к изучению объектов Windows Scripting Host.
Написание сценария для приложения
Если приложение предоставляет классы, то можно добавить элемент управления Script на отдельную форму, например, на ScriptForm, и позволить пользователю приложения создать сценарий. Предположим, вы написали приложение, которое позволяет пользователю открывать файлы с изображениями и сохранять их в различных графических форматах (TIF, JPEG, NPG и т. д.). Пользователь, желающий преобразовать несколько файлов, не должен открывать и записывать каждый файл по отдельности. Ему проще написать сценарий, который в нужный момент открывает файл, преобразовывает его и записывает под другим именем на диск.
Следовательно, ваш класс должен предоставлять методы Open(fllename) для открытия графического файла, Convert(format1, format2)
— для преобразования из одного формата в другой, и SaveAs(filename) - для записи файла в новом формате. Процесс конвертирования формата графических изображений достаточно сложен (это описано в нескольких книгах), но если кратко, то необходимо иметь возможность преобразовывать процедуры в методы и привязывать их к классу.
VB6 в действии: проект StatCIss
Для ознакомления с использованием сценариев в приложениях рассмотрим простой класс, содержащий несколько несложных методов, используемых для вычисления основных статистических характеристик массива данных (рис. 20.6). На самом деле, здесь мы расширяем класс AXStat (см. гл. 15) и с его помощью добавляем возможности сценариев в приложения. Описание класса, который предоставляет законченную объектную модель (например, Excel), выходит за рамки этой книги, но приведенный ниже простой класс - пример того, как возможности сценариев добавляются в приложения.
Чтобы использовать класс StatCIss в проекте SEditor, необходимо выполнить следующие действия.
1 . Откройте проект SEditor и добавьте новый модуль класса.
2 . Запустите новый экземпляр Visual Basic, откройте проект AXStats (папка гл. 15 на компакт-диске) и скопируйте код модуля AXStats.
3 . Переключитесь в проект SEditor и откройте окно кода добавленного модуля класса.
4 . Добавьте код, скопированный из модуля класса AXStats.
Рис. 20.6. Проект StatCIss: вычисление основных статистических характеристик массива данных
Теперь имеется проект, состоящий из формы ScriptForm, на которой пользователь может вводить и выполнять сценарии, объект DisplayClass и класс AXStats, содержащий свойства и методы для вычисления основных статистических характеристик массива данных. Имеет смысл записать компоненты нового проекта в новую папку.
Примечание
Методы класса AXStats возвращают значения типа Double, в то время как VBScnpt является бестиповым языком. Каким образом сценарий взаимодействует с классом AXStats и интерпретирует возвращаемые значения? Можно использовать функции приведения типов, но не ожидайте, что пользователь (который вводит текст сценария) в состоянии выполнить все необходимые преобразования. Проще исправить код класса, удалив все типы. Для этого необходимо открыть окно Code для класса AXStats и удалить все объявления типов (часть As объявления методов и их типов). Для просмотра кода класса AXStats после исправления необходимо открыть проект в среде разработки VB.
Чтобы предоставить пользователю доступ к членам класса
AXStats (и позволить ему разрабатывать сценарии для обработки массивов данных), надо добавить ссылку на класс. Для этого в начало кода ScriptForm добавьте следующее объявление
Private Statistics As New AXStats
Затем добавьте объект Stat в элемент управления Script события Load формы
ScriptControll.AddObject "Stat", Statistics, True
Пользователь приложения получает доступ к членам класса
AXStats с помощью компонентов объектной переменной Stat или их имен. Далее следует небольшой сценарий для вычисления среднего арифметического четырех чисел. Введите следующий код в редактор сценария и щелкните на кнопке Execute Script.
Программа 20.11. Сценарий приложения StatCIss
Add 301
Add 44.50
Add 529
Add 124.5
Show "Mm значение " & Mm
Show "Max значение " & Мах
Show "Среднее " & Average
Если добавить несколько дополнительных методов для более сложных статистических характеристик (стандартное отклонение, корреляцию и т.п.), то пользователи захотят использовать ваше приложение для обработки данных в пакетном режиме. Если добавить ссылку на объект FileSystemObject, то можно будет использовать локальный диск для чтения данных и записи результатов.
В той же папке, что и StatCIss, находятся сценарии
MakeData и Process. Сценарий MakeData создает текстовый файл в корневом каталоге диска С: и записывает туда 100 случайных значений. Сценарий Process открывает указанный файл, добавляет данные к семейству данных класса StatCIss, вычисляет и отображает число элементов данных, их среднее, минимальное и максимальное значения. Чтобы открыть сценарий MakeData, необходимо выбрать в меню File команду Load и выполнить ее, щелкнув на кнопке Execute Script. Затем нужно открыть и запустить сценарий Process..
Совет
В этом проекте есть одна проблема. Оба класса используют метод Clear (один — для очистки набора данных класса AXStat, другой — для очистки нижнего элемента управления TextBox формы). Оператор Clear на самом деле очищает элемент управления TextBox. Дело в том, что в случае конфликта имен, приоритет имеют компоненты класса, добавленного первым. Можно указать конкретный метод с помощью имени класса, задаваемого в префиксе. Для очистки элемента управления TextBox используется оператор Output. Clear, а для очистки массивов данных — оператор Stat. Clear.
Для тестирования проекта StatCIss необходимо изменить установки обработчика ошибок в классе AXStat. Для этого выполните следующие действия.
1 . Выберите команду Options меню Tools, чтобы открыть окно Options.
2 . Выберите вкладку General.
3 . В секции Error Trapping отметьте флажок Break on Unhandled Errors Only (Останов только для необработанных ошибок).
Если эту опцию не установить, то приложение будет прерываться при каждой ошибке (например, при вызове метода Item класса AXStat с ошибочным значением индекса). Включение флажка Break on Unhandled Errors Only позволяет классу генерировать ошибки, которые обрабатываются в коде приложения. Элемент управления Script - удобное средство для добавления возможностей сценария в приложения, но его обработчики ошибок оставляют желать лучшего. Это его первая версия, возможно, в следующих версиях он будет более гибким. Информацию об этом можно найти на http: //www.microsoft. com/scripting.
Последняя часть главы посвящена написанию сценариев для операционной системы. Windows Scripting Host - еще одна область применения знаний VB, если вы освоились с использованием предоставляемых объектов.
О прилагаемом компакт-диске
Прилагаемый компакт-диск является самозагружаемым - вставьте его в дисковод, подождите несколько секунд и затем вы сможете:
• скопировать с него авторские примеры на ваш жесткий диск;
• воспользоваться учебным пособием, включающим поучительные примеры разработки приложений на Visual Basic (например, примеры манипулирования файлами);
• инсталлировать и испытать новое программное обеспечение компаний InstallShield, Blue Sky, NuMega и т.п.;
• читать справочную информацию по VB6 в формате Adobe Acrobat;
• усовершенствовать ваши приложения использованием элементов мультимедиа.
Авторские примеры
Эта книга содержит многочисленные примеры, разработанные автором с целью демонстрации возможностей языка Visual Basic, элементов управления ActiveX и принципов программирования вообще. Автор предоставляет вам возможность использовать их в ваших приложениях. Ниже приводится перечень некоторых из проектов.
CDBox. Эта утилита даст вам возможность поэкспериментировать с элементами Common Dilog Box в интерактивном режиме. Воспользуйтесь ей, чтобы выяснить, как настроить диалоговые окна Font или, скажем. File Open и включить их в ваше приложение, не написав и одной строки кода.
DirMap. Это приложение можно использовать для редактирования и печати содержимого любой папки на вашем жестком диске, включая ее подпапки.
Image. Это приложение, предназначенное для обработки изображений, может послужить отправной точкой для разработки ваших собственных программ. В нем вы также сможете найти многочисленные примеры использования API-функций.
MDIEdit. Быстрый и наиболее эффективный путь овладения техникой работы с многодокументным интерфейсом (MDI).
RFTPad. Приложение, подобное предыдущему, однако позволяющее форматировать и печатать текст.
Globe и TreeViewScan. Позволяют научиться, как заполнять элемент Tree View во время выполнения программ и как сохранять его содержимое на диске.
VBA Sample Code.
Позволяет научиться использовать в ваших программах возможности таких приложений, как Excel, Word и Outlook.
ScriptEdit.
Воспользуйтесь исходным текстом этого приложения, чтобы добавить к вашим программам возможности написания сценариев.
MCIDemo. Изучив этот пример, вы сможете разрабатывать мультимедийные приложения, использующие MCI-команды (воспроизведение аудио- и видеофайлов и многого другого).
Программное обеспечение других компаний
Этот компакт-диск включает, помимо всего прочего, чрезвычайно полезные для VB-программиста продукты других компаний. Воспользуйтесь ими для повышения эффективности вашей работы!
InstallShield. Express Professional 2.1. 30-дневная версия пакета для создания дистрибутивов.
RoboHelp. HTML 6, позволяющий создавать справочные файлы для VB-прило-жений, работающих в Windows 98.
Smartcheck от компании NuMega. Позволяет не только обнаружить ошибки, но и объясняет, что именно происходит, когда они случаются.
LEADTooIs 10. Это элемент ActiveX, выполняющий более 500 функций работы с графикой.
Adobe Acrobat.
Программное обеспечение, абсолютно необходимое для Web-разработок. Используйте его для чтения учебного пособия на этом CD.
Winzip. Лучшая программа архивирования файлов на сегодняшний день.
Объект Document
С точки зрения программирования объект Document - наиболее важный объект в иерархии. Он задает HTML-документ, отображаемый в окне броузера или в одном из фреймов. С помощью свойств и методов объекта Document можно управлять видом и даже содержанием документа. Свойство bgColor можно использовать для чтения или установки цвета фона документа. Свойство Title — для считывания заголовка документа. Метод Write - для задания содержания документа из кода сценария, создания документа на лету. В следующем параграфе рассмотрены свойства объекта Document и даны примеры их синтаксиса.
Объект FileSystemObject
VBScript предоставляет несколько новых объектов, доступных из Visual Basic. Наиболее важным (с точки зрения программиста на VB) является объект FileSystemObject, предоставляющий доступ к файловой системе компьютера, на котором выполняется приложение. Visual Basic предлагает несколько функций и операторов для доступа и манипулирования файловой системой, но объект FileSystemObject является более гибким средством, обеспечивающим методы и свойства для доступа к каждому каталогу и файлу на диске.
Чтобы получить доступ к файловой системе компьютера, на котором выполняется приложение, создайте переменную FileSystemObject с помощью функции Create0bject().
Set FSys = CreateObject ("Scripting. FileSystemObject")
Переменная
FSys
представляет файловую систему и определяется как объект.
Dim FSys As Object
Чтобы получить доступ к текстовым файлам на диске, используйте методы объекта FileSystemObject, описанные ниже.
Это один из способов доступа к файловой системе компьютера из Windows-сценария. В Visual Basic существует лучший метод, использующий раннее связывание для ускорения работы приложения. Вы можете добавить ссылку на объект Microsoft Scripting Runtime, выбрав команду References меню Project для открытия диалогового окна References. Укажите элемент Microsoft Scripting Runtime и щелкните на кнопке ОК. Как только ссылка будет добавлена к проекту, можно объявить переменную FSys с помощью оператора
Dim FSys As New Scripting.FileSystemObject
или
Dim FSys As New FileSystemObject
В окне Code после введения имени переменной FSys появится список компонентов объекта Script, и можно будет выбрать необходимый объект.
Поэкспериментируем с объектом FileSystemObject. Откройте новый проект и поместите командную кнопку на его форму. В окне Code формы введите следующее определение.
Dim FSys As New Scripting.FileSystemObject
Введите следующий оператор в обработчик события Click командной кнопки.
Debug.Print FSys.FileExists ("C:\AUTOEXEC.BAT")
Если файл C:\AUTOEXEC.BAT существует, то строка "True" появится в окне проверки. Компонент FileExists переменной FSys - это метод, который возвращает значение True, если файл существует. В противном случае он возвращает значение False.
Объект FileSystemObject предоставляет свойства и методы для операций с файловой системой, включая создание новых текстовых файлов (или открытие уже существующих), чтение или запись в них. Visual Basic имеет собственные операторы для доступа к текстовым файлам (и к двоичным), поэтому это подмножество объекта FileSystemObject не особенно интересно для программиста на VB. Они описаны здесь, потому что позволяют работать с текстовыми файлами при создании Windows-сценариев. Позже мы обсудим компоненты объекта FileSystemObject, которые полезны при написании Visual Basic-приложений и Windows-сценариев.
Операции чтения из текстовых файлов и записи в них являются основными при разработке сценариев Многие сценарии сохраняют свои результаты в текстовых файлах или считывают из них необходимые параметры (например, сценарии, обрабатывающие большое число файлов). Методы FileSystemObject для работы с текстовыми файлами также могут использоваться внутри сценариев в приложениях Visual Basic (см пример StatCIss ниже в этой главе).
Объект History
Объект History предоставляет методы для перемещения по списку хронологии броузера. Он позволяет обращаться к функциональным возможностям кнопок навигации броузера из кода.
Объект Links
Другой невидимый объект - Links - задает связь в HTML-документе и предоставляет свойства, позволяющие выяснить адресат связи. Число гиперсвязей в текущем документе задается свойством Links. Length. Все гиперсвязи в документе задается массивом Links. URL первой гиперсвязи — Links(O), Links(l) — это URL второй гиперсвязи и т.д. до Links(Links. Length-1).
Массив
Links возвращает объект Links, который предоставляет информацию об атрибутах гиперсвязей. Свойства объекта Links перечислены в табл. 21.4.
Таблица 21.4. Свойства объекта Links
Свойство
Действие
Href
Возвращает загружен во или устанавливает фрейм полный URL для объекта, который
Protocol
Возвращает или устанавливает протокол URL (обычно http)
Host
хост и порт URL
Hostname
хост URL — имя или IP-адрес
Port
или устанавливает порт URL
Pathname
или устанавливает имя пути URL
Search
или устанавливает поисковую часть URL, если она существует
Hash
или устанавливает хэш-часть URL
Target
Последним свойством объекта Frame является цель, которая была определена в <А> фрейме. Цель - окно или фрейм, в котором отображаются данные
Объект Location
Объект Location применяется к объектам Window и Frame и предоставляет информацию об окне (или фрейме) текущего URL. Примеры объекта Location уже приводились, но все его свойства не рассматривались. Перечислим все свойства объекта Location. Они возвращают информацию о URL текущего документа. Задавая их, можно перемещаться к другому документу.
Href. Это свойство возвращает или устанавливает полный URL объекта, который будет загружен в броузер. Используя это свойство, можно соединиться с другими URL с помощью VBScript-кода. Чтобы отобразить URL текущего документа, используется следующее выражение.
MsgBox "You are currently viewing " & document.location.href
' (Текущий документ...)
Можно отобразить другой документ в окне или фрейме с помощью следующего оператора.
document.location.href = "http://www.microsoft.com"
Как вы уже знаете их гл. 20, URL имеет определенные части. Свойства, приведенные в табл. 21.3, возвращают (или устанавливают) их.
Таблица 21.3. Свойства URL
Свойство
Действие
Protocol
Возвращает или устанавливает протокол URL (обычно http)
Host
Возвращает или устанавливает хост и порт URL. Хост и порт разделены двоеточием. Значение порта необязательно и редко используется
Hostname
Возвращает или устанавливает хост URL, который может быть как именем, так и IP-адресом
Port
Возвращает или устанавливает порт URL (необходимо задать номер порта в WWW URL)
Pathname
Возвращает или устанавливает имя пути URL. Это свойство можно использовать, когда необходимо показать документ, находящийся вне корня Web
Объект Navigator
Объект Navigator возвращает информацию о броузере. Одна из главных проблем, возникающая при разработке Web-страниц, следующая: два основных броузера (Netscape Navigator и Internet Explorer Microsoft) не полностью совместимы. Каждый из них поддерживает некоторые возможности, которыми другой не обладает. Это следствие конкуренции между Netscape и Microsoft, хотя установка новых стандартов позволила бы решить эту проблему.
Создание страниц, которые работают в обоих броузерах — не тривиальная задача, особенно для тех, кто разрабатывает активные страницы. Даже если нет возможности разработать страницу, которую можно представить на обоих броузерах, то можно иметь два набора страниц (каждый для своего броузера) и отображать соответствующие страницы. Даже для такой грубой методики необходимо изучить сценарий броузера, который открывает страницу.
Свойства объекта Navigator доступны только для чтения. Они возвращают информацию о броузере, в котором документ просматривается.
AppCodeName (Код имени приложения). Возвращает код имени приложения. Internet Explorer возвращает "Mozilla".
AppName (Имя приложения).
Возвращает имя приложения. Internet Explorer возвращает "Microsoft Internet Explorer".
App Version (Версия приложения). Возвращает версию приложения. Internet Explorer 4 для Windows 95 возвращает "4.0 (compatible; MSIE 4.01; Windows 95)". Следующие версии Internet Explorer и Windows могут возвращать другую строку.
UserAgent (Агент пользователя). Возвращает агента пользователя приложения. Internet Explorer 4 возвращает "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95).".
Предположим, подготовлена HTML-страница, которая может просматриваться любым броузером (обобщенная страница), и версия той же страницы, которая включает возможности, поддерживаемые только Internet Explorer 4. Можно легко обнаружить, какой броузер использует клиент, и если используется Internet Explorer 4 — отобразить усовершенствованную страницу, а для всех других броузеров — обобщенную HTML-страницу.
Чтобы определить значения различных свойств объекта
Navigator, необходимо запустить приложение HTMLEditor (описанное выше) и создать небольшой сценарий, подобный следующему.
SCRIPT LANGUAGE=VBScript>
Document.Write Window.Navigator.propName
Здесь
propName является фактическим именем свойства объекта Navigator. Запустите документ, и значение свойства появится в нижней части окна HTMLEditor.
Объект TableDef: определения таблиц
Объект TableDef задает определение таблиц в объекте Database. Все объекты TableDef формируют семейство. Число таблиц находится в свойстве TableDefs. Count.
Каждая таблица в базе данных задается объектом
TableDef. Перечислим его наиболее важные свойства.
• Count возвращает число строк в таблице.
• Fields - семейство объектов Field. Каждый объект Field задает поле в таблице.
• Indexes — семейство объектов Index. Каждый объект Index задает индекс таблицы.
Итак, объявим и откроем объект Database с помощью следующих команд.
Dim DB As Database
Set DB = OpenDatabase(dbName)
Для доступа к определениям таблиц базы данных используйте выражение DB.TableDefs, являющееся семейством объектов: по одному для каждой таблицы. С помощью элементов этого семейства можно обращаться к свойствам таблиц в базе данных. Чтобы реализовать обращение к каждой таблице самым простым способом, нужно объявить переменную TableDef
Dim tbl As TableDef
а затем просмотреть каждый элемент семейства
DB.TableDefs с помощью цикла For Each... Next.
For Each tbi In DB.TableDefs
Debug.Print tbl.Name
Next
Этот цикл отображает имена таблиц. В дополнение к таблицам данных базы данных Access содержат несколько системных таблиц. Имена этих таблиц начинаются с MSYS и их можно пропустить. Для получения подробной информации о том, как обнаружить и проигнорировать системные таблицы, смотрите параграф "VB6 в действии: проект DBStructure" далее в этой главе.
Индексы таблицы
Большинство таблиц в базе данных имеет хотя бы один связанный индексный файл, а иногда и больше. Для доступа к индексам таблицы предназначено свойство Indexes объекта TableDefs. Свойство Indexes - это семейство объектов, каждый из которых соответствует одному индексу таблицы. Чтобы самым простым способом реализовать обращение к каждому индексу в таблице, нужно объявить объект Index.
Dim idx As Index
а затем просмотреть каждый элемент семейства
Indexes с помощью цикла For Each...Next
For Each idx In tbi Indexes
Debug.Print idx.Name
Next
Элемент tbl — это объект TableDef, который объявлялся в предыдущем параграфе. Следующий вложенный цикл отображает имена всех таблиц в базе данных и имена их индексов под каждой таблицей.
For Each tbl In DB.TableDefs
Debug.Print tbl.Name
For Each idx In tbl.Indexes
Debug.Print idx.Name
Next idx
Next tbl
Можно запрашивать определение каждого индекса с помощью свойства Fields и использовать свойство Unique, чтобы определить, требует ли данный индекс уникальных ключей.
Поля таблицы
Наиболее важное свойство объекта TableDefs — свойство Fields (Поля), которое является семейством объектов, каждый из которых соответствует полю таблицы. Чтобы обратиться к полям таблицы, определите в базе данных нужную таблицу. Это делается с помощью индексного значения, которое равно 0 для первой таблицы, 1 — для второй и DB TableDefs Count-1 — для последней таблицы. К полям первой таблицы в базе можно обращаться с помощью объекта, приведенного ниже.
DB TableDefs (0) Fields
Вместо индекса можно использовать имя таблицы. Следующий объект задает все поля в таблице Titles базы данных BIBLIO/
DB.TableDefs ("Titles").Fields
Чтобы обратиться к каждому полю в семействе Fields, объявите объектную переменную Field и просмотрите семейство с помощью цикла For Each...Next. Следующий фрагмент кода отображает имена и типы каждого поля в первой таблице базы данных.
Dim fid As Field
For Each fld In DB.TableDefs(0).Fields
Debug.Print fld.Name, fld Type
Next
Свойство Type (Тип) возвращает целочисленное значение, которое представляет тип поля. Необходимо написать простую процедуру, которая преобразует этот номер в строку "Integer", "String" и т.п.
Другие свойства объекта Field приведены ниже.
• OrdinalPosition. Определяет порядок полей в таблице.
• AllowZeroLength. Булево свойство, указывающее, может ли поле содержать пустую строку.
• Size. Размер поля в байтах.
• Value. Текущее значение поля.
Объект
Extender
Объект Extender предоставляет некоторые основные свойства данного элемента управления, такие как Name, Width и Height. Эти свойства поддерживаются непосредственно операционной системой и при изменении их значения процедура Property Let не вызывается. Как известно, свойство Name элемента управления может быть изменено в любое время, если элемент управления используется в режиме конструирования, но процедура Property для этого свойства не существует. Можно выяснить, какое имя назначено пользователем элементу, вызвав свойство Name объекта Extender. Объект Extender является также шлюзом к некоторым
свойствам родительского элемента управления, на котором расположен данный элемент управления.
Свойство Name. Существует возможность выяснить имя контейнерного элемента управления и его размеры. Можно обратиться к объекту Extender, используя следующий вызов:
UserControl.Extender.extProperty
где
extProperty - имя свойства объекта Extender. Имя заказного элемента управления возвращается следующим ниже выражением.
UserControl.Extender.Name
Примечание
Но действительно ли нужно вызывать объект Extender для выяснения имени элемента управления в самом элементе управления? Не перестарались ли мы? Нет, элемент управления, на самом деле, не знает собственного имени! Пользователь может изменять свойство Name элемента управления в любое время в течение всего конструирования, а для того, чтобы прочитать имя элемента управления, необходимо действительно воспользоваться услугами объекта Extender. Для использования свойств такого типа нет необходимости в методах Property Get и Property Let.
Свойства Width и Height. Эти свойства возвращают размеры элемента управления. Используйте следующие ниже вызовы:
UserControl.Extender.Width
и
UserControl.Extender.Height
Свойства Tag и Index. Это еще два свойства, которые поддерживает Visual Basic. Они не являются свойствами объекта Extender (хотя синтаксис указывает на обратное). Это свойства специального элемента управления, к которым нельзя обратиться непосредственно. Код для поддержки этих свойств не был добавлен, но, тем не менее, они появляются в окне свойств элемента управления. Поскольку их значения поддерживаются самим Visual Basic, то доступ к ним можно получить только через объект Extender.
Ambient
Объект Ambient подобен объекту Extender в том смысле, что он предоставляет информацию об окружении элемента управления. И, фактически,'эти два объекта иногда перекрывают друг друга. Объект Ambient дает коду элемента управления информацию о цвете фона контейнера, шрифте и т.д. Единственное действительно важное свойство объекта Ambient — UserMode, которое указывает на то, действует ли элемент управления в режиме конструирования или в режиме выполнения программы.
Как известно из опыта работы с обычными элементами управления, все элементы управления VB функционируют в режимах конструирования и выполнения. Так как элемент управления ведет себя одинаково в обоих режимах, то нет необходимости различать их. При конструировании элементов управления ActiveX, однако, часто необходимо дифференцировать режимы работы в самом коде и реагировать на некоторые события по-разному, в зависимости от того, используется ли элемент управления в режиме конструирования или в режиме выполнения.
Свойство UserMode. Это свойство принимает значение True. когда элемент управления действует в режиме выполнения, или False, когда элемент управления действует в режиме конструирования. Для иллюстрации работы этого свойства попробуем отображать текст "Design Mode", когда элемент находится в режиме конструирования. Откройте код обработчика события Paint и вставьте следующие строки в конец кода.
Программа 16.9. Использование свойства UserMode
Private Sub UserControl_Paint()
DrawCaption
OldFontSize = UserControl.Font.Size
UserControl.Font.Size = 10
If Not Ambient.UserMode Then
UserControl.CurrentX = 0
UserControl.CurrentY = 0
UserControl.Print "Design Mode"
End If
UserControl.Font.Size = OldFontSize
End Sub
Эти операторы определяют, используется элемент управление в режиме конструирования или режиме выполнения. В режиме конструирования строка "Design
Mode" отображается в верхнем левом углу, как показано на рис. 16.8. В данном случае необходимы операторы, сохраняющие и восстанавливающие размер шрифта, в противном случае надпись "FLEXLabel Control" будет отображаться тем же маленьким шрифтом, что и строка "Design Mode", либо, наоборот, строка будет отображаться тем же большим шрифтом, что и надпись. Код устанавливает малый размер шрифта, отображает строку и восстанавливает исходный размер шрифта.
Database
В предыдущих параграфах рассматривалось содержимое базы данных. Обратим внимание на ее структуру. Даже если вы знакомы со структурой базы данных, в некоторых случаях может потребоваться определить характеристики таблиц из кода приложения. Например, понадобится информация о том, сколько полей содержит конкретная таблица или как определен индексный файл.
В приложении Database Structure (рис. 17.24) показаны объекты, описанные в этом параграфе. Сначала рассмотрим объекты, составляющие базу данных, а затем – реализацию приложения Database Structure.
Рис. 17.24. Приложение Database Structure отображает любую базу данных, созданную в Microsoft Access
Объектом верхнего уровня является объект Database, который задает базу данных. Чтобы создать объект Database и задать базу данных, объявите объектную переменную.
Dim DB As Database
Объект Database присваивается переменной DB с помощью функции OpenDatabase, которой в качестве параметра передается путь к существующей базе данных и которая возвращает объект Database.
Set DB = OpenDatabase(dbName)
Параметр
dbName — строка пути к базе данных — может быть свойством FileName элемента управления Common Dialogs. Все объекты, рассмотренные в следующих параграфах, являются свойствами объекта Database.
Каждая таблица в базе данных задается объектом
TableDef, а запрос — объектом QueryDef. Каждый из них имеет собственные свойства, подобные Name (имя таблицы или запроса) и Count (число таблиц в объекте TableDef или количество запросов в объекте QueryDef).
QueryDef: определения запросов
Кроме таблиц, база данных может содержать определения запросов. Запросы, которые обычно используются в базе данных, сохраняются в ней и вызываются по именам. Ко всем запросам в базе данных можно обращаться через объект QueryDefs, подобный объекту TableDef. Объект QueryDefs - это семейство объектов QueryDef, каждый из которых соответствует сохраненному запросу. Из программы можно обращаться к следующим свойствам семейства QueryDefs.
• Count. Возвращает число запросов, сохраненных в базе данных.
• Name. Возвращает имя запроса.
• SQL. Возвращает SQL-оператор запроса.
Число запросов, сохраненных в базе данных, можно получить с помощью следующего выражения.
DB.QueryDefs.Count
Чтобы обратиться ко всем запросам, сохраненным в базе данных, объявите объектную переменную QueryDef
Dim qry As QueryDef
а затем просмотрите элементы семейства QueryDefs с помощью цикла For Each...Next.
For Each qry In DB.QueryDefs
Debug.Print qry.Name
Next
VB6 в действии: проект DBStructure
Приложение DBStruct (см. рис. 17.24) позволяет открыть любую базу данных и просмотреть имена ее таблиц, их структуру, запросы, сохраненные в базе данных, и их определения. Таблицы и запросы базы данных отображаются в двух списках слева. Под именем каждой таблицы находятся названия ее индексов. Щелкните на имени таблицы, чтобы отобразить ее поля, или на имени запроса, чтобы отобразить его определение.
Начнем с кода кнопки Open Database.
Программа 17.14 . Кнопка Open Database
Private Sub Command1_C1ick()
On Error GoTo NoDatabase
CommonDialog1.CancelError = True
CommonDialog1.Filter = "Databases|* mdb"
CommonDialogI ShowOpen
' Открытие базы данных
If CommonDialog1.fileName <> " " Then
Set DB = OpenDatabase (CommonDialog1.filename)
Label1.Caption = CommonDialog1.filename
End If
' Очистка элементов управления ListBox
FIdList.Clear
TbiList.Clear
Dim tbl As TableDef
Dim idx As Index
Dim TName As String
File
Объект File задает файл и предоставляет свойства, задающие свойства реального файла, и методы, которые позволяют копировать, перемещать и удалять файлы.
Для создания объекта File и исследования его свойств, выполните следующие действия.
1 . Создайте переменную типа FileSystem Object, объявив ее следующим образом:
Dim FSys As New FileSystemObject
либо вызвав функцию CreateObject(), как показано ниже.
Set FSys = Create0b]ect ("Scripting. FileSystemObject")
2 . Используйте переменную FSys для создания объекта, задающего указанный файл.
Set file = FSys.GetFile(fileName)
3 . Обратимся к свойствам файла с помощью объектной переменной file.
FName = file.Name
FDate = file.DateCreated
FSize = file.Size
Рассмотрим свойства объекта File.
Свойства объекта File
Многие свойства объекта File аналогичны свойствам объекта Folder, который рассматривается в параграфе " Объект Folder" далее в этой главе.
Attributes. Это свойство используется для чтения и установки атрибутов файла. Для чтения используется следующий синтаксис.
thisFile.Attributes
Для установки необходимых атрибутов используйте такой оператор.
thisFile.Attributes = thisFile.Attributes Or new_attribute
Переменная
new_attribute
принимает любое значение, приведенное в табл. 20.2. Для изменения нескольких атрибутов комбинируйте значения с помощью логической операции ИЛИ. Например, следующий оператор
thisFile.Attributes = new_attribute
изменяет заданный атрибут, но при этом очищает все другие. Если файл имеет атрибуты "только для чтения" и "скрытый", то его свойство Attributes равно 3 (1+2 согласно табл. 20.2). Если установить атрибут "архивный", присвоив свойству Attributes значение 32, то другие два атрибута очистятся. Комбинируя новый атрибут (32) и существующие с помощью операции ИЛИ, можно задать файлу одновременно атрибуты "только для чтения", "скрытый" и "архивный".
Таблица 20.2. Допустимые значения переменной newattribute
Shell
Объект Shell — это свойство объекта Wscript, предоставляющее доступ к специальным компонентам (переменной среды и специальным папкам), а также к нескольким методам для работы с системным реестром. Рассмотрим свойства объекта Shell. Перед работой с этими свойствами необходимо создать экземпляр объекта.
Set wShell = Wscript.CreateObiect ("Wscript.Shell")
WshShortcut
Объект WshShortcut предоставляет ярлык и позволяет работать с существующими ярлыками и создавать новые. Для создания WshShortcut используются следующие операторы.
Set WShell = Wscript.CreateObject ("Wscript.Shell")
strDesktop = WShell.SpecialFolders ("Desktop")
Set aShortcut = WShell.CreateShortcut(strDesktop & _
"\Encrypt.lnk")
Если файл Encrypt.lnk существует, то переменная aShortcut
предоставляет ярлык на Рабочем столе. Если он не существует, то он будет создан.
Примечание
Новый ярлык не появится, пока он не будет сохранен методом Save.
Свойства объекта WshShortcut и его метод Save рассмотрены в следующих параграфах. Эти свойства соответствуют параметрам, которые устанавливаются на вкладке Shortcut диалогового окна свойств ярлыка (рис. 20.12).
Arguments. Задает аргументы, передаваемые ярлыку.
Description. Задает описание ярлыка.
FullName. Задает полный путь к ярлыку.
Рис. 20.12. Вкладка Shortcut окна Properties
Hotkey. Задает горячую клавишу, запускающую данную программу. Горячая клавиша состоит из модификатора и клавиши. Возможные модификаторы:
Чтобы назначить комбинацию клавиш для ярлыка, задаваемого переменной myShortCut, используется следующий оператор.
myShortCut.Hotkey =
"ALT+SHIFT+F"
IconLocation.
Задает место расположения значка для ярлыка. Обычно несколько значков хранятся в одном файле. Формат этого свойства имеет вид: Path,index.
C:\Program Files\NetMeeting\conf.exe 1
Для ярлыка NetMeeting используется первый значок из файла conf.exe.
TargetPath. Задает объект, на который ссылается ярлык.
WindowStyle. Задает стиль окна приложения, на которое указывает ярлык, после того, как приложение запущено. Стили перечислены в табл. 20.10.
Таблица 20.10. Возможные значения свойства WindowStyle
Значение
Описание
0
1
2
Нормальное
Минимизированное
Максимизированное
WorkingDirectory.
Задает рабочий каталог ярлыка.
Save. Сохраняет ярлык в файле, имя которого определяется свойством FullName.
WshNetwork
Объект WshNetwork предоставляет свойства и методы для работы с разделяемыми устройствами (дисками и принтерами) в сети, а также свойства локальных компьютеров (сетевые имена, имена доменов и т.п.). Информация об этом объекте содержится на http://www.microsoft.com.scripting.
Глава 21 . Visual Basic и Web
• Объекты для просмотра Web
• Элемент управления WebBrowser и объект InternetExplorer
• Использование гиперссылок в приложениях Visual Basic
• Модель написания сценария Internet Explorer
• Построение элементов управления для использования в Internet
Мы рассмотрели использование VBScript для написания сценария Web-страниц. В этой главе показано слияние рабочего стола и Web, приведены объекты и примеры. Первая рассматриваемая тема - элемент управления WebBrowser, который позволяет отображать HTML-документы в приложениях Visual Basic. При помощи этого элемента управления можно разработать форму для соединения пользователя с Web-узлом (или страницей) и воспроизведения домашней страницы, как с помощью Internet Explorer. Поскольку элемент управления WebBrowser не предусматривает никаких средств навигации, можно ограничить пользователя только собственным узлом (если он не содержит гиперссылки на другие узлы).
В корпоративной среде разрабатываются формы, отображающие объявления, специальные инструкции и все типы информации, которые часто изменяются. Пользователю не нужно запускать броузер для просмотра этой информации. Элемент управления WebBrowser позволяет пользователям получать информацию из приложений, которыми они пользуются ежедневно.
Элемент управления WebBrowser, как и Internet Explorer, может отображать HTML-страницы, заявленные заблаговременно и находящиеся на сервере (или жестком диске). Можно непосредственно манипулировать документом при помощи объектов Internet Explorer Scripting Object Model. С их помощью пишутся приложения Visual Basic, генерирующие код HTML и помещающие его на WebBrowser. Другими словами, возможна разработка приложений Visual Basic, которые генерируют HTML-документы "на лету" и отображают их при помощи элемента управления WebBrowser. Это очень удобно, особенно при разработке средств диалоговых консультаций.
Последняя тема этой главы — создание элемента управления
ActiveX для загрузки информации из Internet. Можно разработать элементы управления ActiveX, которые используют подсоединения к Internet для загрузки информации из сети. В этой главе показано, как это делается. Такие элементы управления называются Internet-enabled, и основной их функцией является подключение к серверу.
Примечание
Другая интересная тема — документы ActiveX. Они были введены с появлением VB5 и являются приложениями, которые могут выполняться в окне Internet Explorer. Документы ActiveX могут запускаться на выполнение дистанционно — через броузер. Но поскольку документы ActiveX — не самые распространенные приложения, разрабатываемые с использованием Visual Basic, эта тема в книге не рассматривается.
InternetExplorer
Объект InternetExplorer позволяет запустить экземпляр Internet Explorer из приложения и манипулировать им с помощью OLE. Он поддерживает те же свойства и методы, что и элемент управления WebBrowser, и имеет дополнительные возможности. Кратко рассмотрим свойства и методы этого объекта, но сначала создадим приложение, которое управляет InternetExplorer. (IExplore на компакт-диске).
Рис. 21.2. Страница Calendar.htm, открытая приложением Browser
VB6 в действии: проект Explore
Чтобы установить ссылку на Internet Explorer из проекта, добавьте ссылку на объект InternetExplorer Для этого выполните следующие действия.
1 . Откройте новый проект, выбрав тип проекта Standard EXE
2 . Выберите команду References (Ссылки) меню Project (Проект), чтобы открыть диалоговое окно References.
3 . Установите флажок Microsoft Internet Controls.
Новый значок на панели элементов управления не появится. Но если открыть окно Object Browser, то можно обнаружить, что класс Internet Explorer был добавлен к проекту. В окне Members будут видны свойства и методы класса IntemetExplorer. С их помощью можно управлять Internet Explorer посредством OLE.
Построим приложение, управляющее одним или несколькими экземплярами IntemetExplorer (рис. 21.3). Пользователь может выбрать адрес из элемента управления ComboBox в окне Visual Basic и щелкнуть на кнопке Show URL, чтобы запустить экземпляр Internet Explorer, в котором воспроизводится выбранный пользователем URL.
Рис. 21.3. Использование приложения IExplore для управления Internet Explorer
Далее выполните следующие действия.
4 . Создайте форму, подобную показанной на рис. 21.3.
5 . Объявите переменную, которая обращается к элементам класса IntemetExplorer.
Dim IE As New IntemetExplorer
6 . Добавьте следующий код инициализации в событие, обрабатываемое при загрузке формы.
Private Sub Form_Load()
List1.AddItem "microsoft"
List1.AddItem "sybex"
List1.AddItem "infoseek"
List1.AddItem "realaudio"
Response
Этот объект используется для пересылки информации клиенту. ASP-файлы могут содержать HTML-код, который просто пересылается клиенту. Если возникает необходимость управлять потоком вывода из программы, то используется метод Write объекта Response. Он поддерживает следующие методы и свойства.
Метод Write
Все то, что записано в объект Response с помощью метода Write, пересылается клиенту. Информация, записываемая с помощью метода Write, является HTML-документом (как и при использовании одноименного метода объекта Document). Приведем пример использования метода Write.
Программа 22.4. Использование метода Response.Write
Внешние теги определяют границы ASP-файла (в данном случае они необязательны), а теги, записанные в объект Response, ограничивают HTML-файл, который виден на экране клиента. Если существует метод, используемый едва ли Не в каждом ASP-файле, то это метод Response.Write. Примеры данной главы не являются исключением из правил.
Метод Write объекта Response является основным способом пересылки данных клиенту. Программа 22.4 достаточно тривиальна. Этот же результат можно было получить непосредственным использованием HTML-тегов или метода Write объекта Document.
Метод Redirect
Этот метод переадресует клиента на другой URL. Если URL вашего узла изменился, то напишите небольшое ASP-приложение для автоматической переадресации клиентов на новый URL.
<%
Response.Write "Our site was moved at a new URL."
Request
Для взаимодействия с пользователем сценарий должен запрашивать информацию, вводимую пользователем в форму, и читать значения из
cookies. Появление ASP позволило упростить процесс чтения данных, поставляемых клиентом, путем инкапсуляции всей совокупности сложных процедур в несколько свойств объекта Request. Этот объект - один из основных инструментов построения серверных сценариев Объект Request обладает пятью свойствами, и все они являются семействами.
QueryString.
Содержит значения, переданные серверу методом GET.
Form. Содержит все формы на странице.
Cookies. Содержит все cookie, записанные на клиентский компьютер Web-узлом.
ServerVariables.
Содержит все HTTP-переменные, определенные сервером
ClientCertificate.
Содержит все сертификаты клиента.
Семейство QueryString
Это семейство, наиболее часто используемое при разработке ASP-приложений Оно предоставляет доступ ко всем параметрам, переданным клиентом вместе с URL Если имена параметров на этапе разработки приложения известны, то их значения можно получить следующим образом.
reqProdName = Request.QueryString ("ProductName")
Если имена параметров на этапе разработки ASP-файла не известны или их нужно обрабатывать последовательно, то воспользуйтесь следующим циклом.
Set Params = Request.QueryString
For Each param in Params
{обработка параметра param}
Next
На рис. 22.5 показана простая HTML-страница (страница SRVRFORM.HTM в папке этой главы на компакт-диске) с единственной формой, посредством которой пользователь вводит информацию, выбирая требуемые пункты в списках.
Рис. 22.5. Типичная форма HTML-страницы
Элементы ListBox на форме имеют следующие имена: HardDisc, Memory, CD, Speaker и Software. Их возможные значения перечислены в тегах для каждого тега . Варианты выбора объема оперативной памяти (Select Memory) представлены значениями 32, 64, 128 и 256. Параметр запроса Memory имеет одно из этих значении, выбранных на форме.
Программа 22.5. Файл SRVRFORM.HTM
Server
Объект Server управляет средой, в которой выполняется серверный сценарий. Наиболее важным членом этого объекта является метод CreateObject, создающий новый экземпляр объекта зарегистрированного класса.
Метод CreateObject
Этот метод идентичен одноименной функции Visual Basic. В качестве аргумента он принимает реестровый идентификатор (Class ID) объекта и возвращает его экземпляр. Метод имеет следующий синтаксис.
Server. CreateObject ("progID")
Для получения доступа к базе данных с помощью ADO-компонента необходимо сначала создать объекты Connection и Recordset с использованием следующих операторов (подробная информация приведена в параграфе "Использование ADO").
Set ADOConnection = Server.CreateObject ("ADODB.Connection")
Set ADORS = Server.CreateObject ("ADODB.Recordset")
Аналогично, необходимо создавать объектные переменные для доступа к другим базовым компонентам ASP, например, File Access или Adviertisement Rotator. Объектные переменные следует создавать для доступа к компонентам ActiveX, разработанным вами. В параграфе " Использование ADO" можно узнать, как установить связь с базой данных, используя объектные переменные. В параграфе "Взаимодействие с компонентами ActiveX" в конце этой главы рассмотрено, как создать объектную переменную для взаимодействия с пользовательскими компонентами ActiveX, работающими на сервере.
Метод MapPath
Это еще один широко используемый метод объекта
Server, который устанавливает соответствие между виртуальными папками и действительными путями на диске. Он чрезвычайно полезен при разработке серверных сценариев: все файлы, с которыми работает сценарий, расположены в виртуальных паПках. Можно реорганизовать структуру папок на Web-узле, затем переименовать несколько виртуальных папок, и ваши сценарии будут работать. Однако бывают случаи, когда требуется знать полный путь к файлу, а получить его можно с помощью метода MapPath.
Объектная модель
ADO
Объектная модель ADO проще DAO, несмотря на то, что она поддерживает больше типов баз данных и предоставляет больше возможностей программисту. Модель ADO состоит из трех объектов:
Connection (Подключение).
Это объект высшего уровня, предоставляющий подключение к источнику данных. Обычно сначала выполняется подключение к источнику данных, а затем (для получения требуемых записей из базы данных или ее изменения) выполняются команды, использующие объект Connection. Однако подключение можно выполнить и в момент создания объекта RecordSet. Объект ADO Connection программируется аналогично объекту Connection конструктора DataEnvironment.
Command (Действие).
Этот объект представляет собой SQL-выражение или сохраненную процедуру, обрабатываемую свойством Data Source. Объект Command может не вернуть результат (если он предназначен для внесения изменений в базу данных) или вернуть RecordSet с требуемыми записями. Для установки объекта Command необходимо задать SQL-выражение или сохраненную процедуру и их параметры (если нужно). Параметры добавляются к семейству параметров (Parameters Collection) объекта Command. Затем можно вызвать метод Execute (Выполнить), чтобы выполнить SQL-выражение или сохраненную процедуру свойства Data Source. Другая возможность состоит в создании объекта RecordSet с последующим связыванием его с объектом Command. С точки зрения программирования объект ADO Command эквивалентен объекту Command конструктора DataEnvironment.
RecordSet (Набор записей).
Этот объект содержит результаты действия объекта Command при работе с базой данных (при условии, что действие возвращает записи). Объект RecordSet можно создать без явного подключения (достаточно передать строку подключения, определяющую Data Source, методу Open объекта RecordSet). Для доступа к полям объекта RecordSet используется его свойство Fields collection (Семейство Fields). Объект ADO RecordSet представляет такие же записи, которые возвращаются конструктором DataEnvironment, с той лишь разницей, что к ним можно получить доступ из кода, а не перетаскивать их на форму.
Объекты активного сервера
HTML является языком для отображения информации на экране клиента. Он позволяет сделать Web-страницы не только красочными, но и интерактивными. Но HTML создавался не как язык программирования и, несмотря на все последующие доработки, так им и не стал.
Для разработки интерактивных страниц необходим инструмент программирования. Эту роль мог бы играть VBScript (или иной язык написания сценариев), но у него есть очень серьезные ограничения. Язык для написания клиентских сценариев должен быть настолько безопасным, что выполнение этого требования существенно уменьшает его возможности. Выход можно найти в перенесении большей части нагрузки на сервер. Инструментальным языком при этом остается VBScript, однако, если программа выполняется на сервере, VBScript получает доступ ко всем объектам на сервере. Это значит, что на сервере VBScript во многом подобен Visual Basic, а серверный сценарий напоминает VB-программу.
Большой интерес представляют вопросы организации доступа к базам данных, расположенных на сервере, со стороны клиента. Простейшим способом доступа к базам данных с помощью ASP является использование компонента
Database, основанного на объекте Active Data Objects (ADO). ADO инсталируется вместе с ASP и его можно использовать в ASP-страницах для доступа к базам данных (см. гл. 18). Компонент ADO обеспечивает эффективный доступ к базам, совместимым с протоколом ODBC или OLE DB. Таким образом, можно использовать ADO в клиентских сценариях (при условии, что этот компонент установлен на компьютере-клиенте) для организации Web-интерфейса, позволяющего получить доступ к корпоративным базам данных без разработки дополнительного серверного сценария.
ASP подчиняются парадигме разработки на основе компонентов. Это означает, что все функциональные возможности для разработки Web-узла обеспечиваются объектами, принадлежащими одной из двух категорий:
• встроенные;
• базовые (или основные).
Встроенные объекты предоставляют методы и свойства для доступа к деталям поступающих запросов (например, к параметрам запроса) и генерирования результатов, возвращаемых клиенту. Базовые объекты обеспечивают функциональные возможности, не являющиеся обязательными, но широко используемые в Web-разработках. Примеры базовых объектов - ADO для доступа к базам данных и компонент файловой системы, используемый при чтении и записи в файлы на сервере. В следующих двух параграфах рассмотрены эти объекты и примеры их использования в Web-разработках.
Объекты для просмотра
Web
Чтобы использовать методы Web и документы с гиперссылками в приложениях Visual Basic необходимы два объекта:
• элемент управления WebBrowser;
•
объект InternetExplorer.
WebBrowser — это элемент управления ActiveX, который отображает HTML-документы в формах Visual Basic. InternetExplorer — это объект автоматизации OLE, использующийся для управления Microsoft Internet Explorer (и элементом управления WebBrowser) из программы. Эти два объекта имеют много общего, поэтому рассматриваются в одном параграфе. Основное внимание уделено элементу WebBrowser.
Объекты, которые представляют текст
Базовым объектом для доступа к тексту в документах Word является объект Range,
который представляет собой непрерывный сегмент текста. Чтобы извлечь некоторый текст из документа, можно воспользоваться методом Range объекта Document, который принимает в качестве параметров позиции начального и конечного символов в тексте. Синтаксически это выглядит так:
Document.Range(start, end)
Параметры start и end — два числовых значения. Непривычным является то, что первый символ документа имеет номер 0. Следующий оператор позволяет извлечь первые 100 символов документа, представленного объектной переменной Document.
Range 1 = Document.Range (0, 99)
Эти символы присваиваются объектной переменной Range). Переменная Range 1 может быть объявлена как вариантная, но ее также можно объявить как переменную типа Range:
Dim Range 1 As Range
В приведенных операторах перед использованием переменной Document ее необходимо установить, чтобы затем можно было сослаться на существующий объект:
Set Documenti = Documents(1)
Переменная
Document1 может быть объявлена как вариантная, но ее также можно объявить как переменную типа Document:
Dim Documenti As Document
Также можно заменить переменную Document1 на встроенный объект ActiveDocument,
который представляет активный документ. К выделенному тексту в активном документе можно обращаться, воспользовавшись следующим выражением:
Application.ActiveDocument.Selection
Слова, предложения и абзацы являются более значимыми элементами текста, нежели символы. Соответственно, объекты Word, Sentence и Paragraph более подходят для работы с текстом и, обычно, именно они используются при обращении к документам. Но эти объекты не поддерживают все свойства объекта Range. Впрочем, все эти элементы текста могут быть преобразованы в объект Range, обладающий свойством Range. Например, следующее выражение возвращает третий абзац в указанном документе как объект Range:
Document1.Paragraphs(3).Range
После этого можно обратиться к свойствам объекта
Range, чтобы обработать третий абзац.
Однако объект Paragraph не обладает ни свойством Font, ни методом Select. Чтобы изменить вид третьего абзаца в документе, необходимо сначала преобразовать абзац в объект Range:
Set Rangel = Documenti.Paragraphs (3).Range
Rangel.Font.Bold = True
Document1 — правильно объявленная переменная типа Document, a Rangel — правильно объявленная переменная типа Range. Впрочем, можно объединить оба оператора в один и избежать, тем самым, необходимости создания объектной переменной Rangel:
Document1.Paragraphs(3).Range.Font.Bold = True
С помощью приведенного ниже оператора можно выделить тот же параграф:
Document.Paragraphs(3).Range.Select
Как только абзац (или любой другой фрагмент текста) выделен, к нему можно применить все средства обработки (например, редактировать, перемещать в другое место, форматировать).
Наиболее часто используются два метода объекта Range: InsertAfter, с помощью которого можно вставить строку текста после указанного объекта Range, и InsertBefore, с помощью которого можно вставить строку текста перед указанным объектом Range. Следующие операторы позволяют вставить заголовок в начало документа и заключительный абзац в конец:
AppWord.ActiveDocument.Select
AppWord.ActiveDocument.Range.InsertBefore _
"This is the document's title"
'(Это заголовок документа)
AppWord.ActiveDocument.Range.InsertAfter
"This is the closing paragraph"
'(Это заключительный абзац)
С помощью метода Select
в объекте ActiveDocument можно выделить текст целиком. Преобразовав после этого выделенный текст в объект типа Range, можно применить к нему методы, присущие объекту соответствующего типа. Методы InsertBefore и InsertAfter позволяют поместить некоторый текст перед и после объекта Range.
VB6 в действии: проект WordVBA
Располагая информацией о методах и объектах, можно разработать программу, которая сможет открыть документ, поместить в него некоторый текст, форматировать
его, а затем сохранить в файле на диске. Начать следует с создания экземпляра Word и установления связи с ним. В этом проекте демонстрируются возможности:
• создания нового документа;
• вставки текста и его форматирования,
• подсчета количества абзацев, слов и символов в новом документе и вывода полученных результатов в окно сообщений (рис. 14.14).
Эти действия выполняются непосредственно из приложения Visual Basic, в то время как Word работает в фоновом режиме. Пользователь не видит окно Word (даже в виде значка на панели задач). Новый документ сохраняется в файле C:\SAMPLE.DOC, и позже его можно будет открыть в Word для редактирования.
Рис. 14.14. В проекте WordVBA демонстрируется создание и обработку DOC-файла из приложения Visual Basic.
Программа, обслуживающая кнопку Create DOC file, проста. Для работы с текстом используется свойство Paragraph объекта Document, чтобы управлять текстом (можно вставлять новые абзацы и работать с ними). Следует обратить внимание на то, как выполняется выравнивание первого абзаца текста с помощью свойства Alignment объекта Paragraph.
Программа 14.10. Кнопка Create DOC file
Private Sub Commandl_Click()
Dim thisDoc As Document
Dim thisRange As Range
Dim prnTime As Date
Dim breakLoop As Boolean
Me.Caption = "Creating document..."
' (Создание документа...)
Set thisDoc = WordApp.Documents.Add
thisDoc.Range.InsertBefore "Document Title" & vbCrLf & vbCrLf
' (Заголовок документа...)
Set thisRange = thisDoc.Paragraphs(1).Range
thisRange.Font.Bold = True
thisRange.Font.Size = 14
thisRange.ParagraphFormat.Alignment = wdAlignParagraphCenter
thisRange.InsertAfter "This sample document was created _
automatically with a Visual Basic application." _
& vbCrLf
' (Этот образец документа был создан
' автоматически приложением Visual Basic...)
thisRange.InsertAfter "You can enter additional text here" _
SvbCrLf
' (Сюда можно ввести текст...)
thisRange.InsertAfter vbCrLf & vbCrLf
thisRange.InsertAfter "This project was created for _
Mastering VB6"
' (Этот проект был создан для книги по VB6)
thisRange.InsertAfter "(Sybex, 1999) and was tested with _
Word 97 "
' ( (изд-ва Sybex, 1999) и был испытан с
' помощью Word 97.)
thisRange.InsertAfter vbCrLf
thisRange.InsertAfter "Your text follow"
' (Далее следует ваш текст)
thisRange InsertAfter Textl.Text
Me.Caption = "Saving document... " ' (Сохранение документа...) thisDoc.SaveAs "c:\sample.doc"
Me Caption = "Printing document..." ' (Печать документа...)
thisDoc.Printout True, True
prnTime = Time
breakLoop = False
While WordApp.BackgroundPrintingStatus <> 0 And Not breakLoop
If Minute(Time - prnTime) > 1 Then
Reply = MsgBox (" Word is taking too long to print." _
vbCrLf & "Do you want to quif" , vbYesNo)
'(Документ печатается слишком долго.. Будете ждать?)
If Reply = vbYes Then
breakLoop = True
Else
prnTime = Time
End If
End If
Wend
WordApp.Quit
MsgBox "Document saved and printed!"
' (Документ сохранен и распечатан!)
Command2.Enabled = True
Command3.Enabled = True
Me Caption = "Word VBA Demo"
End Sub
Кнопка Massage DOC File позволяет продемонстрировать работу с текстом в документе Word с помощью автоматизации OLE. Первоначальный текст содержит множество ненужных пробелов между словами. Чтобы заменить эти пробелы на одиночные (типичная задача при редактировании), можно воспользоваться диалоговым окном Find & Replace (Поиск и замена). Приложение WordVBA выполняет эту операцию, вызывая метод Find.
Для обращения к методу Find требуется указать множество параметров, большая часть которых является необязательными. Для приложения WordVBA необходимо определить строку, которую следует найти, и строку, на которую ее следует заменить. Поэтому надо указать, что программа должна отыскивать два последовательно расположенных пробела и заменять их одним пробелом. Но на этом процесс не закончится, поскольку в документе могут содержаться три последовательно расположенных пробела, а в результате выполнения указанной процедуры их количество будет уменьшено до двух. Поэтому операция Find & Replace (Поиск и замена) должна быть выполнена еще раз. Как только программа отыщет два последовательно расположенных пробела, операция замены будет выполнена еще раз.Программа 14.11. Обработка документа
Word
Private Sub Command2 Click ()
Dim thisDoc As Document
Dim thisRange As Range
WordApp.Documents.Open ("c:\sample doc")
WordApp.Visible = False
Set thisDoc = WordApp.ActiveDocument
thisDoc.Content.Find.Execute FindText:="VB5", _
ReplaceWith:="VB6", Replace:=wdReplaceAll
While thisDoc.Content.Find.Execute(FindText:= " ", _
Wrap:=wdFindContinue)
thisDoc.Content.Find.Execute FindText:= " ", _
ReplaceWith:= " ", Replace:= wdReplaceAll, _
Wrap:=wdFindContinue
Wend
End Sub
Объекты
IE Scripting Object Model
Scripting Model - это иерархия объектов, с помощью которых можно получить доступ к свойствам HTML-документов, отображаемых в окне броузера, и к свойствам самого броузера. Эта модель напоминает организацию объектов в СУБД Access (см. гл. 17 — там рассматривалась иерархическая организация объектов, начинающихся с объекта Database). В Scripting Model каждый объект имеет свойства, являющиеся самостоятельными объектами, которые имеют собственные свойства (некоторые из них также являются объектами), методы и события.
Верхний объект в Scripting Model — Window. Документ отображается внутри этого объекта. Основные свойства объекта Window: его имя (свойство Name) и место расположения отображаемого документа (свойство URL). Прежде рассмотрим объекты Scripting Model в целом и узнаем, что они выполняют для Web-страниц.
Наиболее важное свойство объекта Window — объект Document. Объект Document — это HTML-документ, отображаемый в окне, которое имеет собственные атрибуты (фоновый цвет, строку заголовка и т.д.). Окно может содержать фреймы, которые могут содержать документы. Чтобы обратиться к документу во фрейме, сначала обращаются к соответствующему фрейм-объекту, а затем - к объекту-документу этого фрейма.
Session и Application
Объект Session (Сеанс) поддерживает переменные, относящиеся к конкретному сеансу взаимодействия клиент-сервер. Перед ознакомлением с членами этого объекта и способами его применения для построения ASP-приложений рассмотрим, как ASP-компоненты поддерживают сеанс в условиях протокола без сохранения предыстории.
Мы уже знаем, что HTTP является протоколом, не сохраняющим предысторию. Когда клиент запрашивает новый документ, инициируется новый процесс обмена. Каким же образом ASP знает, что новый запрос принадлежит существующему сеансу обмена? Ответ прост — ASP использует cookies (заготовки).
Когда клиент подсоединяется в первый раз, сервер посылает cookie с именем ASPSESSIONID, который запоминается на клиентском компьютере. При всех последующих обращениях к серверу ASPSESSIONID пересылается вместе с заголовком запроса.
Примечание
Заголовок содержит информацию, необходимую для взаимодействия обоим компьютерам. Вопросы, касающиеся подробностей структуры заголовка, выходят за пределы этой книги.
ASP обрабатывает этот
cookie для восстановления значений переменных, сохраненных ранее в объекте Session. Время действия ASPSESSIONID истекает по окончании сеанса связи. Когда этот же клиент подсоединяется к серверу следующий раз, пересылается новый cookie и создается новый сеанс. Для сохранения информации между сеансами следует сохранить cookie, время действия которого истекло, чтобы при следующем подключении клиента к серверу можно было прочесть его и использовать в качестве ключа для поиска требуемой информации (права доступа и т.п.).
Примечание
Некоторые броузеры не поддерживают cookie (хотя бывает это очень редко). Такие броузеры не поддерживают также объект Session. Это — единственное ограничение на использование ASP.
Объект Application (Приложение) подобен Session с той лишь разницей, что он поддерживает переменные, относящиеся не к отдельному сеансу, а к приложению. Простейшими примерами его использования являются вывод приветственного сообщения в окне клиента и счетчика пользователей. Все, что нужно для реализации счетчика пользователей, это ввести переменную, областью видимости которой является приложение, и увеличивать ее значение на 1 при посещении исходной страницы (являющейся ASP-документом) вашего приложения.
Объявление 32-разрядных функций и структур
В некоторых API-функциях в качестве параметров используются структуры. В приложении MousePos (папка MousePos данной главы на компакт-диске) приводится пример объявления и использования простой структуры. В этом приложении для получения информации о положении мыши в момент выполнения щелчка используется функция GetCursorPosQ. Эта функция должна возвратить вызвавшей ее программе два значения: координаты Х и Y мыши. Эти значения хранятся в структуре POINTAPI, которая состоит из двух элементов - Х и Y. Доступ к ним можно получить из программы с помощью выражений PointAPl.X и PointAPl.Y.
Чтобы создать проект MousePos, выполните следующие действия:
1 . Откройте окно API Viewer, выбрав команду API Viewer в меню Add-Ins.
2 . В открывшемся окне в меню File (Файл) выберите команду Load Text File (Загрузить текстовый файл).
3 . Выберите файл Win32api.txt и выполните двойной щелчок на элементе GetCursorPos в списке Available Items (Доступные объекты).
4 . В окне списка Selected Items (Выделенные объекты) появится следующее объявление:
Declare Function GetCursorPos Lib "user32" _
Alias "GetCursorPos" (IpPoint As POINTAPI) As Long
Параметр, необходимый для вызова функции - это структура данных, называемая POINTAPI. Она хранит координаты точки экрана. Чтобы найти определение структуры данных POINTAPI с помощью API Viewer выполните следующие действия:
5 . В раскрывающемся списке API Type (API-типы) выберите Types (Типы). Список Available Items (Доступные объекты) будет содержать названия всех структур данных, используемых API-функциями.
6 . Найдите структуру данных POINTAPI и выполните двойной щелчок на ее названии. В окне списка Selected Items (Выделенные объекты) появится ее определение.
Type POINTAPI
х As Long
у As Long
End Type
7 . Щелкните на кнопке Сору, чтобы скопировать это определение в буфер обмена (вместе с объявлением функции GetCursorPos()).
Совет
Объявления функций можно помещать в любом месте, но обычно их помещают в Module (Модуль): тогда другие процедуры смогут получить к ним доступ.
Обновление изображения
Теперь можно написать код, который обновляет изображение и вызывает событие TimeOut. Код, который будет написан в этом разделе, не имеет никакого отношения к конструированию элемента управления ActiveX. Этот код необходим при реализации таймера как самостоятельного приложения.
Совет
Если вы еще не совсем привыкли к среде конструирования ActiveX, то можно разработать обычное приложение, которое делает то же самое (то есть отсчитывает время, показывает прошедшее или оставшееся время на элементе управления Label, и обнаруживает, когда подходит время сигнала). Затем можно скопировать необходимые процедуры и вставить их в окне проекта ActiveX.
Теперь напишем код для происходящего каждую секунду события Timer элемента управления Timer. Для этого следует установить свойство Interval элемента управления Timer равным 1000. В обработчике события Timer элемента управления Timer следует обновить изображение и проверить, не нужно ли выключить сигнал.
Программа 16.16. Событие Timer элемента управления Alarm
Private Sub Timerl_Timer()
Dim TimeDiff As Date
Dim StopNow As Boolean
If Time - m_AlarmTime > 0 Then
If NextDay = False Then
StopNow = True
Else
TimeDiff = 24 - Time + m_AlarmTime
End If
Else
If NextDay = True Then
StopNow = True
Else
TimeDiff = m_AlarmTime - Time
End If
End If
If m_CountDown Then
Label1.Caption = Format$(Hour(TimeDiff) & ":" & _
Minute(TimeDiff) & ":" & Second(TimeDiff), "hh:mm:ss")
Else
Label1.Caption = Format(Hour(Time - startTime) & ":" & _
Minute(Time - startTime) & ":" & _
SecondfTime - startTime), "hh:mm:ss")
End If
If StopNow Then
Timeri.Enabled = False
RaiseEvent TimeOut
End If
End Sub
Способ остановки таймера и вызова события TimeOut зависит от того, настроен ли элемент управления для обратного отсчета. При обратном отсчете он отображает оставшееся время, а при прямом отсчете он отображает время, прошедшее с момента запуска таймера (переменная startTime
устанавливается методом StartTimer). Когда достигается значение AlarmTime, таймер останавливается. Это условие в коде проверяется последней If-структурой. Переменная NextDay устанавливается в методе StartTimer. Когда подходит время подачи сигнала, переменная NextDay изменяет свое значение, и это событие сообщает о том, что сигнал включен.
Можно предположить, что момент для инициирования события TimeOut может быть вычислен путем сравнивания AlarmTime с текущим временем:
If Time = AlarmTime Then
Timeri.Enabled = False
RaiseEvent TimeOut
End If
Но этот код никогда не будет работать. Если компьютер слишком занят в момент, когда подходит время сигнала (например, запуск другого приложения или проверка жесткого диска), событие Timer для последней секунды может быть не вызвано. Если это событие было пропущено, нужно будет ждать 24 часа, прежде чем подойдет время следующего сигнала (и потом он снова может не сработать!). Реализация, которая выполнена в нашем примере, включит сигнал, если даже это произойдет на секунду или две позже.
Посмотрите, насколько просто генерируются собственные события. Просто необходимо вызвать метод RaiseEvent из собственного кода, и Visual Basic поймет, что о событии сообщено основному приложению. В приложении любое условие в любое время может инициировать событие. Кроме того, в начале кода наряду с объявлением переменных нужно добавить объявление события TimeOut.
Event TimeOut()
Откройте проект Alarm и исследуйте код объекта UserControl вместе с кодом тестового проекта. Код очень простой, именно поэтому он был выбран для реализации вручную. Естественно, проще реализовать пользовательские элементы управления с помощью мастера интерфейса элемента управления ActiveX, но важно понять, что происходит и что мастер делает автоматически.
Обработка ошибок класса
Класс AXStat содержит программный код, который может инициировать ошибки из кода класса. Если говорить о данном приложении, эти ошибки идентичны ошибкам, которые генерируются Visual Basic, и они могут быть перехвачены. Если, например, пользователь пытается получить доступ к несуществующему элементу (индекс которого больше свойства Count), то класс генерирует ошибку. Класс может обрабатывать ошибку, выдавая соответствующее сообщение, но это не лучший способ обработки ошибок, которые возникают в классах. Разумнее инициировать ошибку и позволить приложению ее обработать.
Для генерирования ошибки исполнения в классе (или в управляющем элементе ActiveX, как это можно увидеть в следующей главе) необходимо воспользоваться методом Raise
объекта Err. Номер ошибки может быть любым целым значением, но следует убедиться в том, что оно не конфликтует с номерами ошибок Visual Basic. Диапазон от 0 до 512 зарезервирован для Visual Basic и не стоит использовать номера из этого диапазона. Можно использовать любой другой номер ошибки, но рекомендуется использовать малые значения и прибавлять к ним константу vbErrorObject. Например, если класс может определять 8 типов ошибок, то можно назначить им номера от 1 до 8 и прибавить к ним константу vbErrorObject.
Если другой элемент управления использует такие же номера ошибок, то можно выяснить, каким элементом управления сгенерирована ошибка, исследуя свойство Source объекта Err. Для выяснения действительного номера ошибки приложение может вычесть эту же константу из значения Err.Number.
Совет
Интересным свойством константы vbErrorObject
является то, что ее значение — очень большое отрицательное число (-2147221504). Таким образом, все номера ошибок, возвращаемые пользовательскими классами, будут отрицательными числами и их очень легко отличить от стандартных ошибок Visual Basic.
Две кнопки с правой стороны тестовой формы генерируют ошибки исполнения, вызывая члены класса AXStat с некорректными аргументами. Следующий программный код показывает, как они вызывают методы Item и Remove с соответствующим кодом, перехватывающим ошибки.
Программа 15.16. Обработка ошибок сгенерированных классом AXStat
Private Sub Command5_Click()
On Error Resume Next
STATS.Remove 9999
If Err.Number <> 0 Then
MsgBox "ERROR # " & Err.Number - vbObjectError _
& vbCrLf & Err.Description & vbCrLf & "In " & Err.Source
' (Ошибка №... в...)
End If
End Sub
Private Sub Command6_Click ()
On Error Resume Next
STATS.Item 9999
If Err.Number <> 0 Then
MsgBox "ERROR #" & Err.Number - vbObjectError _
& vbCrLf & Err.Description & vbCrLf & "In " & Err.Source
' (Ошибка N". . . в. . . )
End If
End Sub
Номер ошибки и ее источник устанавливаются в программном коде класса, методом Raise объекта Err, как показано ранее. Для определения действительного номера ошибки, сгенерированной классом, вычтите константу vbErrorObject
из значения Err.Number. Еще лучше, объявить несколько констант в коде, которые соответствуют значениям ошибок. Ниже приведен перечислимый тип с ошибками, которые генерируются классом AXStats:
Public Enum AXStatErrors
AddError = 1
RemoveError = 2
End Enum
Константы значений ошибок появятся в броузере объектов под классом AXStatsErrors, и их можно использовать в коде приложения в виде выражений AXStatErrors.AddError и AXStatErrors. Remove Error.
Запустите приложение и щелкните на одной из двух кнопок справа на форме. Обе кнопки вызовут ошибку исполнения, пытаясь получить доступ к элементу с индексом 9999. Приложение остановится и выдаст сообщение об ошибке. Почему тестовый проект не перехватил ошибку исполнения с помощью его собственной подпрограммы обработки ошибок?
Ответ прост. По умолчанию Visual Basic в режиме конструирования останавливается в месте возникновения ошибки. Поэтому можно видеть строку, которая вызвала ошибку и исправить соответствующую процедуру в модуле класса. Если создать исполняемый файл и запустить его вне среды разработки, ошибка исполнения будет перехвачена работающим приложением. Можно также изменить поведение механизма перехвата ошибок Visual Basic в процессе конструирования. Откройте меню Tools и выберите команду Options. В диалоговом окне Options, которое появится на экране, выберите вкладку General, как показано на рис. 15.8.
В секции Error Trapping ( Перехват ошибок) вкладки General опция Break in Class Module (Останов в модуле класса) выбрана по умолчанию. Вот почему Visual Basic прерывает выполнение как только возникает ошибка и тестовый проект не имеет шанса обработать ее с помощью собственного обработчика ошибок. Выберите опцию Break on Unhandled Errors (Останов на необработанных ошибках) (как показано на рис. 15.8), закройте диалоговое окно Options и запустите тестовый проект снова. Щелкните кнопку Remove Error или Item Error - на этот раз проект не завершится ошибкой исполнения. Вместо этого появится диалоговое окно с сообщением об ошибке подобное, изображенному на рис. 15.9.
Рис. 15.8. Изменение поведения механизма перехвата ошибок, заданного по умолчанию, во время конструирования.
Рис. 15.9. Перехват ошибок исполнения, генерируемых классом AXStats
Обработка ошибок
Элемент управления Script имеет событие Error, вызываемое в случаях возникновения ошибки. Ошибку может вызвать элемент управления (вызов метода с неправильным аргументом или попытка установить несуществующее свойство) или сам сценарий Она может генерироваться в основном приложении, но не раньше, чем пользователю предложат воспользоваться Script Debugger. Пока разрабатываются и тестируются сценарии, можно позволить Visual Basic запустить отладчик и помочь в отладке. Завершенное приложение не должно выдавать подобных сообщений.
Может показаться, что нынешняя версия элемента управления не позволяет подавлять диалоговое окно, что делает затруднительным распространение приложений. Пользователи могут не иметь инсталированного Script Debugger, и эти сообщения приведут к путанице. Нынешний элемент управления Script далек от совершенства, но, возможно, следующая версия будет более гибкой или будет иметь редактор кода программы.
Необходимо мириться с ограничениями и недостатками элемента управления Script. Для обработки ошибок используйте объект Error, который является свойством элемента управления Script и отличается от объекта Err в Visual Basic. Объект Error имеет два свойства, которые указывают место ошибки в сценарии:
• Line - номер строки с ошибкой;
• Column — положение первого символа оператора, вызвавшего ошибочную ситуацию.
Эти свойства используются для установки указателя на место ошибки. Когда в качестве редактора используется элемент управления TextBox, переход на заданный символ в заданной строке текста этого элемента не является тривиальной задачей. Не существует методов или свойств, позволяющих выполнить это непосредственно.
Объект Error элемента управления Script имеет дополнительные свойства, которые перечислены в табл. 20.5.
Таблица 20.5. Дополнительные свойства объекта Error элемента управления Script
Свойство
Описание
Number Description
Text
Source
Номер ошибки
Описание ошибки
Строка с ошибочным оператором
Имя процедуры или класса, в которых произошла ошибка
<
После обработки ошибки для ее сброса вызывается метод
Clear объекта Error. Рассмотрим обработчик ошибок в коде кнопки Execute Script. Если элемент управления Script генерирует ошибку выполнения и свойство ScriptControll.Error.Number не равно нулю, то можно использовать свойство Error элемента управления Script для получения информации об ошибочном операторе. Но в большинстве случаев элемент управления Script генерирует ошибку автоматизации и не инициализирует объект Error. Обработчик ошибок просто отображает ошибку в окне сообщений.
CodeError:
If ScriptControll.Error.Number <> 0 Then
msg = ScriptControll.Error.Description & bvCrLf
msg =
msg & "В строке " & ScriptControll.Error.Line _
& ", столбце" & ScriptControll.Error.Column
MsgBox msg, ,"Ошибка в сценарии"
Else
MsgBox "ERROR # " & Err.Number & vbCrLf & Err.Description
End If
Наиболее частый источник ошибок - вызов неправильных методов или объектных переменных. Следующий оператор активизирует Excel и вызывает метод Evaluate.
Set EXL = CreateObject ("Excel.Application")
MsgBox "Логарифм числа 99 равен" & EXL.Evaluate ("Log(99)")
Если пропущено имя переменной EXL или приложение Excel отсутствует на машине, то в обоих случаях будет выдано одно сообщение об ошибке автоматизации. Это означает, что сценарий не имеет доступа к объекту. Если вызвать функцию InStr() с ошибочным аргументом (или неправильным числом аргументов), то в обоих случаях появится одно сообщение об ошибке. Объект Error элемента управления Script может локализовать только простые синтаксические ошибки. При работе с объектами элемент управления Script не оказывает существенной помощи.
Обращение к API-функциям из
Visual Basic
Единственное отличие функций Visual Basic от API-функций заключается в том, что последние необходимо объявлять перед использованием. По сути, требуется сообщить Visual Basic имя и местоположение DLL-библиотеки, в которой находится требуемая API-функция, и указать типы и количество ее параметров. После этого ее можно использовать так же, как и функцию Visual Basic.
Объявление API-функций
Для объявления API-функций используется оператор Declare. Одним из способов является ввод имени функции с указанием ее параметров.
Declare Function mciSendString Lib "winmm.dll" _
Alias "mciSendStringA" (ByVal IpstrCommand As String_
ByVal IpstrReturnString As String, ByVal uReturnLenght_ As Long, ByVal hwndCallback As Long) As Long
Примечание
Очень длинную строку, содержащую объявление, обычно разбивают на несколько строк меньшей длины, каждая из которых заканчивается символом "_" (символ подчеркивания). Но можно этого и не делать.
API-функция mciSendString()
является частью библиотеки Winmm, расположенной в файле Winmm.dll в подпапке System папки Windows Суффикс А — это наследство, доставшееся от старых версий API, в которых сосуществовали 16- и 32-х разрядные функции. В Windows 95/98 необходимо использовать 32-разрядные функции.
Почти для всех API-функций необходимо передавать параметры по значению. Только те параметры, которые изменяются самой функцией, необходимо передавать по ссылке. По умолчанию, Visual Basic передает аргументы по ссылке, поэтому для передачи аргументов по значению необходимо использовать ключевое слово ByVal.
Использование приложения API Viewer
Предполагается, что пользователю нет необходимости запоминать параметры каждой функции и даже их имена - он может обратиться к справочной системе. Получить доступ к ней можно непосредственно из IDE-среды — окно API Viewer приведено на рис. 13.1.
Используя это приложение, можно вставить в VB-программу любую функцию. Для этого необходимо выполнить следующие действия.
1 . Выберите команду API-Viewer в меню Add-Ins. Если в меню Add-Ins (Надстройки) нет пункта API Viewer, необходимо открыть диалоговое окно Add-Ins Manager (Диспетчер надстроек) и выполнить правый щелчок на элементе Visual Basic 6 API Viewer, чтобы добавить данный пункт в меню Add-Ins.
Рис 13.1. Окно приложения API Viewer
2 . В диалоговом окне API Viewer в меню File (Файл) выберите команду Load Text File (Загрузить текстовый файл) или Load Database File (Загрузить файл базы данных) Загрузка файла базы данных выполняется быстрее, но лишь в том случае если при этом не происходит преобразование текстового файла в файл базы данных
3 . В окне списка Available Items (Доступные объекты) выберите требуемую функцию и щелкните на кнопке Add (Добавить). API-Viewer отобразит выбранную функцию (функции) в окне списка Selected Items (Выделенные объекты)
4 . Выберите функции, которые необходимо вставить в прикладную программу, а затем щелкните на кнопке Сору (Копировать) для копирования объявления функций в Clipboard (Буфер обмена)
5 . Откройте окно Code (Исходный код) вашего приложения и вставьте объявления функций
Совет
Пакет Win32 Software Development Kit содержит полное описание каждой функции, включая все структуры и сообщения. Microsoft Developer Network (MSDN) предоставляет все необходимое для разработки Windows-приложений. Для получения подробной информации о MSDN посетите сайт
http.//www.microsoft.com/msdn.
Большинство API-функций требует большого числа параметров, причем некоторые из них имеют сложный тип. Типы параметров API функции пере числены ниже.
Обращение к классу
EventTimer из других проектов
Для использования класса в другом проекте сначала нужно добавить ссылку на этот класс. Имеется в виду то, что нужно сделать компонент доступным для системы, зарегистрировав его, как описано в предыдущем параграфе. Если DLL- или ЕХЕ-файл компонента был создан и уже зарегистрирован в системе, то любой проект или другое приложение системы могут использовать его. Чтобы добавить класс EventTimer в проект, выполните следующие действия.
1 . Откройте новый проект, затем меню Project и выберите команду References, чтобы открыть диалоговое окно References (Ссылки). Это окно содержит все объекты, на которые можно ссылаться в данном проекте.
2 . Выберите элемент EventTimer (объекты упорядочены по имени их проектов, а не по имени классов) и нажмите ОК. После того как класс был добавлен в проект, можно посмотреть его интерфейс с помощью Object Browser.
3 . Из меню View выберите команду Object Browser, чтобы открыть окно, показанное на рис. 156. В верхнем раскрывающемся списке выберите необходимую ссылку.
Рис. 15.6. Просмотр членов класса EventTimer с помощью Object Browser
4 . Проект EventTimer предоставляет один класс EventTimerClass, имя которого появилось в окне Classes. В окне Members можно увидеть свойства, методы и события этого класса.
Если выбрать мышью свойство ElapsedTime в окне Members, то на нижней панели окна Object Browser появится его описание. Это свойство объекта EventTimer EventTimerClass и оно доступно только для чтения потому что класс содержит только процедуру Property Get этого свойства. Другими членами выступают методы и события класса. Разработчик возможно догадается что делает класс, просто посмотрев на члены которые он предоставляет
Общие методы элемента управления
OLE Container
Чтобы управлять встроенными или связанными объектами, в элементе управления OLE Container, в дополнение к уже упомянутым, предусмотрены следующие методы.
CreateEmbed
С помощью этого метода создается встроенный объект. Синтаксис метода имеет вид:
CreateEmbed sourcedoc, class
Параметр
sourcedoc — имя файла документа, используемого в качестве шаблона для встроенного объекта. Чтобы создать новый встроенный документ, в качестве параметра sourcedoc
указывается строка нулевой длины ("").
Параметр
class — необязательный параметр, определяющий имя класса встроенного объекта. Этот параметр требуется только в том случае, если параметр sourcedoc опущен. Чтобы найти зарегистрированные классы, выберите свойство Class (Класс) в окне Properties (Свойства) элемента управления OLE Container и щелкните на кнопке с многоточием.
CreateLink
Этот метод позволяет создать связанный объект из содержимого файла. Синтаксис метода CreateLink:
CreateLink sourcedoc, sourceitem
Параметр
sourcedoc — это файл, из которого будет создан объект, а параметр sourceitem —
данные внутри файла, которые должны быть в связанном объекте. Например, чтобы связать содержимое элемента управления OLE Container с блоком ячеек рабочего листа Excel, следует задать файл с помощью параметра sourcedoc, a диапазон связанных ячеек - с помощью параметра sourceitem. Параметр sourceitem может указывать на одиночную ячейку (например, R10C12) или на блок ячеек (например, R1C1:R10C20). Можно также задать именованный блок.
После того как связанный документ создан, значение свойства Sourceitem устанавливается в строку нулевой длины, а его первоначальное значение присоединяется к свойству SourceDoc. Например:
"c:\data\revenus\revl997.xls|RCl:R20C25 "
Самый простой способ определения синтаксиса этих двух команд - это выбрать связываемый объект, а затем при проектировании вставить его с помощью команды Paste Special в элемент управления OLE Container. После того как объект будет связан, просмотрите значение свойства SourceDoc и используйте его в собственной программе.
DoVerb verb
Метод DoVerb выполняет команды ( являющиеся глаголами, например, Edit, Play и т. п.). Объекту известно, как выполнять заданное действие. Синтаксис метода:
DoVerb verb
Значения необязательного параметра verb перечислены в табл. 14.3.
Таблица 14.3. Значения параметра verb
Константа
Значение
Описание
VbOLEPrimary
0
Действие для объекта, заданное по умолчанию
vbOLEShow
-1
Открывает объект для редактирования.
Активизирует приложение, создавшее документ, в окне OLE Container
VbOLEOpen
-2
Открывает объект для редактирования
Активизирует приложение, создавшее документ, в отдельном окне
vbOLEHide
-3
Для встроенных объектов позволяет скрыть приложение, создавшее объект
vbOLEUIActivate
-4
Активизирует объект для оперативного редактирования и позволяет отобразить любые инструментальные средства пользовательского интерфейса. Если объект не поддерживает оперативное редактирование, то появляется сообщение об ошибке
VbOLEInPlaceActivate
-5
Когда пользователь перемещает фокус в окно элемента управления
OLE Container, то с помощью этой операции можно создать окно для объекта и подготовить объект, который нужно отредактировать
vbOLEDiscardUndoState
-6
Когда объект активизирован для редактирования, этот метод позволяет отбросить все изменения, которые приложение, создавшее объект, может отменить
InsertObjDIg
Этот метод позволяет отобразить диалоговое окно Insert Object (Вставка объекта). Установки пользователя, выполненные в этом окне, передаются приложению с помощью значений свойств элемента управления OLE Container.
PasteSpecialDIg
Этот метод позволяет отобразить диалоговое окно Paste Special (Специальная вставка). Установки пользователя, выполненные в этом окне, передаются приложению с помощью значений свойств элемента управления OLE Container.
Object Browser позволяет выяснить, какие встроенные константы используются в различных методах и свойствах элемента управления OLE Container.
1 . Выберите команду Object Browser (Просмотр объекта) в меню View (Вид).
2 . Выберите библиотеку объектов Visual Basic, а в нем объект Constant, чтобы отобразить названия констант в списке Method/Properties (Метод/Свойства).
Если немного поэкспериментировать с методами OLE и элементом управления OLE Container, то можно сделать вывод: в пограничных ситуациях OLE далека от совершенства. У пользователя нет возможности полностью контролировать внешний вид встроенного или связанного объекта, а иногда и панель приложения-сервера остается невидимой. Несмотря на то, что работа над OLE идет уже несколько лет, нельзя считать ее завершенной.
Существует не так уж много созданных в Visual Basic приложений, которые выполняют связывание и встраивание документов, предоставленных приложениями-серверами. Однако другой аспект OLE — OLE-автоматизация — вполне совершенна и является наиболее мощным средством основных Windows-приложений, например, Microsoft Office. Автоматизация OLE рассматривается во второй части главы, а сейчас мы кратко рассмотрим операции перетащить-и-опустить, применяемые в OLE.
Общие свойства элемента управления
OLE Container
В этом параграфе рассмотрены свойства и методы, которые используются при работе с документами, встраиваемыми или связываемыми во время выполнения программы. Эти свойства можно установить в среде Visual Basic при разработке приложения методами, описанными ранее.
Class
Это свойство определяет тип объекта, хранящегося в элементе OLE Container. Если запустить приложение OLERTime, то, выбирая объекты различных типов, зарегистрированных в системе, и щелкая затем на кнопке Object Info, можно посмотреть значения свойства Class.
DispIayType
Это свойство указывает, отображается объект с содержимым (значение свойства 0) или только значок OLE-сервера (1).
• vbOLEDisplayContent
(0) — отобразить объект с содержимым;
• vbOLEDisplayIcon
(1) — отобразить объект в виде значка.
OLETypeAllowed
Значение этого свойства обуславливает тип создаваемого объекта:
• 0 — связанный;
• 1 — встроенный;
• 2 — любой.
Тип объекта определяется в диалоговом окне Insert Object. Соответствующие константы приведены ниже:
• vbOLELinked
(0) - объект можно связать;
• vbOLEEmbedded (1) — объект можно встроить;
• vbOLEEither (2) — объект можно связать или встроить.
OLEDropAllowed
Если значение этого свойства - True, то во время выполнения приложения можно поместить объект в элемент управления OLE Container, перетаскивая его
мышью. К аналогичным результатам приводит копирование объекта в буфер обмена и последующий вызов приложением метода Paste Special для элемента OLE Container.
SizeMode
Значение этого свойства определяет, как будет отображаться объект — в виде значка или реального документа в окне элемента управления
OLE Container. Свойство может принимать следующие значения.
• vbOLESizeClip (0).
Это значение установлено по умолчанию. Размеры изображения объекта равны размерам исходного документа. Если размеры объекта больше, чем размеры окна элемента управления OLE Container, то часть изображения отсекается.
• vbOLESizeStretch
(1). Размер изображения объекта изменяется так, чтобы заполнить все окно элемента управления OLE Container. При этом первоначальные пропорции объекта могут измениться.
• vbOLESizeAutosize
(2). Размеры окна элемента управления OLE Container изменяются таким образом, чтобы отобразить весь объект
• vbOLESizeZoom (3). Размеры объекта изменяются так, чтобы объект занял как можно большую часть окна элемента управления OLE Container, а изображение при этом не исказилось.
SourceDoc
При связывании объекта значение этого свойства определяет файл-источник. Когда вы внедряете объект, это свойство определяет, какой файл будет использован в качестве шаблона.
Sourceltem
Этим свойством обладают только связанные объекты. Его значение определяет связываемые данные, находящиеся внутри файла. Например, если выполняется связывание с блоком ячеек рабочего листа Excel, то значение свойства Sourceltem - это диапазон ячеек, которые будут связаны.
OLEType
При выполнении программы это свойство доступно только для чтения. Оно возвращает статус объекта: 0 — для связанных объектов, 1 — для встроенных объектов, и 2 —объект не был вставлен. Соответствующие константы приведены ниже.
• vbOLELinked (0).
Объект связывается с элементом управления OLE.
• vbOLEEmbedded (1).
Объект встраивается в элемент управления OLE.
• vbOLENone (2). Элемент управления OLE Container не содержит объектов.
AutoActivate
Значение этого свойства определяет, будет содержимое элемента управления OLE Container активизировано двойным щелчком или перемещением фокуса в его окно Свойство AutoActivate может принимать следующие значения.
• vbOLEActivaleManual
(0). Объект не активизируется автоматически. Для его активизации необходимо использовать метод DoVerb.
• vbOLEActivateGetFocus
(1). Объект активизируется для редактирования при каждом попадании фокуса в окно элемента управления OLE Container.
• vbOLEActivateDoubleclick
(2). Значение по умолчанию. Объект в окне элемента управления OLE Container активизируется при выполнении на нем двойного щелчка.
• vbOLEActivateAuto
(3). Объект активизируется, когда элемент управления получает фокус либо на объекте выполняется двойной щелчок.
Определение индексов с помощью
Visual Data Manager
Visual Data Manager можно также использовать для организации индексов внутри базы данных. В нижней части окна базы данных находится список текущих индексов базы. Щелкните на кнопке Add Index, чтобы открыть диалоговое окно Add Index To (рис. 17.9). Опции диалогового окна Add Index To (Добавить индекс к) перечислены в табл. 17.6.
Примечание
Null является специальным значением (см. гл. 3). Поле пустое, если оно не было инициализировано (другими словами, если оно ничего не содержит). В общем случае проверяйте значения поля на равенство Null перед его использованием в операциях.
Рис. 17.9. Диалоговое окно Add Index To
Таблица 17.6. Опции диалогового окна Add Index To
Опция
Описание
Name
Имя индекса. Вы можете использовать имя индекса только при программировании наборов записей типа Table. В SQL-запросах технология Rush-More (Делай быстрее) автоматически использует индексную информацию для оптимизации запросов
Indexed Fields
Список полей, по которым проиндексирована таблица. Поля разделены точками с запятой
Available Fields
Окно списка доступных полей щелчок кнопкой мыши на одном из полей добавит его в список индексных полей
Primary
Выберите эту опцию, если поле индекса рассматривается как первичный ключ для таблицы
Unique
Выберите эту опцию, если необходимо использовать уникальные значения для поля. Если вы индексируете таблицу Customers (Заказчики) по полю имени заказчика, то индекс может не быть уникальным. Возможно совпадение имен нескольких заказчиков Индекс, основанный на ID заказчика, уникален. Два заказчика не могут иметь один ключ, даже если имеют одно имя
IgnoreNulls
Это свойство указывает, может ли какое-нибудь из полей, используемых в индексе, содержать значение Null. Если это свойство установлено в False, а свойство Required - в True, a соответствующее поле содержит значение Null, то генерируется ошибка выполнения программы
Определение размеров свободного пространства на диске
В этом разделе описаны функции для определения типа диска и свободного пространства на нем, а также для поиска каталога
Windows и определения текущего каталога. Перечислим их.
• GetDriveType()
• GetDiskFreeSpace()
• GetWindowsDirectory()
• GetCurrentDirectory()
Эти функции предоставляют дополнительные возможности, которых нет в Visual Basic. Например, вы можете определить, есть ли свободное пространства на диске и является ли данное устройство приводом CD-ROM.
Функция GetDriveTypeQ
Эта функция позволяет определить тип дисковода.
Объявляется она следующим образом
Private Declare Function GetDriveType Lib "kernel32" Alias _
"GetDriveTypeA" (ByVal nDrive As String) As Long
Вы передаете функции имя диска, который необходимо проверить с помощью параметра nDrive, и функция возвращает значение типа Long, которое указывает тип диска. В табл. 13.2 приведены типы устройств и их описания
Таблица 13.2. Описание типов устройств
Значение
Описание
0
1
DRIVEREMOVABLE
DRIVEFIXED
DRIVEREMOTE
DRIVECDROM
DRIVERAMDISK
Тип диска определить невозможно
Данный каталог не является корневым
Сменное устройство, например ZIP-накопитель
Несменное устройство, например жесткий диск С
Устройство удаленного доступа, например сетевой диск
CD-ROM-устройство
RAM-диск
VB6 в действии: проект Drives
Приложение Drives (рис 13.2) обеспечивает вывод на экран окна, содержащего информацию о выбранном диске (тип и свободный объем памяти), о текущей папке и о папке Windows системы. Каждый раз, когда пользователь выбирает другое устройство, информация в окне формы изменяется. В приложении Drives используются три API-функции: GetDiskFreeSpace(), GetCurrentDirectory() и GetWindowsDirectory()
Рис. 13.2. Приложение Drives
Функция GetDiskFreeSpace()
Эта функция позволяет получить разнообразную информацию, касающуюся диска, включая количество свободного пространства. Функция возвращает также количество секторов на кластер, байтов на сектор, количество свободных кластеров на диске и общее количество кластеров. Функция
GetDiskFreeSpace() не предоставляет информацию о свободном дисковом пространстве, но его величина может быть вычислена на основании данных о количестве байтов на сектор, секторов на кластер и свободных кластеров Функция объявляется следующим образом:
Private Declare Function GetDiskFreeSpace Lib "kernel32" _
Alias "GetDiskFreeSpaceA" (ByVal IpRootPathName As
_
String, IpSectorsPerCluster As Long, IpBytesPerSector_
As Long, IpNumberOfFreeClusters As Long _
IpTotalNumberOfClusters As Long) As Long
Назначение параметров этой функции понятны и соответствуют их (значимым) именам.
Чтобы определить размеры свободного пространства на диске С, используются следующие операторы:
retValue
- GetDiskFreeSpace("с:\” Sectors, Bytes,_
freeClusters, totalClusters)
FreeSpace = Sectors * Bytes *
freeClusters
Общий объем свободного пространства равен произведению количества свободных кластеров, секторов на кластер и байтов на сектор.
Функция GetCurrentDirectory()
Эту функцию следует применять в случаях, когда необходимо определить текущий каталог, из которого была запущена программа. Данная функция аналогична свойству Арр. Path Visual Basic, и принимает два параметра, один из которых — длина буфера, а второй — указатель на строковую переменную (буфер), в которой будет сохранен путь к текущему каталогу. Функция должна объявляется следующим образом:
Private Declare Function GetCurrentDirectory Lib
"kernel32"
Alias "GetCurrentDirectoryA" (ByVal nBufferLength
_
As Long, ByVal IpBuffer As String) As Long
После вызова функции параметр lpBuffer содержит текущий путь
Функция GetWindowsDirectory()
Эта функция позволяет узнать, в какую папку на жестком диске инсталлирована Windows. Эта информация нужна для дополнительной инсталляции файлов инициализации или справки в каталог Windows. Параметры этой функции идентичны параметрам GetCurrentDirectory(). Ее объявление имеет вид:
Private Declare Function GetWindowsDirectory Lib "kernel32" _
Alias "GetWindowsDirectoryA" (ByVal IpBuffer As _
String, ByVal nSize As Long) As Long
Полный текст программы Drives приведен ниже.
Программа 13.3. Проект Drives
Option Explicit
Private Declare Function GetDriveType Lib "kernel32" _
Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Private Declare Function GetDiskFreeSpace Lib "kernel32" _
Alias "GetDiskFreeSpaceA" (ByVal IpRootPathName _
As String, IpSectorsPerCluster As Long,_
IpBytesPerSector As Long, _
IpNumberOfFreeClusters As Long, _
IpTotalNumberOfClusters As Long) As Long
Private Declare Function GetCurrentDirectory Lib "kernel32" _
Alias "GetCurrentDirectoryA" (ByVal nBufferLength _
As Long, ByVal IpBuffer As String) As Long
Private Declare Function GetWindowsDirectory Lib "kernel32"
Alias "GetWindowsDirectoryA" (ByVal IpBuffer As String,_
ByVal nSize As Long) As Long
Const DRIVE_CDROM = 5
Const DRIVE_FIXED = 3
Const DRIVE_RAMDISK = 6
Const DRIVE_REMOTE = 4
Const DRIVE_REMOVABLE = 2
Private Sub Commandl_Click()
End
End Sub
Private Sub Drivel_Change()
Dim driveType As Long
Dim freeSpace As Long, Sectors As Long
Dim Bytes As Long
Dim freeClusters As Long, totalClusters As Long
Dim retValue As Long
Dim buffer As String * 255
Dim DName As String
Screen.MousePointer = vbHourglass
DoEvents
DName = Left(Drivel.Drive, 2) & "\"
driveType = GetDriveType(DName)
Select Case driveType
Case 0
Label5.Caption = "UNDETERMINED" Case DRIVE_REMOVABLE
Label5.Caption = "REMOVABLE"
Case DRIVE_FIXED
Label5.Caption = "FIXED"
Case DRIVE_REMOTE
Label5.Caption = "REMOTE"
Case DRIVE_CDROM
Label5 Caption - "CDROM"
Case DRIVE_RAMDISK
Label5 Caption - "RAMDISK"
End Select
‘Вычисляем свободное пространство на диске
retValue GetDiskFreeSpace(DName, Sectors, Bytes,_
freeClusters, totalClusters)
Label6 Caption = Sectors * Bytes * freeClusters
‘Определяем путь к текущему каталогу
retValue = GetCurrentDirectory(255, buffer)
Label7 Caption = buffer
‘Определяем путь к каталогу Windows
retValue =
GetWindowsDirectory(buffer, 255)
Label8 Caption = buffer
Screen MousePointer
= vbDefault
DoEvents
Debug
Print App = Path
End Sub
Private Sub Form_Load()
Drivel_Change
End Sub
Прочие файловые функции
Иногда пользователю требуется информация о файле, например, о его размещении, атрибутах или размере. Приложение Filelnfo (рис. 13.3) на компакт-диске демонстрирует возможности получения информации о файле с помощью API-функций.
Рис. 13.3. Приложение Filelnfo
VB6 в действии: проект Filelnfo
Приложение Filelnfo использует следующие функции:
• GetFullPathName()
• GetFileAttnbutes()
• GetFileSize()
Рассмотрим их подробнее.
GetFullPathName(). Функция возвращает полный путь к файлу. Объявляется она следующим образом:
Private Declare Function GetFullPathName Lib "kernel32" _
Alias "GetFullPathNameA" (ByVal IpFileName As String, _
ByVal nBufferLength As Long, ByVal IpBuffer As String, _
ByVal IpFilePart As String) As Long
В приложении Filelnfo эта функция используется для получения пути к файлу, указанному пользователем в стандартном диалоговом окне File Open (Открыть файл)
В качестве параметра функции передается имя файла, путь к которому необходимо определить, а функция возвращает путь в переменной filePath.
GetFileAttributes().
Функция возвращает длинное целое значение, указывающее на состояние файла только для чтения, скрытый или нормальный. Она аналогична функции GetFileAttributes() в Visual Basic. Объявляется следующим образом:
Private Declare Function GetFileAttributes Lib "kernel32"
Alias
"GetFileAttributesA" (ByVal IpFileName As String) As Long
В табл. 13.3 приведены значения атрибутов файла. Использование этих функции продемонстрировано в программе Filelnfo.
Таблица 13.3. Атрибуты файлов
Значение
Описание
FILE_ATTRIBUTE_ ARCHIVE
Архивный файл
FILE_ATTRIBUTE_ COMPRESSED
Сжатый файл
FILE_ ATTRIBUTE_ DIRECTORY
Имя каталога
FILE_ATTRIBUTE_ HIDDEN
Файл или каталог является скрытым: при обычном выводе на экран его не видно
FILE_ATTRIBUTE_ NORMAL
Файл не имеет атрибутов
FILE_ATTRIBUTE_ READONLY
Файл предназначен только для чтения
FILE_ ATTRIBUTE_ SYSTEM
Файл является частью операционной системы
<
GetFileSize().
Чтобы определить размер файла, следует открыть его с помощью функции CreateFile(), использовав в ней параметр OPEN_EXITING (чтобы проверить, что открываемый файл существует). После этого можно воспользоваться функцией GetFileSize(), чтобы получить размер файла в байтах. Естественно, после выполнения операции файл необходимо закрыть с помощью функции CloseHandle().
Приведем исходный текст программы Filelnfo.
Программа 13.4. Проект Filelnfo
Option Explicit
Private Declare Function GetFileAttributes Lib "kernel32"_
Alias "GetFileAttributesA" (ByVal IpFileName As String) As Long
Private Declare Function GetFullPathName Lib "kernel32" _
Alias "GetFullPathNameA" (ByVal IpFileName As String, _
ByVal nBufferLength As Long, ByVal IpBuffer As String,_
ByVal IpFilePart As String) As Long
Private Declare Function CreateFile Lib "kernel32" Alias _
"CreateFileA" (ByVal IpFileName As String, _
ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, _
ByVal IpSecurityAttributes As Any, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As Long
Private Declare Function GetFileSize Lib "kernel32"
(ByVal hFile As Long, IpFileSizeHigh As Long) As Long
Private Declare Function CioseHandle Lib "kernel32" _
(ByVal h0b]ect As Long) As Long
Const FILE_ATTRIBUTE_ARCHIVE = &H20
Const FILE_ATTRIBUTE_COMPRESSED =
&H800
Const FILE_ATTRIBUTE_DIRECTORY =
&H10
Const FILE_ATTRIBUTE_HIDDEN =
&H2
Const FILE_ATTRIBUTE_NORMAL =
&H80
Const FILE_ATTRIBUTE_READONLY =
&H1
Const FILE_ATTRIBUTE_SYSTFM &H4
Const GENERIC_READ =
&H80000000
Const OPEN_EXISTING =
3
Const GENERIC_WRITE = &H40000000
Private Sub Commandl_Click()
Dim retValue As Long
Dim filePath As String * 255
Dim attrFlag As Long, attrStr As String
Dim fileName As String, filePointer As Long
Dim fileSize As Long
CommonDialogI.ShowOpen
If CommonDialogI fileName <> "" Then fileName = _
CommonDialogI fileName
‘Определение пути к файлу
retValue = GetFullPathName(fileName, 255, filePath, 0)
Label5 Caption – filePath
‘Определение атрибутов файла
attrFlag = GetFileAttributes(fileName)
If (attrFlag And FILE_ATTRIBUTE_ARCHIVE) Then
_
attrStr =
"Archive"
If ( attrFlag And FILE_ATTRIBUTE_COMPRESSED) Then _
attrStr = attrStr & "Compressed"
If (attrFlag And FILE_ATTRIBUTE_DIRECTORY) Then _
attrStr = attrStr & "Directory"
If (attrFlag And FILE_ATTRIBUTE_HIDDEN) Then _
attrStr = attrStr & "Hidden"
If (attrFlag And FILE_ATTRIBUTE_NORMAL) Then _
attrStr = attrStr & "Normal"
If (attrFlag And FILE_ATTRIBUTE_READONLY) Then _
attrStr = attrStr & "Read-Only"
If (attrFlag And FILE_ATTRIBUTE_SYSTEM) Then _
attrStr = attrStr & "System"
Label6.Caption = attrStr
‘ Определение размера файла
filePointer = CreateFile(fileName, GENERIC_READ Or _
GENERIC_WRITE, 0&, 0&, OPEN_EXISTING, _ FILE_ATTRIBUTE_NORMAL, 0&)
fileSize = GetFileSize(filePointer, 0&)
Label7.Caption = fileSize
CloseHandle (filePointer)
End Sub
Основные понятия
Прежде чем приводить примеры использования определенных API-функций, ознакомимся с некоторыми основными понятиями. Win32 API состоит из функций, структур и сообщений, позволяющих создавать приложения для Windows 95/98 и Windows NT.
API-функции Windows можно разделить на следующие функциональные группы:
• Windows Management (Управление Windows);
• Graphic Device Interface - GDI (Интерфейс графических устройств);
• System Services (Kernel) (Системные ресурсы (Ядро системы));
• Multimedia (MMSystem) (Средства мультимедиа).
Функции, входящие в состав этих элементов, организованы в виде DLL-библиотек (Dynamic Link Libraries - библиотеки динамической компоновки), и для получения доступа к ним можно воспользоваться любым языком программирования. DLL загружается только на время выполнения программы, поэтому нет необходимости включать ее в приложение на этапе компоновки. Поскольку API-функции используются также и Windows, DLL-библитотеки всегда доступны вашим приложениям.
Функции группы Windows Management (Управление Windows) —
это функции, необходимые для создания и управления приложениями. Все операции ввода и вывода, выполняемые системой, используют эти API-функции, включая ввод с клавиатуры и работу с мышью, а также обработку сообщений, получаемых пользовательским приложением. Эти функции позволяют приложениям организовать более эффективную обработку событий мыши по сравнению с возможностями, предоставляемыми Visual Basic.
Graphic Device Interface (Интерфейс графических устройств) предоставляет функции, использующиеся для организации управления всеми графическими устройствами, поддерживаемыми системой, включая монитор и принтер. Кроме того, они позволяют задавать шрифты, перья и кисти. GDI также поддерживает операции вывода линий и окружностей, а также операции побитовой обработки изображений с помощью функции BitBlt(). (Подробнее с операциями обработки битов изображения можно познакомиться в гл. 7 "Цвет и пиксели в Visual Basic").
Функции группы System Services (Системные ресурсы) используются для получения доступа к ресурсам компьютера и операционной системы. Мы рассмотрим, как можно использовать эти функции для определения доступности некоторых ресурсов системы во время работы приложения.
Функции из группы Multimedia (Средства мультимедиа) позволяют воспроизводить звук, MIDI-музыку и цифровое видео. Для этого следует воспользоваться MCI-командами и интерфейсом MCI-сообщений, которые подробно рассматриваются в Приложении В "Using Multimedia Elements to Enhance Applications"
("Использование элементов мультимедиа для расширения приложений") на компакт-диске.
Основные теги
HTML
Независимо от того, что вы собираетесь делать в Web, некоторые основные понятия HTML необходимо усвоить. Программисту на Visual Basic изучить и использовать HTML достаточно просто. В этой главе приведена информация по HTML, необходимая для создания функционирующих Web-страниц. Опишем теги, сгруппированные по категориям, для создания простых HTML-документов.
Заголовки
Заголовки разделяют части документа. Подобно документам, подготовленным текстовым процессором, HTML-документы могут иметь заголовки, вставляемые тегом <Нn>. Существует шесть уровней заголовков от <Н1> (наивысший) до <Н6> (самый низкий). Для размещения в начале документа заголовка первого уровня используется тег <Н1>.
Welcome to Our Fabulous Site
К этой же группе относится тег , который отображает горизонтальную линию и используется для разделения частей документа. Документ, изображенный на рис. 19.2 и демонстрирующий использование HTML-тегов, сгенерирован следующим HTML-файлом.
Document title
Sample HTML Document
The Document body may contain:
Text, images, sounds and HTML commands
Рис. 19.2. Простой HTML-документ с заголовками и линией
Форматирование абзаца
HTML не разрывает строки абзаца до тех пор, пока в текстовом файле не вставить символ перехода на новую строку. Формат абзаца определяется используемыми в документе шрифтами и размером окна броузера. Чтобы начать новый абзац, нужно дать точное указание броузеру вставить символ перехода на новую строку, используя тег <Р>. Тег <Р> также заставляет броузер вставить дополнительное вертикальное пространство. Чтобы форматировать абзацы без дополнительного вертикального пространства, используется тег .
Как протестировать HTML-теги
Хотя существуют WYSIWYG-инструменты для создания HTML-документов, простой редактор, например Notepad, также позволяет проверить несколько тегов, о которых говорилось в этой главе. Для этого создайте простой текстовый файл с описанной ранее структурой HTML-файла. Сохраните его как TEST.HTM (можно использовать любое имя, но расширение должно быть НТМ). Когда этот файл будет сохраняться впервые, выберите All Files в поле Save As Type диалогового окна Save As. Если не изменить расширение по умолчанию, то будет добавлено расширение ТХТ, и файл будет назван TEST.HTM.TXT.
После сохранения документа переключитесь в Internet Explorer и откройте документ, выполнив команду Open меню File. Теперь можно переходить от текстового редактора в броузер и обратно, редактировать HTML-файл и сохранять его, переключаться в окно Internet Explorer и загружать обновленную версию этого файла нажатием клавиши F5.
Форматирование символов
HTML предлагает набор тегов, предназначенных для форматирования слов и символов. В табл. 19.1 перечислены основные теги форматирования символов. Тег FONT и его аргументы описаны ниже.
Таблица 19.1. Основные теги форматирования символов
Тег
Действие
<В>
<ЕМ>
Включает атрибут полужирного начертания
Включает атрибут курсивного начертания
Включает атрибут машинописного стиля, используется для распечатки листингов
Выделяет текст, идентичен тегу
Отображает текст шрифтом с постоянным шагом, используется для распечатки листингов
Тег . Задает имя, размер и цвет используемого шрифта. Принимает один или более аргументов, описанных ниже.
• SIZE. Задает размер текста. Значение размера выражается не в точках, пикселях или других абсолютных величинах. Это число в диапазоне от 1 (наименьший шрифт) до 7 (наибольший шрифт). Следующий тег отображает текст минимального размера.
tiny type
А следующий тег отображает текст максимального размера
HUGE TYPE
• FACE. Задает шрифт, использующийся для отображения текста. Если заданный шрифт отсутствует на компьютере клиента, то броузер заменит его наиболее близким. Следующий тег отображает текст шрифтом Comic Sans MS
Some text
Можно задать несколько шрифтов Броузер использует первый заданный шрифт. Если он недоступен, то пробует подключить следующий и т.д.
Some text
Если шрифт Comic Sans MS отсутствует на клиентском компьютере, то броузер отображает текст шрифтом Arial (стандартный шрифт Windows, имеется на любой машине). Некоторые интересные шрифты используемые для оформления Web страниц (Verdana, Comic Sans MS и Tahoma), устанавливаются отдельно с Internet Explorer.• COLOR. Задает цвет текста шестнадцатеричным числом (#FFOOFF) либо именем Internet Explorer распознает следующие имена цветов
Aqua Gray Navy Silver
Black Green Olive Teal
Blue Lime Purple White
Fuchsia Maroon Red Yellow
Следующие строки отображают текст красным (Red) цветом.
Thi4 is red text
This is red text
Можно комбинировать несколько атрибутов в одном теге
Открытие базы данных
Для получения доступа к базе данных NWIND из кода активной серверной страницы необходимо создать объект Connection методом Server. CteateObject.
Set DBConnection = Server.CreateObject("ADODB.Connection")
Эту переменную можно использовать для установления связи с базой данных (вызвав ее метод Open).
DBConnection.Open "NWINDDB"
Первый аргумент метода Open — имя источника данных, соответствующего открываемой базе данных. После получения из базы требуемых записей следует освободить объект Connection, вызвав его метод Close.
DBConnection.Close
Совет
Описанный метод предпочтительнее при работе с базами данных Microsoft Access. Если вы работаете с базами SOL Server, то переменную DBConnection следует создавать в коде обработчика события Application_OnStart. Тогда она будет доступна всем клиентам, которым необходим доступ к базе NWIND. Система управления базами данных SQL Server поддерживает многоканальный доступ, а драйвер Microsoft Access ODBC — нет. (Он создает набор подключений, из которых используется первое доступное.) Именно поэтому после завершения работы с базой данных необходимо освобождать объект Connection.
Отображение баз данных
Visual Data Manager - одно из самых простых специальных средств разработки баз данных. Эти средства позволяют исследовать и изменять структуру базы данных и, в некоторых случаях, вводить данные. Можно получить доступ к структуре базы данных из приложения с помощью ряда объектов.
В этом разделе разрабатывается утилита, которая отображает структуру любой базы данных. Упомянутые объекты образуют иерархию, начинающуюся с объекта Database (База данных), причем каждый элемент в базе данных представлен как уникальный объект, к которому можно обращаться как к свойству объекта Database.
Отображение нескольких имен авторов
Вы, возможно, обратили внимание на то, что данная программа отображает только имя первого автора каждого издания. Не исключено, что в подобных приложениях, возможно, захочется отображать всех авторов каждого издания.
Можно, например, добавлять имена авторов в элемент управления ComboBox или ListBox. Можно легко модифицировать программу, чтобы она отображала все имена авторов, если считать, что имена второго и третьего авторов любого издания появляются именно после первой совпадающей записи в таблице Title Authors. Можно вызвать метод MoveNext для объекта AUTHORISBN RecordSet и если его поле ISBN такое, как ISBN текущей книги, то у книги - другой автор и его имя можно отобразить. Если поле ISBN отлично от поля ISBN текущей книги, то у книги больше авторов нет.
Методы Move объекта RecordSet работают с учетом значения индекса RecordSet. Например, вызов метода MoveNext для объекта RecordSet с индексом осуществляет переход на следующую запись в индексе.
Отслеживание перемещения мыши
В практике программирования на Visual Basic часто используется событие MouseMove. Это событие позволяет пользователю контролировать движение мыши. С помощью события MouseMove можно получить информацию о координатах мыши, как только ее указатель помещен на форму. В некоторых ситуациях требуется контролировать координаты определенной точки непосредственно из обработчиков событий Click или DblClick событий (обычно они не позволяют получить информацию о координатах места, в котором выполнен щелчок) или отслеживать перемещение мыши за пределами окна формы Чтобы иметь возможность в любой момент определить текущее положение мыши, следует использовать функцию GetCursorPos.
Private Declare Function GetCursorPos Lib "user32" _
(lpPoint As POINTAPI) As Long
Примечание
Параметры функции GetCursorPos() рассматривались в параграфе "Объявление 32-х разрядных функций и структур".
VB6 в действии: проект MouseMov
В приложении MouseMov (рис. 13.5) для отслеживания перемещения мыши используется бескйнечный цикл. При этом предусматривается возможность передачи управления Windows с помощью оператора DoEvents. Это позволяет Windows обрабатывать другие события (например, остановку программы) при выполнении пользователем щелчка на кнопке Stop. Если бы оператор DoEvents не использовался, то приостановить выполнение программы было бы нельзя.
Рис. 13.5. Приложение MouseMov позволяет отслеживать положение указателя мыши, даже если указатель находится за пределами окна формы приложения
Функция GetCursorPos() возвращает переменную POINTAPI, которую затем можно передать функции WindowFromPoint(), чтобы получить дескриптор окна, на котором находится указатель мыши. Как только дескриптор окна получен, можно определить имя класса окна с помощью функции Get'ClassName(), которая возвращает имя класса окна. Если полученное имя - SysListView32, то это значит, что мышь находится на Рабочем столе Windows. В противном случае мышь находится в другом окне.
Большую часть программы занимает цикл отслеживания указателя мыши. Программа определяет положение указателя мыши и использует эту информацию для получения дескриптора окна и определения имени класса. После этого имя класса выводится на экран и обновляется каждый раз, когда указатель мыши перемещается в новое окно.
Программа 13.7. Приложение MouseMov
Option Explicit
Private Declare Function GetCursorPos Lib "user32" _
(lpPoint As POINTAPI) As Long
Private Declare Function WindowFromPoint Lib "user32"
(ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias _
"GetClassNameA" (ByVal hwnd As Long,_
ByVal IpClassName As String, ByVal nMaxCount As Long) As Long
Private Type POINTAPI
X As Long
Y As Long
End Type
Private gStop As Boolean
Private Sub Commandl_Click()
Dim mousePT As POINTAPI
Dim prevWindow As Long, curWindow As Long
Dim X As Long, Y As Long
Dim className As String
Dim retValue As Long
‘ Отслеживание положения курсора
If Commandl.Caption = "Start" Then
Commandl.Caption = "Stop"
gStop = False prevWindow = 0
‘ Отслеживать до тех пор, пока процесс не будет прерван
‘ пользователем
Do
‘ Остановка отслеживания
If gStop = True Then Exit Do
Call GetCursorPos(mousePT)
X = mousePT.X
Y = mousePT.Y
‘ Получение информации об окне, на котором расположен
‘ указатель мыши
curWindow = WindowFromPoint(X, Y)
If curWindow о prevWindow Then
className = String$(256, "")
prevWindow = curWindow
retValue = GetClassName(curWindow, className, 255)
className = Left$(className, InStr(className,_
vbNullChar) - 1)
If className = "SysListView32" Then
Labell.Caption = "The mouse is over the desktop."
‘(Указатель мыши находится на рабочем столе.)
Else
Labell.Caption = "The mouse is over" & className
‘(Указатель мыши находится на...)
End If
End If
DoEvents
Loop
‘ Остановка отслеживания положения указателя
Else
Command1.Caption = "Start"
gStop = True
End If
End Sub
Private Sub Form QueryUnload(Cancel As Integer,
UnloadMode As Integer)
gStop = True
End Sub Этот проект создан на основе проекта MousePos, который находится в соответствующей папке на компакт-диске.
Панели
Страницы, которые были показаны ранее, занимали все окно броузера. Тем не менее, используя панели (frame), на экране можно отобразить несколько документов. Панели создаются тегом . Такой подход связан с определенными издержками, поэтому мы будем создавать плавающие панели (с возможностью прокрутки содержимого) с использованием тега
Страница, показанная на предыдущем рисунке, на конкретном компьютере может выглядеть не так хорошо. Если окно броузера меньше 700 пикселей в ширину, то в нем не хватит места для двух рамок: отобразить их рядом нельзя, вторая рамка появится ниже первой. Такая проблема возникает при отображении рядом двух изображений в узком окне. Выходом из такой ситуации является размещение изображений в смежных ячейках таблицы без обрамления. То же можно проделать с плавающими панелями. Плавающая панель вставляется в ячейки таблицы также просто, как изображение или абзац текста.
Параметры API-функций
При использовании API-функций необходимо предусмотреть объявление функций и их параметров. Win32 API предназначен для программистов, работающих на языке С или С ++. Поэтому в документации используются структуры данных, принятые в С. Их необходимо преобразовать к их эквивалентам в Visual Basic. В табл. 13.1 приведены объявления, предусмотренные в языке С, и соответствующие VB-эквиваленты. В последнем столбце приведено описание способа передачи параметров API-функциям. Все типы данных передаются по значению, кроме Integer Pointer и Long Integer Pointer (указатели).
Таблица 13.1.
Соответствие типов данных в С и Visual Basic
Объявление С
Тип данных Visual Basic
Способ передачи параметров
Integer
Integer
ByVal
Integer Pointer (LPINT)
Integer
ByRef
Long
Long
ByVal
Long Integer Pointer
Long
ByRef
Stung Pointer (LPSTR)
String
ByVal
Handle
Long
ByVal
Char
String
ByVal
Void Pointer
Any
ByRef
Передача параметров по значению
Чтобы использовать API-функции в VB-приложении, необходимо ознакомиться с двумя механизмами передачи параметров — ByVal
и ByRef. Подробно они рассмотрены в гл. 3.
Когда параметры передаются по значению, вызываемая процедура работает с локальными копиями переменных. Процедура может изменить их значения, но не саму переменную в вызывающей программе. В Visual Basic для индикации такого способа передачи используется ключевое слово ByVal. Ниже приведен текст процедуры AnySub(), в которой параметр anyNumber передается по значению, ему присваивается значение 10. При выходе из процедуры исходное значение переменной восстанавливается.
Программа 13.1. Передача параметров по значению
Sub AnySub(ByVal anyNumber as Integer)
anyNumber = 10
Debug.Print anyNumber
End Sub
Если вызвать процедуру AnySub() следующим образом,
х = 1
Call AnySub(х)
Debug.Print x
то в окне проверки появится сообщение:
AnyNumber = 10
х = 1
С помощью оператора Print в процедуре AnySub() отображается значение, присвоенное переменной anyNumber внутри процедуры (локально). Значение, присвоенное переменной х в вызывающей программе (1), также появляется в окне проверки. Значение 10, присвоенное переменной anyNumber в процедуре AnySub(), вне этой процедуры недействительно.
Передача параметров по ссылке
При передаче параметров по ссылке процедуре предоставляется доступ к переменной в вызывающей программе. Процедура, параметр которой передается таким образом, получает адрес области памяти, хранящей значение параметра. Это дает ей возможность изменять значение параметра. В Visual Basic такой механизм передачи значений параметров устанавливается по умолчанию. В следующем примере процедура AnySub() изменяет значение параметра.
Программа 13.2. Передача параметров по ссылке
Sub AnySub(mylnt As Integer)
mylnt
= 20 ' теперь переменная mylnt имеет значение 20
End
Sub
Если теперь вызвать эту процедуру,
Dim x
As Integer
{Требуемые операторы}
х
= 4
Debug.Print "Before calling AnySub x = " &
x
' (Перед вызовом AnySub x
=...)
Call AnySub(x)
Debug.Print "After calling AnySub x = " & x
' (После вызова AnySub x
=...)
то в окне Debug появятся следующие строки:
{Перед вызовом AnySub х = 4
После вызова AnySub х = 20
Изменение значения переменной х процедурой AnySub() носит глобальный характер, поскольку значение параметра передавалось по ссылке. Если нет оснований разрешать вызываемой процедуре глобальное изменение значений параметров, то параметры необходимо передавать по значению. Некоторые API-функции сохраняют результаты работы, изменяя значения переданных им параметров, поэтому предполагается, что параметр такой функции должен передаваться по ссылке. В языке С такие параметры называются указателями (pointers), так как они указывают на область памяти, в которой хранится значение переменной.
Печать и сохранение документов
Чтобы напечатать документ, следует вызвать метод
Printout:
Printout Background, append, range, outputfilename, from, to, _
item, copies, pages, PrintToFile, Collate,
_
ActivePrinterMacGX, Manual Duplex Print
Все параметры необязательные и соответствуют свойствам, которые вы можете установить в диалоговом окне Print программы Word. Значение параметра Background определяет, будет ли печать выполняться в фоновом режиме. Обычно этому параметру присваивают значение True (при автоматизации приложений).
Совет
При вызове методов с большим количеством параметров (большинство из которых, как правило, опускаются), следует использовать именованные параметры, чтобы определить только некоторые из них. Например, чтобы организовать печать первых трех страниц активного документа, следует воспользоваться следующим выражением.
AppWord.ActiveDocument.Printout from:=1, to:=3
При использовании VBA для указания Word напечатать документ процесс постановки документа в очередь на печать выполняется не мгновенно. Если попытаться закрыть Word сразу после вызова метода Printout, то он сообщит, что завершение работы в данный момент приведет к отмене процедуры печати. Чтобы удостовериться в том, что документ был записан в буфер (это означает, что можно правильно завершить работу Word), необходимо организовать цикл, в котором будет выполняться проверка значения свойства BackgroundPnntingStatus. До тех пор, пока это значение не равно 0, приложение выполняет запись информации в буфер. После того как будет переписана вся информация, можно выйти из Word. Этот прием будет использован в параграфе " VB6 в действии проект WordVBA" далее в этой главе.
Чтобы сохранить докумет, следует воспользоваться методом SaveAs объекта Document с помощью выражения.
SaveAs FileName, File Format, LockComments, Password, _
AddToRecentFiles, WritePassword, ReadOnlyRecomitiended, _
EmbedTrueTypeFonts, SaveNativePictureFormat, _
SaveFormsData, SaveAsOCELetter
Как и в случае с методом Print, параметры метода SaveAs соответствуют установкам диалогового окна Save As приложения. Если файл был предварительно сохранен, следует использовать метод Save, для обращения к которому вообще не требуется задавать параметры. Он позволяет выполнить сохранение документа в файле, используя опции, определенные в методе SaveAs (при самом первом сохранении документа) Чтобы сохранить активный документ в файле с другим именем, следует воспользоваться следующим выражением:
AppWord.ActiveDocument.SaveAs "с:\Documents\Report99.doc"
К свойствам объекта Document также относится свойство Saved,
которое возвращает значение True
или False,
указывающее, был ли документ изменен с момента последнего сохранения. Это свойство можно использовать в программе, чтобы определить, следует ли обращаться к методу Save (Сохранить) перед завершением работы приложения.
Ниже приведен фрагмент программы, позволяющей открыть существующий документ, распечатать его, а затем закрыть приложение. Следует отметить то обстоятельство, что с целью упрощения программы для создания нового экземпляра Word используется функция Create0bject(). Способ установления связи с существующим экземпляром Word рассматривался ранее.
Программа 14.9. Открытие и печать DOC-файла
Dim WordApp As Word.Application
Dim thisDoc As Document
Dim prnTime As Date
Dim breakLoop As Boolean
Set WordApp = CreateOb]act ("Word Application")
WordApp.Visible - False
WordApp.Documents.Open ("c:\sarriple.doc")
thisDoc.Printout True, True
prnTime = Time
breakLoop = False
While WordApp.BackgroundPrintingStatus <> 0 And Not breakLoop
If Minute(Time - prnTime) > 1 Then
Reply = MsgBox("Word is taking too long to print." _
& vbCrLf & "Do you want to quit7", vbYesNo)
'(Word слишком долго выполняет
'печать ... Остановить печать?)
If Reply = vbYes Then
breakLoop = True
Else
prnTime = Time
End If
End If
Wend
WordApp.Quit
MsgBox "Document saved and printed!"
' (Документ сохранен и напечатан')
До тех пор пока Word выполняет запись документа в буфер, значение свойства Background PrintingStatus не равно 0, а пока выполняется цикл, работа приложения не будет завершена.
Из-за аппаратных ошибок этот процесс может никогда не закончиться, и, следовательно, приложение будет заблокировано. Каждую минуту, программа спрашивает пользователя, будет ли он ждать или нет. Если пользователь принимает решение завершить распечатку, переменная breakLoop принимает значение True, что приводит к прерыванию цикла While...Wend. Это достаточно простой подход, хотя он требует больших затрат времени работы процессора. Гораздо более эффективным представляется использование в форме элемента управления Timer, позволяющего программно контролировать процесс печати документа.
Перечислимые свойства
Если переключиться на тестовую форму и поэкспериментировать с элементом управления, то можно заметить, что он ведет себя не совсем так, как обычный элемент управления. Специальные свойства в окне свойств элемента управления могут быть установлены в любое значение Необходимо добавить код, который бы отображал только допустимые значения свойств Effect и TextAlignment и, таким образом, ограничивал выбор пользователя только допустимыми значениями. На рис. 16.6 показано окно свойств элемента упоавления. в котором выбрано свойство TextAlignment.
Рис. 16.6. Некоторые специальные свойства должны иметь ограниченное число значений, которые отображаются в раскрывающемся списке
Тип данных, который содержит малое число значений, называется Enumerated (перечислимым) типом. Integer, Double и другие числовые типы данных являются базовыми и могут представлять числовые значения. Если приложение использует переменную, которая может принимать только ограниченное число целочисленных значений, можно использовать перечислимый тип. Свойство TextAlignment как раз и является такой переменной, поскольку может принимать только одно из нескольких целочисленных значений. Дни недели, например, или месяцы года также являются примерами данных перечислимого типа. Для того чтобы создать перечислимый тип, сначала необходимо объявить значения перечислимого типа. Таким образом VB узнает, какие из значений являются допустимыми. Вставьте следующее объявление перечислимого типа в начало кода сразу после оператора Option Explicit:
Enum Align
[Top Left]
[Top Middle]
[Top Right]
[Center Left]
[Center Middle]
[Center Right]
[Bottom Left]
[Bottom Middle]
[Bottom Right]
End Enum
Это объявление сообщает Visual Basic, что любая переменная, объявленная как Align,
может иметь значения от 0 до 8 (перечислимые значения соответствуют числам, начинающимся с 0). Строки в объявлении типа являются синонимами соответствующих числовых значений, которые будут отображаться в окне свойств. Квадратные скобки в объявлении необходимы только в том случае, если соответствующие строки содержат пробелы (или другие недопустимые символы).
Теперь необходимо заменить тип свойства TextAlignment с Integer на Align (этот перечислимый тип мы только что объявили), так как тип свойства TextAlignment должен быть именно перечислимым. Откройте проект FLEXLabel и выполните следующие изменения:
1. Выберите объект UserControl, откройте окно с его кодом и в начале кода вставьте следующее определение типов:
Enum Align
[Top Left]
[Тор Middle]
[Top Right]
[Center Left]
[Center Middle]
[Center Right]
[Bottom Left]
[Bottom Middle]
[Bottom Right]
End Enum
2. Измените определения процедур Property Let и Property Get свойства TextAlignment таким образом, чтобы они имели тип Align (вместо Integer). Сделать это можно следующим образом:
Public Property Get TextAlignment() As Align
TextAlignment = m_TextAlignment
End Property
Public Property Let TextAlignment (ByVal New_TextAlignment _
As Align)
M_TextAlignment = New_TextAlignment
PropertyChanged "TextAlignment"
End Property
Обратите внимание, что код проверки допустимости значений в процедуре Property Let более не нужен, поскольку пользователь не может выбрать недопустимое значение для этого свойства в окне свойств. Если попытаться связать недопустимое значение со свойством непосредственно в коде, то такая команда будет проигнорирована без каких либо предупреждений или сообщении об ошибке Значение свойства просто не изменится. Попытка присвоить перечислимой переменной недопустимое значение посредством кода приведет к сообщению об ошибке во время выполнения программы.
Первичный ключ
В реляционной системе баз данных каждая запись имеет уникальный идентификатор, который используется для указания записи и связывания ее с другими записями в других таблицах. В большинстве случаев внимательное изучение данных позволяет обнаружить некую характеристику, делающую каждую запись уникальной. Она и может стать первичным ключом. Первичный ключ такого типа называется композитным. Например, в базе данных служащих фирмы номер социального обеспечения каждого работника является композитным первичным ключом.
Когда не имеется явного поля или набора полей, которые могут использоваться для формирования композитного первичного ключа, система управления базами данных Visual Basic (механизм JET) может автоматически генерировать уникальный числовой ключ для каждой записи. Этот ключ предназначен для добавления к таблице поля и установки его типа AutoNumber. Автонумеруемое поле автоматически увеличивается на единицу всякий раз, когда добавляется новая запись. Это гарантирует уникальность ключа, хотя сам ключ не обязательно может что-нибудь означать. До тех пор, пока все таблицы ссылаются на одну запись с помощью одного и того же ключа, последний не обязательно должен иметь содержательный смысл. Иногда автоматически нумеруемый первичный ключ создается для конкретных целей, например, при использовании автоматически нумеруемого поля для номера счета.
Независимо от типа первичного ключа целесообразно делать первичный ключ таблицы полем типа Long (см. гл. 3). Таким образом вы значительно упрощаете разработку других таблиц.
Подход, ориентированный на работу с данными
OLE позволяет сконцентрироваться на работе с данными. Пользователю достаточно знать, что
необходимо сделать, а не как
сделать, и какие программные средства использовать при этом. Например, пользователю многокомпонентной программы не обязательно для работы с электронными таблицами использовать только
Excel или для работы с текстом - только WordPerfect. OLE-приложение предоставляет пользователю доступ к функциональным возможностям электронной таблицы, текстового процессора или графической программы, и все это — внутри одной программы, называемой приложением-контейнером (container application). Visual Basic позволяет создавать компоненты, которые могут использовать функциональные возможности других прикладных программ, и приложения, содержащие составные документы.
Примечание
В прикладных программах, структурированных традиционным образом, главное внимание уделяется обработке данных, а в OLE-приложениях — тому, чем будут обрабатываться эти данные. При изучении OLE-технологии следует помнить об этом простом принципе, выражающем сущность OLE и делающем OLE полезным для пользователя, удовлетворение интересов которого является целью разработчика. Программирование с использованием OLE может оказаться сложным, но конечный продукт должен быть простым и удобным в использовании.
Подключение к Web-серверу
Чтобы подключиться к Web-серверу, запустите Internet Explorer и введите следующий адрес в поле Address броузера.
http://127.Ci.0.1
Это адрес локального компьютера, действительный на любой машине -зарезервированный IP-адрес для подключения к серверу, запущенному на компьютере, с которого поступил запрос на подключение. После введения этого адреса Web-сервер отображает документ по умолчанию. Вы можете скопировать в корневой каталог сервера любой HTML-документ и открыть его, передав его имя после адреса сервера. Еще лучше — создайте виртуальную папку для каталога C'\INETPLIB\WWWROOT, назовите ее MVB6 и скопируйте в нее HTML-файлы, которые будут тестироваться в это главе. По следующему адресу можно открыть файл Calendar.htm в окне броузера.
http://127.0.0.1/MVB6/Calendar.htm
В следующем параграфе мы научимся разрабатывать выполняемые на сервере приложения, которые можно запускать с компьютера клиента. Оказывается, что разработка таких приложений не составляег особого труда. Это такие же сценарии, которые можно встроить в HTML-страницу, только выполняются они на сервере. Их называют активными серверными страницами (Active Server Pages — ASP) и, имея навыки программирования на Visual Basic, можно немедленно присгупать к их программированию.
Visual Basic предоставляет специальный тип проекта — тип IIS Application — позволяющий автоматизировать процесс разработки активных серверных страниц. Даже при наличии таких средств достаточно сложно создать сценарий, имеющий практическое применение, без знания основ работы сценариев на сервере и объектов для взаимодействия с клиентом, предоставляемых ASP.
Подключения
Для явного подключения к источнику данных объявите переменную Connection с помощью выражения:
Dim ADOConn As New ADODB.Connection
Вызовите метод Open объекта ADOConn, передавая в качестве аргумента строку подключения.
ADOConn.Open "DSN=AdvWorks;UID=xxx;PWD=xxx"
(Здесь ххх -идентификатор пользователя и пароль соответственно.) Аргумент DSN — имя источника данных Data Source.
Когда объект Connection создан, его можно назначить свойству ActiveConnection объектов RecordSet или Command.
Получение информации
Outlook сохраняет разнотипную информацию в различных файлах. Информация о контактах хранится в файле Contacts (Контакты), входящие сообщения хранятся в папке InBox и т.д. Большинство пользователей, однако, изменяет структуру папок, предлагаемьи Outlook, добавляя дополнительные подпапки к заданным по умолчанию. Например, чтобы упорядочить информацию о контактах, можно создать подпапки Business и Personal в папке Contacts (Контакты). Аналогично, в папке InBox можно создать папки Business, Personal и Junk.
Типичной задачей, которую требуется решать, является поиск желаемой информации. В последующих примерах будет рассматриваться способ доступа к контактам и входящим сообщениям в папках Contacts и InBox, соответственно.
VB6 в действии : проект Contacts (Контакты)
В качестве первого примера того, как, используя средства OLE, можно работать с Outlook, будет рассмотрено приложение Contact, форма которого приведена на рис. 14.20. В этом приложении подразумевается, что все объекты, относящиеся к контактам, хранятся в папке Contacts. Если контакты пользователя организованы по-другому, например, в отдельных подпапках в папке Contacts, следует скопировать (на время) несколько соответствующих файлов в эту папку, чтобы можно было проверить приложение. Чуть позже, в параграфе "Рекурсивный просмотр папки Contacts" будет рассмотрена рекурсивная процедура просмотра всей папки Contacts (включая подпапки).
Главная форма проекта Contacts содержит два списка. Первый список заполнен названиями компаний, которые считываются из соответствующих полей каждого контакта. В этом списке названия компаний не дублируются, несмотря на то, что типичная папка Contacts может содержать несколько контактов из одной и той же компании. Чтобы просмотреть список контактов, принадлежащих одной компании, необходимо щелкнуть на ее названии. Соответствующие контакты появятся в поле списка Contacts. Теперь при каждом щелчке на имени контакта в нижней части окна формы будет отображаться подробная информация о контакте.
Программа начинает свою работу с обращения к Outlook ( после щелчка на кнопке Start Outlook). Ниже приведен код обработчика нажатия соответствующей кнопки.
Рис. 14.20. В проекте Contacts выполняется поиск информации о контактах объекта в папке Contacts в Outlook
Программа 14.18. Обращение к Outlook
Private Sub Commandl_Click ()
On Error GoTo OutlookNotStarted
Set OLApp - CreateOb^ect ("Outlook Application")
On Error GoTo NoMAPINameSpace
Set mNameSpace - OLApp GetNamespace ("MAPI")
List1.Clear
List2.Clear
Command2.Enabled = True
Exit Sub
OutlookNotStarted:
MsgBox "Could not start Outlook"
' (Невозможно запустить Outlook)
Exit Sub
NoMAPINameSpace:
MsgBox "Could not get MAPI NameSpace"
' (Невозможно получить место нахождения MAPI)
Exit Sub
End Sub
Если обращение к Outlook было успешным, кнопка View Contact становится доступной. Если щелкнуть на этой кнопке, программа создаст семейство, содержащее все объекты, находящиеся в папке Contacts, и отсортирует семейство allContacts согласно названиям компаний. Повторяющиеся названия будут удалены из списка (это обеспечивается оператором If, находящимся в конце подпрограммы). Текст программы обработчика кнопки View Contact приведен ниже.
Программа 14.19. Загрузка списка контактов
Private Sub Command2_Click()
Set allContacts = _
mNameSpace.GetDefaultFolder(olFolderContacts).Items
all Contacts.Sort = "CompanyName"
On Error Resume Next
For Each mContact In allContacts
If Trim(mContact.CompanyName) <> "" Then _
List1.Addltem mContact.CompanyName
If List1.List(List1.Newlndex) =
List1.List(List1.Newlndex - 1) Then
List1.Removeltem List1.Newlndex
Next
End Sub
Программа, которая получает контакты из выбранной (в левом окне) папки, должна быть помещена в обработчик события Click элемента ListBox.
Программа 14.20. Получение списка контактов в выбранной компании
Private Sub Listl_Click()
Dim CompanyName As String
Dim filterString As String
If List1.Listlndex = -1 Then Exit Sub
CompanyName = Listi.Text
filterString = "[CompanyName] = " " " & CompanyName & " " " "
Set thiscontact =
allContacts.Find(filterString)
If IsNull(thiscontact) Then
MsgBox "Fatal error in locating a contact.Program will exit"
' ( Фатальная ошибка при поиске контакта. Работа
' программы будет завершена)
End
End If
List2.Clear
While Not thiscontact Is Nothing
If Trim(thiscontact.FullName) <> " " Then _
List2.Addltem thiscontact.FullName
Set thiscontact = allContacts.FindNext
Wend
End Sub
Для вывода дополнительной информации о контакте потребуется еще одна программа, которая должна быть включена в обработчик события Click элемента управления List.
Программа 14.21. Вывод информации о контакте
Private Sub List2_Click()
Dim ContactName As String
Dim filterString As String
If List2.ListIndex = -1 Then Exit Sub
ContactName = List2.Text
filterString= "[FullName]= " " " & ContactName & " " " "
Set thiscontact = allContacts.Find(filterString)
If IsNull(thiscontact) Then
MsgBox "Fatal error in locating a contact. Program will exit"
' Фатальная ошибка при поиске контакта. Работа
' программы будет завершена)
End
End If
IblName.Caption = "" & thiscontact.Full Name
IblPhone.Caption = "" & thiscontact.BusinessTelephoneNumber
IblFAX.Caption = "" & thiscontact.BusinessFaxNumber
IblEMall.Caption = "" & thiscontact.EmaillAddress
End Sub
VB6 в действии: проект Messages
В проекте Messages демонстрируются приемы получения почтовых сообщений. Сообщения могут храниться в папках InBox и OutBox, а также в любых подпапках, созданных в этих папках. Программа Messages может получать сообщения только из папки InBox. Если в этой папке нет никаких сообщений, следует скопировать (на время) туда несколько входящих сообщений, чтобы проверить приложение. Чуть дальше в этой же главе будет рассмотрена процедура просмотра сообщений в папке InBox (включая вложенные подпапки) на любую глубину. Уместно напомнить, что это будет делать рекурсивная процедура.
Приложение Messages (рис. 14.21) позволяет выбирать сообщения, основываясь на информации об их отправителе или дате отправления. Критерии поиска задаются пользователем путем ввода соответствующих значений в окна, расположенные в правом верхнем углу формы. После ввода следует щелкнуть на кнопке Show Selected Messages (Показать выбранные сообщения), чтобы отобразить сообщения, отвечающие заданным критериям. Программа будет выводить только имя отправителя сообщения и тему. Затем, каждый раз, когда пользователь будет выбирать одно из сообщений в этом списке, щелкая на нем, подробная информация о нем будет отображаться в окнах соответствующих элементов управления в нижней части формы (включая текст сообщения). Если сообщение, содержит присоединенные файлы, их имена отображаются в окне сообщения. Запустите этот проект и поэкспериментируйте с ним. Впрочем, имеются две проблемы, о которых следует знать. Во-первых, приложение Messages может просматривать только сообщения в папке InBox. Если сообщения находятся в подпапках папки InBox, следует переместить (на время) несколько сообщений в папку InBox. Вторая проблема заключается в том, что имена отправителя читаются из папки Contacts. Если имена в папке Contacts не соответствуют именам, которые появляются в сообщениях, то нельзя будет увидеть сообщения, посланные выбранным контактом.
Рис. 14.21. В проекте Messages демонстрируется возможность чтения входящих сообщении Outlook из VB-приложений
Пользовательские элементы управления ActiveX на Web-страницах
Элементы управления ActiveX используются как на формах, так и на Web-страницах. Это достаточно смелое утверждение, поскольку Рабочий стол и Web-страница имеют различные требования, и не так просто разработать элемент управления для обеих сред. Основное различие состоит в использовании приложений этих двух типов. Приложения для Рабочего стола разрабатываются с учетом того факта, что все ресурсы находятся на локальной машине, где они и запускаются. Приложения Web запускаются на удаленном компьютере, и любые дополнительные ресурсы (изображения и звук) подгружаются по мере необходимости. К счастью, большинство элементов управления, созданных для Рабочего стола, работают и на Web-страницах, но не все они работают одинаково хорошо в обеих средах.
Microsoft предлагает большое количество элементов управления ActiveX для использования на Web-страницах. Некоторые из них поставляются вместе с Internet Explorer, включая такие элементы управления, как Structured Graphics, Filter и Sequencer. Дополнительную информацию и примеры использования можно найти по адресу http://www.microsoft.com/workshop. Практически, каждый элемент управления ActiveX, размещенный на форме Visual Basic, можно использовать и на Web-странице (если он загружен и проинсталлирован на компьютере клиента). В следующих параграфах рассказывается, как использовать на Web-страницах пользовательские элементы управления ActiveX, созданные в предыдущих главах.
Страница ALARM.HTM
В этом параграфе рассматривается создание Web-страницы с использованием элемента управления ALARM (см. гл. 16). Зачем утруждать себя размещением будильника на Web-странице (кроме как для наглядной демонстрации возможностей пользовательских элементов управления при помощи VBScript)? На рис. 19.8 показана одна причина. Страница содержит таймер, который позволяет пользователю читать страницу за 60 секунд. Пользователь всегда может оставить страницу, введением другого URL в поле Address броузера или нажатием кнопки Back. Если пользователь продержит эту страницу открытой 60 секунд, то сценарий автоматически предоставит ему или ей другую страницу.
Таймер удобен в нескольких ситуациях. Например, можно его использовать для обновления страницы "живыми" данными или отсчета времени в игре.
Знатокам элементов управления ActiveX для Web-приложений известно, что есть элемент управления Timer, который можно использовать и для Web-страниц, но это не так просто, как применение элемента управления Alarm. Во-первых, при использовании элемента управления Timer нужно вести отсчет времени в вашей программе. Во-вторых, время задержки таймера задается в миллисекундах, а сценарий должен обработать событие Timer много раз, прежде чем выполнить какое-то действие.
Рис. 19.8. Пользовательский элемент управления Alarm на Web-странице
Элемент управления ActiveX Alarm, как и элемент управления Timer из Visual Basic, не содержит видимых компонентов и если нужно, чтобы пользователь знал, что происходит, то нужно предоставить ему видимую обратную связь из сценария.
Начнем с тегов HTML для размещения, например, экземпляра элемента управления Alarm на Web-странице.
classid="cisid:7282EB2E-B8A9-11CF-B2FB-005348C101FC"
border="0"
width="120" heigth="33">
Teг вставляет элемент управления ActiveX на страницу, но его синтаксис, мягко говоря, специфический. Однако вам нет потребности вводить его вручную. Каждый элемент управления ActiveX имеет свойства NAME и ID, подобно встроенным элементам управления. Свойство CLASSID представляет собой длинную строку, которая идентифицирует элемент управления в системном реестре. Чтобы создать определение объекта на странице, используют WYSIWYG-редактор HTML, такой как Frontpage Express (поставляется вместе с Internet Explorer). Создадим новую HTML-страницу и вставим требуемый элемент управления ActiveX, выполнив следующие действия.
1 . Выберите команду ActiveX диалогового окна Other Component меню Control Insert, чтобы открыть диалоговое окно ActiveX Control Properties.
2 . Откройте раскрывающийся список Pick a Control и найдите пункт AlarmProjectAlarmCtl. Таким образом, элемент управления ActiveX Alarm будет занесен в список Registry (Если Alarm ProJect.AlarmCtI в списке не появился, то следуйте инструкциям следующей врезки ''Регистрация пользовательских элементов управления ActiveX").
3 . Установите имя элемента управления как AlarmCtl.
4 . Щелкните на кнопке Properties, чтобы установить дополнительные свойства пользовательского элемента управления. Для элемента управления Alarm установите в свойстве Count Down значение True.
5 . Щелкните на кнопке ОК, чтобы закрыть диалоговое окно.
6 . Выберите команду HTML меню View, чтобы открыть текстовый редактор, отображающий исходный код страницы. Выберите определение тега и скопируйте его в Clipboard.
7 . Переключитесь в текстовый редактор HTML-документа и вставьте определение тега .
Как видите, вставить тег на Web-страницу для пользовательского элемента управления не сложно. Это определение не изменяется, даже когда тег устанавливается на другом компьютере. Также тег можно скопировать из любой Web-страницы, содержащей его.
Регистрация пользовательских элементов управления ActiveX
После разработки пользовательского элемента управления
ActiveX его не нужно регистрировать для использования в тестовом проекте. Если его нужно использовать в другом проекте, то сначала нужно его зарегистрировать. Для регистрации пользовательского элемента управления ActiveX выполните следующее.
1 . Создайте ОСХ-файл элемента управления, выбрав команду Make control.ocx (control — это имя пользовательского элемента управления) меню File.
2 . Переключитесь на сеанс работы с DOS, чтобы отобразилась командная строка DOS, перейдите в папку, в которой сохранен ОСХ-файл, и введите команду:
С:\windows\system\regsvr32 control.ocx
Замените
control.ocx именем ОСХ-файла, необходимым для регистрации.
3 . Выйдите из DOS.
Новый элемент управления может использоваться в любом проекте, даже на Web-страницах. В среде разработки Visual Basic имя пользовательского элемента управления появится в диалоговом окне Components (чтобы открыть это диалоговое окно, выберите команду Components меню Project). Такое же имя появится в диалоговом окне свойств элементов управления ActiveX Frontpage.
Значение элемента управления CLASSID будет отличаться в конкретной системе. Поэтому, нельзя использовать файл ALARM.HTM в том виде, в котором он находится на компакт-диске. Необходимо изменить атрибут CLASSID на значение, генерируемое вашей системой.
8 . Введите соответствующий текст и теги HTML на страницу, сохраните ее как ALARM HTM и откройте с помощью Internet Explorer.
Кроме того, пользователь должен видеть элемент управления Alarm с обратным отсчетом прямо на странице. Конечно, ничего не произойдет, когда пройдет время выдачи сигнала, потому что не добавлен соответствующий код. Как только загрузится страница, сценарий должен включить таймер, и по истечении положенного времени он предоставит пользователю другую страницу (начальную страницу Sybex).
Для этого нужно открыть страницу в текстовом редакторе и добавить следующий сценарий.
Событие window_onLoad инициируется при загрузке страницы. В этом событии необходимо инициализировать свойства элемента управления. Установите свойство AlarmTime на минуту вперед от текущего времени и начните отсчет. Свойство CountDown было установлено при определении тега следующей командой в обработчике события onLoad.
AlarmCtl.CountDown =
True
Свойство AlarmTime не может быть установлено в режиме разработки — только в сценарии страницы.
Когда истечет указанный промежуток времени, будет инициировано событие AlarmTime. В его обработчике нужно запрограммировать броузер на переход на другую страницу с использованием метода Window.Navigate.
Программа 19.2. Страница Alarm.htm
Alarm Demo Page
classid="clsid:7282EB2E-B8A9-llCF-B2FB-005348C101FC"
border="0"
width="120" heigth="33">
The Alarm Page Demo
You will be given 60 seconds to read the important information on
this page and then you'll be taken to our home page.
The little alarm clock at the top of the page will count down every
second and when it reaches zero, your computer will be connected to
SYBEX home page.
If you are not connected to the Internet, you'll get an error message
instead.
Это HTML-код, создающий страницу, показанную на рис. 19.8. HTML-теги просты, и даже при слабом знакомстве с HTML этот код понять просто. Чтобы увидеть этот элемент управления в действии, выполните следующее.
1 . Откройте Internet Explorer.
2 . Выберите команду Open в меню File, и в диалоговом окне откройте файл Alarm.htm.
3 . Подождите 60 секунд, и сценарий загрузит домашнюю страницу SYBEX.
Элемент управления Alarm хорошо работает в Internet Explorer, и нет необходимости в его доработке. Он ведет себя точно так, как в среде Visual Basic. Он предоставляет свои свойства и методы, а его события можно программировать.
Страница UINPUT.HTM
Страница UINPUT.HTM (рис. 19.9) демонстрирует использование элемента управления ActiveX CTextBox на Web-странице. Воспользуйтесь схемой из предыдущего параграфа для создания с помощью Frontpage определения тега , a затем добавьте текст и HTML-теги Тег для вставки элемента управления CTextBox показан ниже.
NAME= "CTextBoxl"
classid="clsid 7282EB5A-B8A9-11CF B2FB-005348C101FC"
border="0"
WIDTH="150" HEIGHT="19">
Рис. 19.9. Страница UINPUT HTM использование элемента управления CTextBox для получения от пользователя обязательных и необязательных данных
Сценарий страницы прост. Он инициализирует элементы управления, задавая их свойства Mandatory и Text.
Sub window_onLoad()
CTextBox1.Mandatory=1
CTextBox2.Mandatory=1
CTextBox6.Mandatory=1
CTextBox1.Text=" "
CTextBox2.Text=" "
CTextBox3.Text=" "
CTextBox4.Text=" "
CTextBox5.Text=" "
CTextBox6.Text=" "
EndSub
Если эти элементы управления используются для сбора данных от пользователя, то на форме будет кнопка Submit. Чтобы до передачи данных на сервер удостовериться, что требуемым полям присвоены значения, используйте событие onClick кнопки. На компакт-диске находится страница LABEL3D.HTM, которая использует пользовательский элемент управления FLXLabel (гл. 16) для отображения выпуклого и тисненого текста в окне броузера. Чтобы протестировать элемент управления FLXLabel на Web-странице, необходимо зарегистрировать элемент управления в системе, а затем разместить на странице атрибут CLASSID элемента управления со значением, заданным Visual Basic.
Пример организации связывания и встраивания
Давайте рассмотрим пример реализации связывания и встраивания с точки зрения пользователя. Чтобы создать составной документ с помощью программы WordPad, необходимо выполнить следующие действия.
1. Запустите редактор WordPad с помощью меню Start (Пуск)/
2. Выберите команду Object (Объект) в меню Insert (Вставка), чтобы вызвать на экран диалоговое окно Insert Object (Вставка объекта), как показано на рис. 14.2.
3. Установите переключатель в положение Create from File (Создать из файла), а затем щелкните на кнопке Browse (Обзор).
4. В диалоговом окне Browse (Обзор) (идентичном диалоговому окну File Open (Открыть)) выберите растровое изображение и щелкните на кнопке ОК. Выбранное изображение будет встроено в документ WordPad.
Если сохранить этот документ, то в нем сохранится растровое изображение. При этом WordPad будет выполнять функции приложения-контейнера, содержащего растровый объект, сохраненный вместе с документом. Если пользователь будет редактировать исходное растровое изображение, то его копия, вставленная в документ WordPad, не изменится.
Inseil Object
Рис. 14.2. Диалоговое окно Insert Object (Вставка объекта) позволяет выбрать существующий объект (или создать новый) и встроить его (или связать) с текущим документом
Если установить переключатель в положение Create New (в диалоговом окне Insert Object (Вставка объекта)), то на экране появится прокручивающийся список объектов, доступных системе. Каждое приложение, выполняющее функции приложения-сервера, регистрирует предоставляемые объекты в системе, чтобы приложения-контейнеры могли ими воспользоваться. Когда вы вставляете объект, приложение для работы с ним запускается автоматически при открытии каждого нового документа. Вернемся в диалоговое окно Insert Object (Вставка объекта), установим переключатель в положение Create New (Создать новый) и выберем из списка Object Types объект Bitmap Image (Растровое изображение). По умолчанию предполагается, что растровые изображения создаются в программе Paint. Если в системе не была заменена прикладная программа для создания и обработки растровых изображений, то WordPad установит связь с Paint и выведет на экран ее интерфейс пользователя Меню WordPad будет заменено на меню Paint, и на экране появится панель инструментов Paint (рис. 14.3). Теперь можно создать новое растровое изображение, пользуясь средствами Paint, но этот процесс будет происходить в WordPad. При этом не нужно запускать другое приложение, копировать растровое изображение, а затем вставлять его в ваш документ.
Независимо от того, какое было вставлено растровое изображение — новое или уже существующее — для его редактирования достаточно выполнить двойной щелчок в области изображения. Операционная система обращается к Registry (Реестру), чтобы найти приложение, ассоциированное с растровым изображением. По умолчанию — это программа Paint, которая поставляется вместе с Windows. Если эта установка не была изменена, то будет запушено приложение Paint и вместо меню и панели инструментов WordPad появится меню Paint (рис 14.3). (Если же эта установка была изменена, то будет запущено иное приложение). Теперь можно отредактировать растровое изображение, а затем возвратиться в основной документ щелкнув за пределами растрового изображения. В нашем случае, приложение Paint является приложением-сервером, которое "знает", как обрабатывать растровые изображения.
Рис. 14.3. Меню и панели инструментов приложения-контейнера (WordPad) заменяются меню и панелями инструментов приложения-сервера (Paint)
Растровое изображение, помещенное в документ WordPad, и растровое изображение, содержащееся на дисковом файле - это два отдельных объекта. Можно изменять этот файл на диске, заменять его другим, можно даже удалить его — на содержимое документа WordPad это не повлияет. В документе WordPad содержится копия растрового изображения.
Поскольку можно редактировать встроенный объект в том окне, в котором он находится, не нужно знать, с помощью какой программы был создан объект, и не нужно работать с этим объектом в отдельном окне. Одно из преимуществ такого подхода — упрощается выполнение операции масштабирования объекта по отношению к окружающему тексту.
Если в диалоговом окне Insert Object (Вставка объекта) установить флажок Link (Связать), то объект в документе WordPad будет связан с исходным объектом. При связывании объекта в системе будет только один объект (файл, содержащий растровое изображение. При этом в документе WordPad будет содержаться ссылка на него, а не копия объекта. Тот же объект может быть связан с другим документом, возможно, с другим приложением. Независимо от количества документов, ссылающихся на данный объект, в системе будет находиться только один исходный объект. Если его изменить, то во всех документах, ссылающихся на него, появится уже измененная версия объекта (рис. 14.4).
Рис. 14.4. Во время редактирования связанного объекта средствами приложения-сервера, связанное с ним изображение в приложении-контейнере также модифицируется по мере редактирования исходного объекта
Примечание
Если объект, вставленный в приложение-контейнер, связан с исходным объектом (файлом-источником), то его нельзя отредактировать из приложения-контейнера. Это можно сделать из приложения-сервера. Сущность связывания заключается в том, что пользователь не может редактировать объект из какого-либо приложения. В памяти компьютера находится только один экземпляр объекта, и его можно изменить только с помощью программы, в которой он был создан. Как только объект будет изменен, все программы, имеющие на него ссылки, также изменятся.
Присоединение запросов к базе данных
Рассмотрим процесс определения запроса с помощью SQL-операторров и присоединения их к базе данных. Выполните следующие действия.
1 . Запустите Visual Data Manadger и откройте базу данных BIBLIO.
2 . В окне Database щелкните правой кнопкой мыши на запросе All Titles и из контекстного меню выберите команду Design.Visual Data Manadger отобразит другое окно с определением запроса (рис. 17.18).
Рис. 17.18. Кроме таблиц, база данных содержит запросы — SQL-операторы, входящие в проект базы данных
Примечание
Как видите, при открытии окна Database иконка запроса отличается от иконки таблицы.
Имя запроса появляется в свойстве RecordSource элемента управления Data, соединенного с базой данных BIBLIO. Позже мы используем этот запрос, чтобы модифицировать приложение ManyTbIs. Но сначала рассмотрим инструментальные средства Visual Data Manager для построения SQL-запросов.
Построение SQL-запросов
Если SQL кажется вам сложным для изучения, то знайте: Visual Data Manager позволяет создавать простые SQL-операторы с помощью мыши. Щелкните правой кнопкой мыши в окне Datadase и из контекстного меню выберите New Query (Новый запрос), чтобы открыть окно Query Builder (Конструктор запросов) (рис. 17.19).
Рис. 17.19. Query Builder: построение SQL-операторов с помощью мыши
Используем Visual Data Manager для построения простых SQL-операторов. Выполните следующие действия, чтобы создать запрос, выбирающий названия всех изданий и их издателей.
1 . Выберите имена таблиц Publishers и Titles, щелкнув кнопкой мыши на их именах в списке Tables (Таблицы). Поля выбранных таблиц появятся в списке Field to Show (Показывать поля).
2 . Щелкните на именах полей, которые необходимо включить в запрос (в RecordSet, который этот запрос возвратит). Щелкните на следующих именах полей Titles Title, Titles [Year Published] и Publishers Name.
Построим наиболее сложную часть SQL-оператора. Щелкните на кнопке Set Table Joins (Установить связи между таблицами) для задания объединения (чтобы определить, как таблицы будут объединены) Visual Data Manager не использует оператор JOIN. Он реализует объединения с помощью ключевого слова WHERE, а это означает, что на этот инструмент нельзя полагаться при создании усовершенствованных запросов.
3 . В списке Select Table Pair (Выбрать пары таблиц) щелкните на именах таблиц Titles и Publishers. Поля обеих таблиц появятся в списках под заголовком Select Fields to Join On (Выбрать поля для объединения), как показано на рис. 17.20.
Рис. 17.20. Диалоговое окно Join Tables: позволяет определить внутренние объединения
4 . Щелкните на поле PubID в обоих списках. Таблицы Titles и Publishers объединятся по значению поля PubID.
5 . Щелкните на кнопке Add Join to Query (Добавить объединение к запросу), чтобы добавить в запрос объединение.
6 . Щелкните на кнопке Close, чтобы возвратиться в окно конструктора запросов Query Builder. Запрос определен.
7 . Щелкните на кнопке Show, чтобы отобразить SQL-оператор, или на кнопке Run, чтобы выполнить его. После сообщения о том, является ли данный запрос SQLPassThrough-запросом, щелкните на кнопке No. Появится новая форма с элементом управления Data, позволяющим перемещаться по выбранным записям.
8 . Для присоединения запроса к базе данных щелкните на кнопке Save. Visual Data Manager запросит имя запроса и присоединит его к базе данных. В следующий раз при подключении элемента управления Data к базе данных в списке доступных элементов RecordSource появится имя запроса.
Можно использовать конструктор запросов Query Builder, чтобы определить критерии выбора, реализуемые с помощью ключевого слова WHERE для группирования и упорядочивания результатов запроса, а также ограничения размера RecordSet (если он слишком большой).
Чтобы добавить критерий выбора, выберите имя поля в списке Field Name, задайте операцию и определите значение в поле Value. Если вы не помните значение определенного поля, то щелкните на кнопке List Possible Values (Список возможных значений) и Visual Data Manager выведет все значения указанного списка.
SQL-операторы, сгенерированные конструктором запросов Query Builder, просты и пригодны для несложных запросов. Например, конструктор запросов Query Builder не создает множественные объединения. Но всегда можно отредактировать SQL-оператор (открывая запрос в режиме разработки) и добавить в него ключевые слова. Если необходимо создать SQL-оператор, а вы еще свободно не владеете SQL-языком, то используйте более совершенный инструмент, например, MS Access.
VB6 в действии: проект SQLTbIs (модификация ManyTbIs)
Приложение ManyTbIs объединяет все таблицы базы данных
BIBLIO для отображения названий книг с именами авторов и издателей. В нем используется метод Seek для объединения таблиц не потому, что это наиболее эффективная реализация, а чтобы продемонстрировать использование индексов в методе Seek. Реализуем подобное приложение, но для определения RecordSet с необходимыми полями будем использовать SQL-операторы. Выполните следующие действия.
1 . Откройте приложение ManyTbIs, сохраните его как SQLTbIs (измените имя формы на SQLTbIs) и поместите его в новую папку.
2 . Удалите все элементы управления Data формы и разместите на ней новый элемент управления Data. Назовите его TITLES и присвойте его свойству Caption значение
Titles-Authors-Publishers.
3 . Соедините этот элемент управления с базой данных BIBLIO, указав в свойстве DatabaseName путь к базе данных.
4 . Откройте список свойства RecordSource и выберите All Titles. Это имя SQL-запроса в базе данных, который возвращает необходимый RecordSet (названия изданий, их авторов и издателей).
5 . Так как RecordSet создан с помощью SQL-оператора, то он является набором записей типа DynaSet, и для элемента управления Data необходимо установить свойство RecordSetType в 1-DynaSet.
6 . Теперь откорректируйте свойства DataSource и DataFields элементов управления, размещенных на форме, чтобы они были связаны с соответствующими полями RecordSet через элемент управления Datal. Для этого необходимо установить их свойство DataSource в значение
Datal, а свойство DataField - в Title, Company Name, Year Published и Author.
7 . Последние два поля на основной форме приложения (Descriptions и Comments) не являются частью запроса All Titles, поэтому удалите их из формы. Можно изменить запрос или создать новый (который содержит эти поля), основанный на запросе All Titles.
8 . Удалите весь код в приложении: он больше не нужен.
В действительности, SQL-оператор выполняет функции кода приложения, но этот подход компактнее и эффективнее.
Проектирование иерархии объектов
Command
Проект, называющийся DataRep, находится в папке этой главы на компакт-диске. В этом параграфе созданы несколько объектов Command, организованных в иерархическую структуру. Названия всех компаний содержатся в таблице Customers. Найдем для каждой компании выписанные ею счета и общее их количество. А для каждого счета - его подробное описание и итоги. Отобразим иерархию записей с помощью элемента управления Grid (элемент управления типа MSHFlexGrid). Элемент управления MSHFlexGrid похож на элемент управления MSFlexGrid, однако предназначен для использования с базами данных и с иерархией элементов управления Command.
Первая колонка содержит имена компаний, вторая — количество счетов для каждой компании, третья - итоговую сумму по всем счетам компании. Последующие колонки должны показывать номер счета, дату заказа и сумму заказа. На рис. 18.2 представлены данные, отображаемые в элементе управления MSHFlexGrid. Обратите внимание, что детали некоторых из заказчиков скрыты. Символ плюса перед именем заказчика означает, что строки с деталями могут быть раскрыты.
Рис. 18.2. Иерархия объектов Command (заказчики-счета-сумма), отображаемые в элементе управления FlexGnd
Выполните следующие действия.
1 . Откройте новый Data-проект и создайте объект Connection для базы NWIND, как показано в последнем параграфе.
2 . Добавьте новый объект Command (Commandl), откройте диалоговое окно его свойств (щелкните правой кнопкой на имени Commandl и выберите Properties).
3 . В окне Properties объекта Commandl установите значение свойства Connection в Connection 1 и выберите Source of Data (Источник данных).
Имена компаний приведены в таблице Customers базы данных NWIND, поэтому выберите строку Table в списке Database Object и Customers - в списке Object Name. После выбора Table в первом раскрывающемся списке появятся имена всех таблиц.
Мы хотим получить счета каждого заказчика. Это означает, что необходимо создать новый объект Command, который будет принадлежать уже созданному объекту Commandl, те будет дочерним для объекта Commandl. Commandl содержит данные о заказчиках, а дочерний объект — счета заказчиков.
4 . Щелкните правой кнопкой в окне DataEnvironment на объекте Commandl и выберите из контекстного меню команду Child.
Новый объект Command будет назван Command2. Так как Command2 — это дочерний объект Command1, то для него выполняется точно такое же подключение, как и для объекта Command1. Поэтому окно Connection недоступно. Дочерний объект Command не может иметь собственного подключения. В нашем случае дочерний объект Command возвращает счета из таблицы Orders.
5 . Выберите строку Table в списке Database Object и укажите Orders — в списке Object Name.
Так как Command2 — это дочерний объект, то необходимо установить связь (relation) с его с родительским объектом.
6 . Переключитесь на вкладку Relation диалогового окна Properties объекта Command2 и выберите Command 1 в качестве родительского объекта в пункте Parent Command (рис. 18.3).
Отношения между объектами определены. Таблицы Customers и Orders используют поле CustomerID в качестве связующего.
7 . Выберите значение CustomerID в списках ParentFields и Child Fields/Parameters и щелкните на кнопке Add. В текстовом поле внизу будет показана связь поля CustomerID таблицы Customers с полем CustomerID таблицы Orders.
Добавьте следующий дочерний объект Command, принадлежащий Command2.
Рис. 18.3. Вкладка Relationship: определение отношении между дочерними и родительскими объектами Command
8 . Щелкните правой кнопкой на объекте Command2 в окне DataEnvironmentI, выберите команду Child и откройте диалоговое окно Properties для нового объекта Command.
Новый объект Command будет возвращать сумму для каждого счета. Сумма не хранится в таблице базы данных NWIND. Она вычисляется с использованием SQL-оператора. Так как сумма счета часто пересчитывается, то в качестве источника данных следует выбрать View (Просмотр). Это эквивалентно тому, что значение OrderSubtotals будет вычисляться с помощью SQL-оператора всякий раз, когда это требуется. Результатом этого вычисления будет набор записей, как если бы источником данных была таблица. Разумеется, значения, представленные как View, не могут редактироваться.
9 . Выберите View в списке Database Object, а в списке Object Name укажите Ок. Subtotals
Диалоговое окно свойств объекта Commands должно выглядеть так, как показано на рис. 18.4.
Следующая задача - добавление отношений между объектом
Commands и его родительским объектом Command2. Для этого выполните следующие действия.
1 . На вкладке Relation определите Command2 в качестве родительского объекта и выберите поле OrederID в обоих списках области Relationship Definition (рис. 18.5).
2 . Чтобы добавить отношение, щелкните на кнопке Add.
Мы создали иерархию объектов Command: суммы счетов были подключены к группам счетов, которые, в свою очередь, подключены к заказчикам. Зададим способ подведения итогов. Сумма (или итог) обычно задается вначале определения дочернего объекта. Выполните следующие действия.
1 . В диалоговом окне Command2 выберите вкладку Aggregates (Итоги).
2 . Создайте новый итог и назовите его Order Total (щелкните на кнопке Add и укажите Order Total в приглашении ввода имени нового итога).
3 . Для вычисления суммы используется функция SUM, поэтому выберите Sum в списке Function Нам необходимо добавить сумму всех счетов к объекту Commands, который хранит все детали счетов.
4 . Выберите объект Commands в списке Aggregate On и имя Subtotal в списке Field.
Рис. 18.4. Источник данных объекта Command3
OrderTotal — это имя итогового значения, вычисляемого для каждого счета. Это значение содержит суммы по всем счетам, выбранным с помощью элемента управления Command2 (рис. 18.6). По отношению к элементу Command2, OrderTotal – одно из полей его набора записей (RecordSet).
Рис. 18.5. Отношение объекта Commands к родительскому объекту
Рис. 18.6. Вкладка Aggregates объекта Command2
Задайте способ подведения итогов для объекта Command 1. Выполните следующие действия.
1 . Откройте диалоговое окно свойств Command 1 и выберите вкладку Aggregates.
2 . Добавьте новый итог и назовите его TotalOrders. Сумма TotalOrders — количество счетов на каждого заказчика.
3 . Выберите Count в списке функций (необходимо посчитать количество счетов, а не их сумму), a Command2 в списке Aggregates и укажите OrderID в списке Field.
Итог TotalOrders вычисляет количество всех счетов в RecordSet объекта Comnnand2 для каждого заказчика. На рис. 18.7 показано задание способа вычисления первого итога объекта Command 1.
Рис. 18.7. Закладка Aggregates объекта Command 1
Вычислите полный итог по всем счетам для каждого заказчика. Выполните следующие действия.
1 . Добавьте новый итог с именем CustomerTotal.
2 . На этот раз необходимо добавить частичный итог для всех счетов. Для этого выберите функцию SUM, затем в списке Aggregate On - Command2, и в списке Field - OrderTotal.
OrderTotal — это еще один итог, определенный для объекта Command2. По отношению к объекту Objecti, OrderTotal является одним из его полей. После определения всех итогов окно DataEnvironmentI конструктора ActiveX выглядит так, как показано на рисунке 18.8. С помощью вертикальной полосы прокрутки можно увидеть итоги для каждого из объектов — они находятся под соответствующими объектами Command.
Рис. 18.8. Окно DataEnvironment после определения всех итогов
Мы построили объекты Command, которые возвращают нужные записи из базы данных, и определили отношения между ними. Теперь нужно вывести данные на форму. Способы вывода данных на форму описаны в следующих параграфах.
Проектирование с использованием конструктора
ActiveX DataEnvironment
Создадим простое приложение для работы с базами данных с использованием конструктора ActiveX DataEnvironment. Проект Denvl — это простая форма, которая позволяет перемещаться по записям таблицы Customers в базе данных NWIND. Для разработки формы, показанной на рис. 18.1, нужно выполнить подключение к базе данных NWIND, затем получить данные из таблицы Customers и отобразить их в элементах управления, связанных с данными.
Для этого необходимо выполнить следующие действия.
1 . Открыть новый проект и в окне типа проекта выбрать Data Project.
2 . Выполнить двойной щелчок на объекте DataEnvironmentI в проводнике проекта, для того чтобы открыть окно DataEnvironment.
Рис. 18.1. Проект Denv1: основы использования конструктора элементов ActiveX DataEnvironment
Окно приложения DataEnvironment содержит объект
Connection и один или больше объектов Commandю Папка Commands пуста, но она будет заполнена позже при создании объектов Commandю
3 . Щелкните правой кнопкой мыши на объекте Connection 1 и выберите Properties из контекстного меню, чтобы открыть окно Data Link Properties. Используйте вкладки в этом окне для задания базы данных, к которой нужно подключиться.
4 . На вкладке Provider выберите драйвер связи между приложением и базой данных.
Большинство баз данных использует OLE DB-провайдер, являющийся для баз данных тем же, чем является OLE для других приложений. Выберите Microsoft OLE DB-Provider. Это простейший провайдер, который подключает приложение к базам данных Microsoft Access.
5 . Выберите вкладку Connection.
6 . Щелкните на кнопке с многоточием, чтобы указать путь к базе данных NWIND (в папке VB98).
7 . Щелкните на кнопке Test Connection, чтобы убедиться в том, что подключение работает.
8 . Если база данных требует указания имени пользователя и пароля, то будет выдано приглашение для их ввода. Введите ту же информацию в соответст вующие редактируемые поля вкладки Connection.
9 . Выберите вкладку Advanced, чтобы выбрать способ открытия базы данных и опции доступа к ней для других пользователей.
6 . Щелкните на кнопке ОК, чтобы перейти к окну DataEnvironmentI, в котором информация представлена в виде дерева.
7 . Нажмите на знаке плюс перед объектом Command 1, чтобы отобразить имена полей таблицы Customers.
8 . Выберите форму проекта (если вы не переименовывали ее, то это Form1).
9 . Перетащите на форму объект Command 1 из окна DataEnvironmentI. Visual Basic создаст столько пар "метка-текстовое поле", сколько понадобится для отображения всех полей объекта Command 1. Если вы не хотите, чтобы были показаны все поля, перетащите только выделенные поля.
10 . Выберите форму и разместите на ней элементы управления. В этой форме отсутствуют кнопки навигации. Разместите четыре кнопки на форме (см. рис. 18.1) и введите следующие команды для их событий Click.
Программа 18.1. Программирование кнопок навигации
Private Sub Commandl_Click ()
DataEnvironment1.rsCommand1.MoveFirst
End Sub
Private Sub Command2_Click()
If DataEnvironment1.rsCommand1.BOF Then
Beep
Else
DataEnvironment1.rsCommand1.MovePrevious
If DataEnvironment1.rsCommand1.BOF Then
DataEnvironment1.rsCommand1.MoveFirst
End If
End If
End Sub
Private Sub Command3_Click()
If DataEnvironment1.rsCommand1.EOF Then
Beep
Else
DataEnvironment1.rsCommand1.MoveNext
If DataEnvironment1.rsCommand1.EOF Then
DataEnvironment1.rsCommand1.MoveLast
End If
End If
End Sub
Private Sub Command4_Click ()
DataEnvironment1.rsCommand1.MoveLast
End Sub
Если вы прочитали предыдущую главу, то вам должен быть понятен этот код. Объект DataEnvironmentI предоставляет набор данных rsCommandl типа RecordSet, который содержит записи, извлеченные из таблицы Customers объектом Command 1. Имя набору данных назначается автоматически в соответствии с именем объекта Command (с префиксом "rs"). Объект DataEnvironmentI.rsCommandl — это набор данных, который поддерживает большую часть методов и свойств объекта DAO.
Для перемещения по записям используются методы Move (MoveFirst, MoveNext, MovePrevious и MoveLast). Чтобы предотвратить перемещение к несуществующей записи (перед первой или после последней), проверьте свойства BOF и EOF набора данных rsCommand 1. Совет
Информация о свойствах EOF и BOF и об их использовании методами приведена в гл. 17.
Используя конструктор ActiveX DataEnvironment и несколько строк кода, можно разработать форму, способную перемещаться по набору записей. Этот пример не производит должного впечатления. Используя элемент управления Data это можно сделать гораздо быстрее. В следующем примере создается более сложный объект Command способом комбинирования трех таблиц из одной и той же базы данных (и все внутри конструктора ActiveX DataEnvironment) без единой строки кода.
Программирование операции перетаскивания для вставки объектов
OLE-операции Drag-and-Drop (Перетащить-и-опустить) удобнее задавать в тексте программы, а не определять автоматически. Проект OLEDDMAN (папка OLEDD на компакт-диске) имеет тот же интерфейс, что и проект OLEDDAUTO, но в нем установлено значение Manual свойства OLEDropMode. Значение своиства OLEDragMode элемента управления TextBox установлено в Automatic, поэтому для инициализации операции писать программу не требуется. То же относится и к элементам управления RichTextBox и PictureBox.
Каждый из элементов управления определяет, когда на него опущен объект, и реагирует соответствующим образом. Рассмотрим самый простой элемент управления — TextBox. Когда на него опущен объект, происходит событие OLEDragDrop, эквивалентное событию DragDrop. Событие OLEDragDrop определяется следующим образом:
Private Sub Textl_OLEDragDrop^(Data As Data0b]ect, _
Effect As Long, Button As Integer, Shift As Integer, _
x As Single, у As Single)
Data - это переменная, описывающая объект, который был опущен. Эта переменная имеет несколько свойств для доступа к объекту (они рассматриваются вкратце). Effect — константа, которая определяет тип перемещения (операция Move или Copy). Параметр Button
описывает кнопку, щелчок на которой инициализирует операцию помещения объекта; параметр Shift
содержит информацию о состоянии клавиш управления Shift, Alt и Ctrl. Последние два параметра - координаты точки, в которую помещается скопированный или перемещенный объект.
Методы, применяемые при работе с объектами типа Data подобны методам, используемым при работе с буфером обмена Clipboard. Метод GetFormat позволяет определить формат данных. При этом он не возвращает тип данных. При его вызове необходимо указывать предполагаемый тип данных, и если он соответствует указанному, то возвращается значение True, в противном случае — False. Чтобы выяснить, содержит ли объект Data текст, следует воспользоваться следующим оператором If:
If Data.GetFormat(vbCFText) Then
{обработка текста}
End If
(Константы, описывающие различные типы данных, точно такие же, как и используемые при работе с буфером обмена.)
Чтобы получить сами данные, следует использовать метод GetData. Этот метод возвращает объект, который должен быть присвоен соответствующей переменой. Если данные являются текстом, можно присвоить значение, возвращенное методом GetData, свойству Text элемента управления TextBox. Если данные — растровое изображение, то можно присвоить их свойству Picture того элемента управления, который может выводить изображение.
Синтаксис метода GetData имеет вид:
Data.GetData(format)
где
formal — константа, которая определяет желаемый формат данных. Один и тот же объект может иметь различные форматы. Выделив абзац из документа Word, можно поместить его в окно элемента управления TextBox как текст, а в окно элемента управления RichTextBox - как сформатированный текст. Данные как таковые могут быть восстановлены во множественных форматах, в зависимости от возможностей элемента-получателя. Метод EditCopy элемента управления Graph работает точно так же (рассматривается в Приложении В "The MSChart Control" ("Элемент управления MSChart")). Он копирует текущее изображение из окна элемента управления Graph. Эти данные могут быть вставлены либо как растровое изображение в рабочее окно графического редактора, или как текст — в окно текстового редактора.
Если пользователь поместил один или несколько файлов на элемент управления (значение выражения GetFotmat(vbCFFiles)
равно True), можно воспользоваться семейством Files объекта Data, чтобы получить названия этих файлов:
If Data.GetFormat(vbCFFiles) Then
For i = 1 To Data.Files.Count
{обработка файла Data.Files(i)) }
Next
End If
Ниже приводится текст обработчика OLE — операции перетащить-и-опустить для окна элемента управления TextBox:
Private Sub Textl_OLEDragDrop(Data As Data0b]ect, _
Effect As Long, Button As Integer, Shift As Integer, _
x As Single, у As Single)
Dim pie As Picture
If Data GetFormat(vbCFFlles) Then
Text1.Text "You dropped the following files " & vbCrLf
' (Вы поместили следующие файлы)
For i = 1 To Data Files Count
Textl.Text = Textl Text & Data.Files(i) & vbCrLf
Next
End If
If Data.GetFormat(vbCFRTF) Then
Text1.Text = Data.GetData(vbCFText)
End If
If Data GetFormat(vbCFBitmap) Then
imgWidth = Round(ScaleX(Data GetData _
(vbCFBitmap).Width, vbHimetric, vbPixels))
imgHeight - Round(ScaleY(Data GetData _
(vbCFBitmap) Height, vbHimetric, vbPixels))
Textl.Text = " You dropped an image with the folowing _
specifications:" & vbCrLf
' (Вы поместили изображение со следующими параметрами:)
Text1.Text = Textl.Text & "WIDTH " & imgWidth & vbCrLf
Text1.Text = Textl.Text & "HEIGHT " & imgHeight
End If
Если поместить один или несколько файлов в окно элемента управления TextBox, то будут перечислены их имена. Если вы перетащили текст из элемента управления RichTextBox, то этот же самый текст появится в окне элемента TextBox не отформатированным. И, наконец, если поместить в TextBox изображение из элемента управления PictureBox, то будут выведены характеристики изображения. Следует обратить внимание на то, как программа передает размеры изображения. Объект, полученный в результате применения метода GetData, является объектом типа Picture, следовательно, можно обратиться к его свойствам Width и Height, чтобы получить значения размеров объекта.
Текст обработчика события OLEDragDrop элемента управления RichTextBox напоминает фрагмент, приведенный выше. Однако элемент управления RichTextBox воспринимает большее количество типов данных и реагирует на них по-разному Можно открыть соответствующий проект в Visual Basic и исследовать текст программы. Если попытаться поместить изображение в окно элемента управления RichTextBox, то в результате будет получено сообщение об ошибке. Следующий фрагмента программы должен бы выполнить вставку растрового изображения в RichTextBox, но этого не происходит. Во время выполнения программы вместо перемещения изображения выдается сообщение об ошибке.
If Data.GetFormat(vbCFBitmap) Or Data.GetFormat(vbCFDIB) Then
RichTextBox1.OLEObjects.Add, , Data.GetData(vbCFDIB)
GoTo PasteDone
End If
Единственный выход из данной ситуации который можно предложить - на мгновение переключить свойство OLEDropMode элемента управления RichTextBox в состояние Automatic, а затем вернуть его в состояние Manual. Первое действие должно происходить в обработчике события OLEStartDrag элемента управления PictureBox.
Private Sub Picture1_OLEStartDrag(Data As Data0bject, _
AllowedEffects As Long)
RichTextBox1.OLEDropMode = rtfOLEDropAutomatic
End Sub
После того как операция переноса завершена можно установить исходное значение свойства OLEDropMode элемента управления. Это действие должно выполняться в обработчике события OLECompleteDrag элемента управления TextBox, которое сигнализирует об окончании OLE-операции перетащить-и-опустить:
Private Sub Picture1.OLECopmpleteDrag(Effect As Long)
RichTextBox1.OLEDropMode = rtfOLEDropManual
End Sub
OLE-операции перетащить и-опустить аналогичны обычным операциям такого типа но они могут быть несколько более сложными из-за разнообразия объектов, которые могут переносить. Получатель (элемент управления) должен быть в состоянии распознать тип переносимого объекта, чтобы обработать его. Способность обнаруживать перемещение файлов на форму Visual Basic означает, что вы можете создавать приложения, которые способны взаимодействовать с рабочим столом (получать файлы, помещенные пользователем, обрабатывать их, перемещать их в различные папки и т. п.). OLE операции перетащить-и-опустить — очень интересная возможность, которую в дальнейшем, вы можете изучить самостоятельно, обратившись к справочной системе Visual Basic.
Программирование
ADO
Как видно, бескодовое приложение для работы с базами данных, созданное с помощью элемента управления ADO, не такое гибкое и мощное, как приложение, разработанное с использованием элемента управления Data. Для полноценного использования ADO необходимо уметь управлять им с помощью программного кода. В этом параграфе обсуждается объектная модель ADO и показано, как программировать его основные объекты. Оставшаяся часть этой главы посвящена объектам Active Data, даны несколько примеров, демонстрирующих сходство между ADO и DAO.
Простое редактирование и обновление записей
Основное отличие между объектами ADO RecordSet и DAO RecordSet или RDO ResultSets - это отсутствие метода Edit. He надо готовить запись к редактированию. Вместо этого полю присваивается новое значение. Не нужно вызывать метод Update для записи изменений. При перемещении к другой записи изменения автоматически записываются в базу данных.
Другая интересная особенность объекта ADO RecordSet — он позволяет создавать массивы имен полей и значений и использовать их для добавления новых записей. Для добавления новой записи используйте метод AddNew. Пример добавления новой записи к текущему объекту RecordSet (RecSet) с использованием массива и приведен ниже.
RecSet.AddNew Array ("ProductName", "CategoryID", "UnitPrice"),
Array ("Ma's Marmelade", 34, 3.45)
При перемещении к другой записи или вызове метода
RecSet. Update новая запись записывается в базу данных.
Редактировать текущую запись еще проще. Просто назначьте полям новые значения.
RecSet. Fields ("ProductName") = "Ma's Marmelade"
Для обновления нескольких полей в записи также используйте массивов:
RecSet.Update Array ("ProductName", "CategoryID", "UnitPrice"),
Array ("Ma's Marmelade", 34, 3.45)
Методы AddNew и Update принимают в качестве аргументов два массива. Первый содержит имена полей, а второй — их значения.
В последнем параграфе этой главы рассмотрены два примера программирования объектов ADO.
VB6 в действии: проекты AD01 и AD02
На компакт-диске находятся два простых проекта, демонстрирующих некоторые методы и свойства ADO компонентов. Откройте проекты AD01 и AD02 в среде разработки Visual Basic и просмотрите их код. Проект AD01 демонстрирует операции получения и манипулирования записями. Главная форма содержит два списка имен категорий (табл. Categories в базе данных NWIND) и имен товаров в выбранной категории. Когда пользователь выбирает категорию в первом списке, второй список заполняется наименованиями ее товаров.
В первом параграфе главы описываются протоколы, используемые в Web и Internet, рассказывается о тегах HTML и показано, как использовать HTML для создания простых документов с гиперссылками (статические Web-страницы). Далее показано, как активизировать Web-страницы, используя сценарии (scripting) VBScript и элементы управления ActiveX, как преобразовать статическую Web-страницу в интерактивное приложение (это позволит запустить ее через Internet в окне броузера). В конце главы рассмотрено создание Web-страниц, в которых используются стандартные элементы управления ActiveX.
В главе также даны основы построения динамических HTML-страниц (DHTML). DHTML - последняя тенденция в оформлении Web-страниц, переводящая HTML на новый уровень — позволяет Web-разработчикам создавать приложения HTML, аналогичные приложениям рабочего стола, обогащенным эффектами мультимедиа. Это слишком обширная тема для глубокого и подробного изучения, поэтому мы рассмотрим лишь принципы создания DHTML. Относительно Web, основное внимание уделено нескольким темам, посвященным работе Web и разработке Web-страницы как приложения. Описана роль VBScript в программировании Web-страниц. В следующих главах приведена специфическая информация о сочетании авторских технологий VB и Web в Web- и VB-приложениях. Мы научимся отображать страницы HTML на формы Visual Basic и использовать модели Web с гиперссылками в VB-приложениях.
Intranet является органичной частью Web
Материал этой главы полезен не только при выпуске документов в Internet, но и при построении Intranet-приложений.
Широкое распространение Web — доказательство того, что он действительно прост в использовании. Средства работы с ним становятся составной частью операционных систем, и рабочий стол Windows 98 напоминает Web-броузер.
Если Web-технология позволяет упростить такую хаотичную структуру как Internet, то почему бы не использовать ее в локальных сетях? Многие локальные сети спроектированы как миниатюрные Internet. Intranet или корпоративная Internet — это локальная сеть, использующая технологию Internet. Для упрощения операций в Intranet можно использовать Web-модель, не запуская конкретную Web-страницу, и без ограничений в виде платы за модемную связь. Intranet, как и
Internet, работает с протоколом TCP/IP, но не является глобальной сетью. Пользователи Intranet сети - работники корпорации, университета или другой организации. Эта сеть не доступна пользователям извне. В отличие от World Wide Web, Intranet-сеть имеет один сервер. Он поддерживает все документы, запрашиваемые клиентами.
Во многих корпорациях
Intranet используется для предоставления информации служащим, а Web-узел — внешним пользователям. Использование технологии, которая сделала Web столь популярным, позволяет создавать локальные корпоративные сети. Но основная особенность корпоративной Intranet заключается не столько в использовании протокола связи TCP/IP, сколько в использовании протокола HTTP (HyperText Transfer Protocol — протокол передачи гипертекста).
Проверка корректности данных
Из первого примера главы видно, что элемент управления Data может использоваться для редактирования записей. Однако приложения баз данных должны проверять правильность (validating) данных пользователем перед их сохранением в базе. Элемент управления Data предоставляет несколько событий и методов для проверки правильности вводимых данных перед их сохранением в базе.
Проверка орфографии документов
Одна из наиболее полезных функции Word — способность к орфографической проверке документов. Эту же возможность Word предоставляет объектам VBA, и ее можно использовать в приложениях, созданных в Visual Basic. Сделать это очень просто. Чтобы обратиться к подпрограмме проверки орфографии Word, необходимо определить два объекта семейство ProofReadingErrors и семейство SpellingSiiggestions.
Семейство ProofReadingErrors — это свойство объекта Range Оно содержит слова с орфографической ошибкой в объекте Range. Чтобы вызвать Word для орфографической проверки фрагмента текста и расширить семейство ProofReadingErrors, следует вызвать метод SpellmgErrors объекта Range. Этот метод возвращает результат, который должен быть сохранен в объектной переменной типа ProofreadingErrors:
Dim SpellCollection As ProofreadingErrors
Set SpellCollection = DRange SpellingErrors
DRange — это объект типа Range (абзац или весь документ). Вторая строка заполняет переменную SpellCollection словами с орфографическими ошибками. После этого можно организовать цикл типа For Each Next, чтобы прочитать слова из указанного семейства.
Помимо отыскания и выделения орфографических ошибок,
Word может также предлагать список альтернативных вариантов написания или список слов, которые звучат подобно ошибочно написанному слову. Чтобы найти список альтернативных вариантов написания слов, следует вызвать метод GetSpellmgSuggestions
объекта Application, передавая ему слово с орфографической ошибкой в качестве параметра. Обратите внимание, что это метод объекта Application, а не проверяемого объекта Range. Результаты, возвращенные методом GetSpellmgSuggestions, должны быть сохранены в аналогичной объектной переменной, которая была объявлена как переменная типа SpellingSuggestions:
Dim CorrectionsCollection As SpellingSuggestions
Set CorrectionsCollection = _
AppWord.GetSpellmgSuggestions ("antroid")
Оператор, находящийся во второй строке, организует доступ к списку предлагаемых вариантов для слова antroid.
Чтобы просмотреть список предложенных слов, следует предусмотреть цикл получения всех элементов семейства CorrectionsCollection. Пример, приведенный в следующем параграфе, демонстрирует использование обоих методов в приложении Visual Basic.
VB6 в действии: проект SpellDoc
SpellDoc — это приложение, в котором используются методы Word для орфографической проверки документа. Приложение SpellDoc можно найти в папке, посвященной этой главе на компакт-диске. Главная форма приложения, показанная на рис. 14.15, содержит окно элемента управления TextBox, в которое пользователь может вводить некоторый текст (или вставлять текст из другого приложения) и выполнять его орфографическую проверку, щелкая на кнопке Spell Check Document.
Рис. 14.15. Главная форма приложения SpellDoc
Приложение обратится к Word и запросит список слов с орфографическими ошибками Этот список будет отображаться в окне другой формы (рис. 14.16). В окне элемента управления ListBox, расположенном слева, приводится список всех слов с орфографическими ошибками, которые Word обнаружил в тексте. Но Word не только составляет список слов, содержащих орфографические ошибки, но и предлагает возможные варианты их замены. Чтобы просмотреть список альтернативных вариантов написания определенного слова, следует с помощью мыши выбрать слово в левом списке
Рис. 14.16. Эта форма приложения SpellDoc отображает слова с орфографической ошибкой и возможные варианты замены
Чтобы заменить все вхождения выделенного слова (с орфографической ошибкой) на выбранный вариант, следует щелкнуть на кнопке
Replace (Замена). Можно разработать собственный интерфейс, предоставляющий пользователю возможность выбора, количества и вида вхождений слов с орфографической ошибкой, которые будут заменены.
В программе используются три глобальные переменные, которые объявлены следующим образом:
Public AppWord As Application
Public CorrectionsCollection As SpellingSuggestions
Public SpellCollection As ProofreadingErrors
Переменная
SpellCollection
описывает семейство, содержащее все слова с орфографическими ошибками, а переменная CorrectionsCollection - семейство, содержащее предложенные программой проверки орфографии варианты замены для определенного слова. Значение переменной CorrectionsCollection присваивается каждый раз, когда пользователь выбирает другое слово с орфографической ошибкой в окне Spelling Suggestions (см. рис. 14.16).
После выполнения щелчка на кнопке Spell Check Document программа обращается к приложению Word. Сначала с помощью функции Get0bject() программа пытается соединиться с запущенным экземпляром Word. Если в настоящее время нет ни одного запущенного экземпляра Word, запускается новый экземпляр. Это выполняет следующий фрагмент программы.
Программа 14.12. Обращение к Word
Set AppWord = Get0bject ("Word Application")
If AppWord Is Nothing Then
Set AppWord = CreateObject ("Word.Application")
If AppWord Is Nothing Then
MsgBox "Could not start Word Application will end"
' (Невозможно открыть Word Работа приложения
' будет прекращена)
End
End If
End If
После того как связь с Word установлена, программа создает новый документ и с помощью метода InsertAfter объекта Range копирует содержимое окна элемента управления TextBox в новый документ. Это выполняется следующим образом:
AppWard.Documents.Add
DRange.InsertAfter Textl.Text
Теперь VB-программа вызывает метод SpellingErrors объекта Range, который возвращает семейство объектов Word. Результат метода SpellingErrors присваивается объектной переменной SpellCollection:
Set SpellCollection = DRange.SpellingErrors
Приведенный ниже фрагмент программы добавляет слова, содержащиеся в переменной SpellCollection, к левому списку второй формы и отображает эту форму.
Программа 14.13. Кнопка Check Document
Private Sub Command1_C1ick()
Dim DRange As Range
Me.Caption = "starting word "
' (начальное слово)
On Error Resume Next
Set AppWord = Get0bject ("Word.Application")
If AppWord Is Nothing Then
Set AppWord = CreateObject ("Word.Application")
If AppWord Is Nothing Then
MsgBox " Could not start Word. Application will end"
'(Запустить Word невозможно. Приложение будет закрыто) End
End If
End If
On Error GoTo ErrorHandler
AppWord.Documents.Add
Me Caption = "checking words... "
'(проверка слов... )
Set DRange = AppWord.ActiveDocument.Range
DRange.InsertAfter Text1.Text
Set SpellColiection = DRange.SpellingErrors
If SpellColiection.Count > 0 Then
SuggestionsForm.List1.Clear
SuggestionsForm.List2.Clear
For iWord = 1 To SpellColiection.Count
SuggestionsForm!List1.Addltem _
SpellColiection.Item(iWord)
Next
End If
Me.Caption = "Word VBA Example"
SuggestionsForm.Show
Exit Sub
ErrorHandler:
MsgBox "The following error occured during the document's _
spelling"& vbCrLf & Err.Description
' (Во время проверки обнаружена следующая ошибка ...)
End Sub
Во второй форме приложения основное внимание сконцентрировано в Word на обработке события Click в окне Words in Question. Каждый раз, когда выполняется щелчок на элементе списка в левом окне ListBox, программа вызывает метод GetSpellingSuggestions
объекта AppWord, передавая выбранное слово в качестве параметра. Обратите внимание, что к значению свойства Listlndex объекта List прибавляется 1, чтобы отобразить тот факт, что индексация элементов семейства начинается с 1, в то время как индексация элементов окна списка ListBox начинается с 0. Метод GetSpellingSuggestions возвращает другое семейство, содержащее предложенные слова, которые помещены во второе (правое) окно элемента управления ListBox, помещенное на форме с помощью следующего фрагмента.
Программа 14.14. Обработчик события
Click в окне списка
Private Sub Listl_Click()
Screen.MousePointer = vbHourglass
Set CorrectionsCollection = _
AppWord.GetSpellingSuggestions(SpellColiection.Item _
(List1.ListIndex + 1))
List2.Clear
For iSuggWord = 1 To CorrectionsCollection.Count
List2.AddltemCorrectionsCollection.Item(iSuggWord)
Next
Screen MousePointer = vbDefault
End Sub
Приложение Spell Doc может стать отправной точкой для создания средствами Visual Basic различных пользовательских приложении, в которых требуется проверка правильности написания, но не требуются мощные средства редактирования. В некоторых случаях может потребоваться настройка проверки правописания, хотя такая ситуация встречается достаточно редко. Например, в приложении, обрабатывающем почтовые отправления, может потребоваться выполнение орфографической проверки, позволяющей исключить неправильно введенные адреса. В этом случае сначала следует организовать просмотр списка слов, возвращенных методом SpellingErrors, проверить, содержатся ли в словах специальные символы, и удалить их.
Теперь вполне очевидно, что внести изменения в Office-приложения совсем несложно. Познакомившись с объектами этих приложений, можно установить с ними связь, управляя некоторыми свойствами и вызывая методы этих объектов.
Работа с графическими объектами
Графические объекты являются важной частью любого приложения. Графическим объектом может быть и простой значок, и сложное растровое изображение. В параграфе рассмотрены некоторые методы вывода графических изображений с помощью API-функций. Рассмотрены функции BitBlt() и StretchBlt(), в определенном смысле эквивалентные методу PaintPicture в Visual Basic. Основное различие между ними заключается в том, что метод PaintPicture можно применять только к определенному объекту (элементу управления PictureBox или форме), а с помощью функций BitBltQ и StretchBltQ можно выполнять копирование пикселей изображения в пределах рабочего стола. Их можно использовать для создания разнообразных приложений, например программ копирования экрана, чего не позволяет метод PaintPicture.
Работа с объектом
RecordSet
Если создан объект RecordSet, то можно получить доступ к записям и их полям с помощью нескольких методов и свойств, идентичных методам и свойствам объекта RecordSet DAO. Количество возвращенных записей хранится в свойстве RecordCount, принимающем правильное значение только при перемещении на последнюю запись. Для RecordSet типа Forward-Only нельзя просто получить количество записей. Необходимо просканировать и обработать их все. При иных типах RecordSet можно переместиться с помощью метода MoveLast на последнюю запись, а затем вернуться к первой записи, используя метод MoveFirst. После этого для получения количества строк в объекте RecordSet можно использовать свойство RecordCount. Конечно, этот метод не будет работать с RecordSet типа Forward-Only.
Доступ к индивидуальным значениям полей в строке получают с помощью семейства Fields. Количество колонок в объекте RecordSet находится в свойстве Fields Count. К каждому из полей в текущей строке можно адресоваться с помощью индекса (это порядковый номер поля в SQL-выражении) или по его имени. Например, если используется SQL-выражение,
SELECT ProductName, ProductID FROM Products
то можно получить доступ к именам товаров в текущей записи с помощью выражений двух видов:
RecSet.Fields(0).Value
или
RecSet.Fields ("ProductName") .Value
(Можно опустить Value, как свойство, установленное по умолчанию для семейства Fields.)
Для сканирования объекта RecordSet используйте методы Move (MoveFirst, MoveLast, MovePrevious и MoveNext). В дополнение к методам навигации, объект RecordSet содержит метод AbsolutePosition,
который указывает на позицию текущей записи в объекте RecordSet.
Для сканирования RecordSet можно использовать цикл:
For Each rec In RecSet
{обработка текущей записи}
Next
или следующий фрагмент с циклом For...Next
RecSet.MoveLast
AllRecs = RecSet.RecordCount
RecSet.Move First
For i = 1 To AllRecs
{обработка текущей записи}
RecSet.MoveNext
Next
Похожий цикл используется для сканирования колонок
RecordSet. Имена полей получают с помощью свойства Fields(i).Name. Следующий цикл предназначен для печати имен колонок в наборе записей RecSet.
For Each fld In RecSet.Fields
Debug.Print fld.Name
Next
Можно отсортировать RecordSet в соответствии со значениями полей или отфильтровать их, чтобы отобрать записи, отвечающие определенному критерию. Извлекать рекомендуется только нужные записи в желаемом порядке. Когда это невозможно (или когда создан клиентский RecordSet и необходимо применять разные методы обработки разных записей), то используются свойства Sort и Filter объекта RecordSet.
Свойство Sort принимает в качестве аргумента имя поля, в соответствии с которым необходимо отсортировать RecordSet. Предположим, создан объект RecordSet с именами заказчиков из базы данных NWIND, и необходимо отсортировать их в соответствии с полем Country. Установите свойство Sort.
RSCustomers.Sort = "Country ASCENDING"
Для фильтрации выбранных записей в RecordSet используйте следующее выражение.
RSCustomers.Filter = "Country = 'Germany' "
RSCustomers. Filter — не метод, и он не возвращает RecordSet. А метод Move будет игнорировать записи, у которых значение поля Country не Germany.
Работа с
ADO
Чтобы использовать ADO в приложении, добавьте ссылку на библиотеку ADO Object в диалоговом окне References. Выполните следующие действия.
1 . Откройте меню Project
2 . Выберите References меню Project, чтобы открыть диалоговое окно References.
3 . Отметьте опцию Microsoft ActiveX Data Object 2.0 Library
После того как библиотека ADO добавлена в проект, просмотрите состав библиотеки с помощью Object Browser. Если вы знакомы с Remote Data Objects (RDO) из Visual Basic 5, то заметите, что основные объекты, предлагаемые моделью объектов ADO, похожи на RDO, включая процесс доступа к базе данных. Необходимо произвести подключение, а затем выполнить SQL-выражение или сохраненную процедуру базы данных и обработать результаты запроса, возвращаемые объектом RecordSet. В следующем параграфе этот процесс рассмотрен подробно.
Размещение одного окна поверх других
Часто приходится сталкиваться с приложениями, которые размещают свое окно поверх окон других приложений независимо от того. какое именно из них является активным. Примером такого окна может служить окно Find (Найти) редактора Microsoft Word. Чтобы предусмотреть такую возможность, воспользуйтесь API-функцией SetWindowPos().
Private Declare Function SetWindowPos Lib "user32" _
(ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _
ByVal x As Long, ByVal у As Long, _
ByVal ex As Long, ByVal cy As Long, _
ByVal wFlags As Long) As Long
Параметр
hWnd — дескриптор окна, х и у — координаты левого верхнего угла окна, сх и су — ширина и высота окна соответственно. Параметр h WndInsertAfter — дескриптор окна, после которого окно hWnd
находится в списке окон. Параметр hWnd
может принимать одно из значений, указанных в табл. 13.5.
Таблица 13.5. Значения параметра hWnd
Значение
Расположение окна
HWND_BOTTOM HWND_TOP HWND_TOPMOST
HWND_NOTOPMOST
Внизу списка окон
Поверх всех окон
Наверху списка окон
Наверху списка окон, под самым верхним окном
Параметр wFlags является целочисленной константой, содержащей один или несколько флагов, приведенных в табл. 13.6.
Таблица 13.6. Флаги, составляющие параметр wFlags
Флаг
Действие
SWP_DRAWFRAME
Рисует рамку окна
SWP_HIDEWINDOW
Скрывает окно
SWP_NOACTIVATE
Делает окно неактивным
SWP_JMOMOVE
Сохраняет координаты текущего положения окна (параметры х и у игнорируются)
SWP_NOREDRAW
Запрещает автоматическую перерисовку содержимого
окна
SWP_NOSIZE
Сохраняет данные о текущем размере окна
SWP_NOZORDER
Сохраняет текущее положение окна в списке других
окон
SWP_SHOWWINDOW
Отображает окно
Совет
Можно скопировать значения констант из окна API Viewer непосредственно в ваше приложение. Избегайте задания числовых констант в вашем коде.
Текст программы типичного приложения WinTop, демонстрирующего использование функции SetWindowPos(), приведен ниже.
Программа 13.9. Приложение WinTop
Option Explicit
Private Declare Function SetWindowPos Lib "user32" _
(ByVal hwnd As Long, ByVal hWndInsertAfter As Long,_
ByVal x As Long, ByVal у As Long,
ByVal ex As Long, ByVal cy As Long,
ByVal wFlags As Long) As Long
Const HWND_TOPMOST = -1
Const SWP_SHOWWINDOW = &H40
Private Sub Form_Load()
Dim retValue As Long
retValue = SetWindowPos(Me.hwnd, HWND_TOPMOST,_
Me.CurrentX, Me.CurrentY, 300, 300, SWP_SHOWWINDOW)
End Sub
Эту методику можно использовать для создания окна
Search & Replace (Поиск и замена) в проекте RTFPad (см. гл.9). При этом данное окно будет оставаться расположенным поверх других окон и видимым при переходе в окно формы редактора (рис. 13.7). Для этого вставьте объявление функции SetWmdowPos() и пару констант в модуль
Public Declare Function SetWindowPos Lib "user32" _
(ByVal HWND As Long, ByVal hWndInsertAfter As Long,_
ByVal x As Long, ByVal у As Long, ByVal ex As Long, _
ByVal cy As Long, ByVal wFlags As Long) As Long
Public Const HWND_TOPMOST = -1
Public Const SWP SHOWWINDOW = &H40
Рис. 13.7. Диалоговое окно Search & Replace (Поиск и замена) видимо даже в том случае, когда активным становится другое окно
Кроме того, потребуется изменить программу обработчика события команды меню Find (Найти). Строку
SearchForm Show
замените следующим оператором:
SetWindowPos SearchForm.hwnd, HWND_TOPMOST, _
Me.CurrentX, Me.CurrentY, 470, 155, SWP_SHOWWINDOW
Значения 470 и 155, указанные в программе, являются размерами окна Search & Replace в пикселях. Значение свойства BorderStyle формы Search должно быть установлено в Fixed, тогда пользователь не сможет изменить размер окна.
Реализация семейства свойств
Некоторые компоненты ActiveX предоставляют массив или семейство свойств. Например, элемент ListBox предлагает свойство List, которое является массивом. Пункты элемента ListBox сохраняются в массиве List, который является свойством этого компонента и к ним можно обратиться, указав индекс от 0 до ListCount-1. Реализовывать свойство - массив из кода компонента не очень сложно, но должны быть объявлены массив и методы для добавления выбора и удаления элементов массива. Вообще массивы - не самые лучшие структуры для хранения нескольких элементов, потому что неудобно быстро удалить элемент из массива. Чтобы удалить элемент из массива, необходимо переместить все элементы следующие за удаляемым, на одну позицию. Структура которая лучше подходит для этого - объект Collection.
Реализация семейства
Для реализации общедоступного семейства в разрабатываемом компоненте, в объекте Collection надо создать следующие свойства и методы.
• Метод Add. Добавляет новый элемент в семейство.
• Метод Remove. Удаляет элемент из семейства.
• Метод Clear. Удаляет все элементы из семейства.
• Свойство Count. Возвращает количество элементов в семействе.
• Свойство Item. Возвращает заданный элемент семейства.
Чтобы сделать это, вставьте следующее объявление семейства в окне Code модуля класса.
Dim DataCollection As New Collection
Data Collection —
это новая переменная которая может содержать несколько элементов. Затем вставьте определения следующих свойств и методов чтобы разработчик мог управлять семейством (добавлять и удалять элементы из семейства нумеровать их и отыскивать выделенные элементы по их ключу). Свойство Count класса возвращает значение свойства Count семейства.
Программа 15.7. Свойство Count переменной DataCollection
Public Property Get Count() As Long
Count = DataCollection.Count
End Property
Метод Add — это общедоступная функция, которая возвращает значение True, если ее аргументы успешно добавлены в семейство Если при выполнении возни кают ошибки, то метод возвращает False.
Программа 15.8. Метод Add переменной DataCollection
Public Function Add(dValue As Double) As Boolean
On Error GoTo AddError
DataCollection.Add dValue
Add = True
Exit Function
AddError:
Add = False
End Function
Метод Remove — также функция, возвращающая результат типа Boolean. Функция возвращает True, если указанный элемент успешно удален из списка. Кроме того, она генерирует прерывание ошибок выполнения, которое главное приложение может обработать с помощью оператора On Error. Заметьте, что оператор Err.Raise в программном коде 15.9 инициирует ошибку выполнения с номером и ее описанием (обязательно надо добавить константу vbObjectError, чтобы избежать конфликтов со стандартным сообщением об ошибке). Поскольку приложение использует класс — он будет получать стандартную ошибку Visual Basic. Заметьте, что Visual Basic может инициировать свою собственную ошибку 1. Но ошибка 1 существует только для нашего класса, вот почему была добавлена константа vbObjectError.
Программа 15.9. Метод Remove переменной DataCollection
Public Function Remove(index As Long) As Boolean
If index < 0 Or index > DataCollection.Count Then
DataCollection.Remove index
Remove = True
Else
Err Raise vbObiectError + 2, "ClassName", _
"Couldn't remove item"
(... элемент удалить нельзя)
Remove = False
End If
End Function
Синтаксис метода Raise для объекта Err:
Err.Raise number, source, description
где source — имя компонента, в котором появляется ошибка (возможно, что несколько компонентов инициируют одинаковую ошибку). Основное приложение должно знать одновременно номер и источник ошибки, а затем предпринять соответствующие действия (т.е. устранить причину, которая инициировала ошибку или повторить операцию).
Метод Item выбирает указанный элемент из семейства, основываясь на индексе, который служит аргументом. Если индекс выходит за границы семейства, возникает ошибка 2 выполнения.
Программа 15.10. Метод Item переменной DataCollection
Public Function Itemfindex As Long) As Double
If index < 0 Or index > DataCollection.Count Then
Err.Raise vbObjectError + 1, "ClassName", _
"Index out of bounds"
'(Индекс вышел за пределы границ массива)
Else
Item = DataCollection(index)
End If
End Function
Последний метод (Clear) удаляет все элементы из семейства. Поскольку семейство не имеет собственного метода Clear, необходимо удалить все элементы из семей ства с помощью его метода Remove. Заметьте, что обход семейства осуществляет из конца в начало. Прямой обход может вызвать ошибку исполнения, поскольку сразу после удаления первого элемента свойство DataCollection Count становится меньше на единицу, но это изменение не влияет на число итераций.
Программа 15.11. Метод Clear переменной DataCollection
Public Function Clear() As Boolean
On Error GoTo ClearError
For i = DataCollection.Count To 1 Step -1
DataCollection Remove i
Next
Clear = True
Exit Function
]
ClearError:
Clear = False
End Function
VB6 в действии: класс AXStat
Проект класса AXStat демонстрирует процесс создания классов, которые предоставляют семейства. Класс AXStat предоставляет члены стандартного семейства и следующие специальные члены.
• Свойство Average. Возвращает среднее значение из набора данных, который хранится в элементе управления.
• Свойство Min. Возвращает минимальное значение из набора данных.
• Свойство Мах. Возвращает максимальное значение из набора данных.
Специальные свойства достаточно просты и их реализация показана ниже.
Программа 15.12. Специальные члены класса AXStat
Public Property Get Average() As Double
Dim dSum As Double
Dim itm As Long
For itm = 1 To DataCollection.Count
dSum = dSum + DataCollection(itm)
Next
Average =
dSuiti / DataCollection.Count
End Property
Public Property Get Min () As Double
Dim itm As Long
Min = 1E+202
For itm = 1 To DataCollection.Count
If DataCollection(itm) < Min Then _
Min = DataCollection(itm)
Next
End Property
Public Property Get Max() As Double
Dim itm As Long
Max =
-1E+202
For itm =
1 To DataCollection.Count
If DataCollection(itm) > Max Then _
Max = DataCollection(itm)
Next
End Property
Этот код считывает значения данных, которые хранятся в семействе DataCollection, и вычисляет их базовую статистику. Можно использовать процедуру Property Get, чтобы получить более полную статистику, чем показана здесь. Заметьте, что свойства предназначены только для чтения (не имеет смысла устанавливать их значения) и не определены дуальные процедуры Property Let.
Код, который реализует стандартные методы семейства, подобен коду, приведенному ранее в разделе "Реализация семейства". Достаточно просто изменить имя класса в строке, которая инициирует ошибки исполнения.
Тестирование класса AXStat. Тестовый проект для класса AXStat показан на рис. 15.7. Кнопка Create Data Set (Создать набор данных) добавляет 100 случайных чисел к семейству класса. Кнопка Display Data (Отобразить данные) берет данные из класса и показывает их в окне списка. И, наконец, кнопка Show Statistics (Показать статистику) вызывает методы класса для вычисления основных статистических характеристик набора данных и их отображения. Кнопки справа демонстрируют способ обработки ошибок, инициируемых в классе (но к ним вернемся позже).
Для использования класса AXStat в проекте необходимо сначала добавить в проекте ссылку на класс, а затем создать объектную переменную, соответствующую классу. Следующее объявление должно появиться в самом начале окна кода тестовой формы:
Dim STATS As New Statistics
Ключевое слово New
говорит Visual Basic, что необходимо создать новый экземпляр модуля класса Statistics. Первая командная кнопка использует метод Add переменной STATS для создания набора данных из 100 значений.
Программа 15.13. Заполнение объекта STATS случайными данными
Private Sub Command1_C1ick()
List1.Clear
STATS.Clear
For i = 1 То 100
STATS.Add Rnd() * 1000
Next
Command2.Enabled = True
Command3.Enabled = True
End Sub
Рис. 15.7. Тестовая форма класса AXStat
Кнопка Display Data извлекает данные из переменной STATS с помощью метода Item. Значения данных формируются в цикле, который работает в диапазоне от 1 до STATS.Count.
Программа 15.14. Чтение данных из объекта STATS
Private Sub Command2_Click()
Dim i As Long
List1.Clear
For i = 1 To STATS.Count
List1.AddItem Format(STATS.Item(i), "000.000000")
Next
End Sub
Кнопка Show Statistics вызывает методы Average, Min и Мах переменной для вычисления основных статистических характеристик набора данных. Код, соответствующий кнопке Show Statistics, приведен ниже.
Программа 15.15. Использование класса AXStat для вычисления статистических характеристик
Private Sub Command3_Click()
StatsMsg = "There are " & STATS.Count & _
" points in the data set" & vbCrLf
' (В наборе присутствуют ... элементов данных)
StatsMsg = StatsMsg & "Their average is" & _
STATS.Average & vbCrLf
' (Их среднее значение. .)
StatsMsg = StatsMsg & "The smallest value" & STATS.Mm & vbCrLf
'(Минимальное значение...)
StatsMsg = StatsMsg & "The largest value"& STATS.Max
'(Максимальное значение...) MsgBox StatsMsg
End Sub
Редактирование страницы свойств
Запустите тестовый проект и проверьте работоспособность страниц свойств, сгенерированных мастером. Теперь наступил момент, когда можно добавить еще несколько элементов управления на страницу Text Property, которая позволит разработчикам изменять другие заказные свойства. Законченная страница должна иметь вид, подобный представленному на рис. 16.12.
Рис. 16.12. Страница свойств со свойствами элемента управления FLEXLabel
Откройте страницу свойств в режиме конструирования и добавьте два элемента управления ComboBox и две соответствующие метки над ними. Установите нужный размер и шрифт для всех элементов.
Теперь все готово к изменению кода. Оба элемента управления ComboBox должны быть заполнены допустимыми установками для соответствующих свойств. Наилучшее место для вставки кода инициализации — событие Initialize.
Программа 16.11. Инициализация страницы CaptionProperties
Private Sub PropertyPage_Initialize()
Combo1.AddItem "Top Left"
Combo1.AddItem "Top Middle"
Combo1.AddItem "Top Right"
Combo1.AddItem "Center Left"
Combo1.AddItem "Center Middle"
Combo1.Addltem "Center Right"
Combo1.AddItem "Bottom Left"
Combo1.AddItem "Bottom Middle"
Combo1.AddItem "Bottom Right"
Combo2.Addltem "None"
Combo2.Addltem "Carved Light"
Combo2.Addltem "Carved"
Combo2.Addltem "Carved Heavy"
Combo2.Addltem "Raised Light"
Combo2.Addltem "Raised"
Combo2.Addltem "Raised Heavy"
End Sub
Теперь необходимо исправить обработчик события
SelectionChanged(). Добавим операторы, инициализирующие два элемента управления ComboBox, которые соответствуют двум новым свойствам. Введите следующий код в обработчик события SelectionChanged страницы свойств.
Программа 16.12. Инициализация элементов ComboBox
Private Sub PropertyPage SelectionChanged()
txtCaption.Text = SelectedControls(0).Caption
Combol.Listlndex = SelectedControls(0).TextAlignment
Combo2.Listlndex = SelectedControls(0).Effect
End Sub
Затем необходимо обновить переменную Changed из событий, обозначающих выбор нового значения из элемента управления ComboBox. Поскольку элементы ComboBox не позволяют вводить новые значения, то выбор может осуществляться только с использованием события Click. Значит, необходимо добавить обработчик события Click для элементов ComboBox, как показано ниже.
Private Sub Combol_Click()
Changed =
True
End Sub
Private Sub Combo2_Click ()
Changed = True
End Sub
На последнем шаге исправим обработчик события
ApplyChanges() так, чтобы он приводил в действие изменения в элементах ComboBox. Ниже приведен код, реализующий обработку щелчка на кнопке Apply.
Программа 16.13. Применение изменений
Private Sub PropertyPage_ApplyChanges()
SelectedControls(0).Caption = txtCaption.Text
SelectedControls(0).TextAlignment = Combol.Listlndex
SelectedControls(0).Effect = Combo2.Listlndex
End Sub
Теперь можно переключиться на тестовую форму и проверить работу страниц свойств. Как видите, страницы свойств не являются чем-то новым - это обычные формы VB, на которых можно помещать все виды элементов управления. При работе с этими страницами следует придерживаться нескольких правил, предлагаемых мастером.
1 . Устанавливайте свойство Changed в значение True каждый раз, когда свойства меняют свое значение для разрешения использования кнопки Apply.
2 . Модифицируйте свойства элементов управления, используя выражение SelectedControls (0) propertyName, где propertyName — фактическое имя свойства.
3 . Инициализируйте свойства в событии PropertyPage_SelectionChanged() каждый раз, когда пользователь переключается на новую страницу свойств.
Если открыть окно свойств для объекта UserControl, то можно увидеть, что свойство PropertyPages имеет значение 4. Это указывает на то, что элемент управления имеет четыре страницы свойств. Для того чтобы исключить ненужные страницы свойств, вызовите диалоговое окно Connect Property Page, показанное на рис. 16.13 и очистите флажок перед соответствующим именем страницы свойств.
Рис. 16.13. В диалоговом окне вместе со стандартными страницами свойств Visual Basic показана заказная страница свойств элемента FLEXLabel
Конструирование элемента управления ActiveX теперь не представляет большой сложности. Мастер интерфейса элементов управления ActiveX берет на себя многочисленные детали. Он создает скелет кода элемента управления, а разработчик пишет код, выполняющий специфические действия, которые что другие элементы делать не могут. Код, написанный разработчиком, представляет собой самый обыкновенный код приложения VB. И все же существует несколько различий между обычным приложением и элементом управления. Чем больше разработчик будет знать об этих отличиях, тем лучше он будет подготовлен к конструированию элементов управления ActiveX. Следующий раздел уделяет большее внимание именно таким различиям.
Регистрация компонентов
ActiveX
Классы регистрируются автоматически в системе, где они разработаны. Создаваемые DLL или ЕХЕ-файлы, реализующие классы, также автоматически регистрируются Visual Basic. Но если нужно создать класс, который должен быть доступен разработчикам в других системах? Если компонент создан как ЕХЕ-сервер, то его можно распространить в виде ЕХЕ-файла. При запуске на компьютере, где компонент будет использоваться, класс зарегистрируется автоматически. Никаких сообщений или форм при этом не выдается. Все, что нужно сделать, так это запустить ЕХЕ-сервер, который сам себя зарегистрирует.
Для DLL-компонент ситуация отличается коренным образом, поскольку они сами не выполняются. Они должны загружаться другим приложением (вот почему ActiveX DLL называются еще внутренними серверами — они обслуживают только процессы, которые их содержат). ActiveX DLL должны регистрироваться с помощью утилиты REGSVR32, которая поставляется с Visual Basic (она находится в подпапке RegUtils папки Tools на компакт-диске Visual Basic). REGSVR32 — это программа, которая позволяет регистрировать и удалять внутренние серверы. Возможность удаления внешних серверов также важна. Например, просто удалить DLL-файлы, которые реализуют программный компонент, недостаточно. Необходимо также убрать компоненты из системного реестра, что можно сделать с помощью утилиты REGSVR32.
Для регистрации ActiveX DLL создайте файл, используя команду Make ClassName.dll из меню File (ClassName является именем класса). Затем скопируйте этот файл в папку Windows System или любую другую. Для регистрации DLL откройте окно Command Prompt (окно командной строки DOS), перейдите в папку, где находится DLL, и выполните следующую команду:
С:\WINDOWS\SYSTEM\REGSVR32 ClassName.dll
ClassName.dll -
это имя файла, в котором реализован сервер. Есть несколько опций, которые можно использовать с утилитой REGSVR32. Опция /и удаляет ранее зарегистрированный DLL.
Чтобы удалить файл ClassName.dll, используйте команду:
REGSVR32 /u ClassName.dll
Когда новый компонент DLL зарегистрирован, утилита REGSRV сообщает о результатах операции в диалоговом окне. Для подавления вывода этого окна можно использовать опцию /s (silent - молчаливый) REGSRV32 - это наиболее простой механизм для распространения DLL-серверов. Все, что при этом нужно сделать, это написать маленькую программу, которая копирует файл DLL в папку и затем запускает утилиту REGSRV32 для регистрации скопированного DLL. Если дистрибутивные файлы были созданы с помощью мастера Package & Deployment, то все компоненты, которые должны быть установлены вместе с приложением, будут устанавливаться программой инсталляции.
Рекурсивное сканирование папки
Рекурсивное сканирование папки (сканирование файлов папки и ее подпапок на произвольную глубину) - это стандартная операция при программировании файловой системы. В гл. 11 было показано, как рекурсивно сканировать папку, используя элементы управления File System (элементы управления DriveListBox, DirectoryListBox и FileListBox). В гл. 8 было создано приложение, которое заполняет элемент управления TreeView содержимым устройства или папки. Древовидная структура идеальна для представления папки, потому что папка является древовидной структурой. В проекте Explorer при использовании объекта FileSystemObject мы обещали вернуться к пояснению работы проекта.
В этом параграфе рассмотрено приложение FSystem, которое заполняет элемент управления TreeView папками диска С. Для отображения содержимого другого устройства или папки внесите в код соответствующие изменения. Форма приложения FSystem показана на рисунке 20.3. Запустите приложение и щелкните на кнопке Populate Tree, чтобы увидеть структуру папок диска С: в окне элемента управления TreeView. Время реакции приложения зависит от количества папок в корневом каталоге устройства. Будьте терпеливы или измените код для просмотра меньшего количества папок.
Рис. 20.3. Приложение FSystem: некоторые методы объекта FileSystemObject
Начнем с простой версии приложения, которая выводит имена папок в окно проверки. Затем заменим оператор Debug. Print соответствующими операторами для добавления имен папок в элемент Tree View.
Программа 20.4. Сканирование диска с помощью объекта FileSystemObject
Dim FSys As New Scripting.FileSystemObject
Private Sub Command1_Click()
Dim folderSpec As String
Set FSys = CreateObject ("Scripting.FileSystemObject")
' В следующей строке укажите папку, которую необходимо видеть
folderSpec = "с:\"
ScanFolder(folderSpec)
Debug.Print "*** Конец списка объектов каталога ***"
End Sub
Sub ScanFolder(folderSpec As String)
Dim thisFolder As Folder
Dim sFolders As Folders
Dim fileItem As File, folderItem As Folder
Dim AllFiles As Files
Set thisFolder = FSys.GetFolder(folderSpec)
Set sFolders = thisFolder.SubFolders
Set AllFiles = thisFolder.Files
For Each folderItem In sFolders
Debug.Print
Debug.Print "*** ПАПКА " & folderltem.Path & "***"
ScanFolder (folderItem.Path)
Next
For Each fileItem In AllFiles
Debug.Print fileItem.Path
Next
End Sub
Обработчик события Click кнопки Command 1 вызывает подпрограмму ScanFolder(), чтобы просканировать папку, имя которой передается в качестве аргумента. ScanFolder() создает объектную переменную thisFolder, которая задает текущую папку. Затем программа создает семейство подпапок из сканируемой папки. Это семейство - sFolder -
сканируется, и имена подпапок отображаются в окне проверки. После вывода на экран имени текущей папки подпрограмма ScanFolder() рекурсивно вызывается для сканирования подпапок текущей папки. После сканирования текущей папки, включая ее подпапки, программа отображает файлы в текущей папке, используя семейство AllFiles.
В версии программы FSystem на компакт-диске операторы, выполняющие вывод в окно проверки, закомментированы и добавлены операторы, помещающие имена папок и файлов в элемент управления TreeView.
Программа 20.5. Заполнение элемента TreeView
Dim FSys As New Scripting.FileSystemObject
Private Sub Coininandl_Click ()
Dim folderSpec As String
Set FSys = CreateObject("Scripting.FileSystemObject")
' В следующей строке укажите папку, которую хотите увидеть
folderSpec = "c:\wind"
folderSpec = UCase(folderSpec)
TreeView1.Nodes.Add, ,folderSpec, folderSpec
Screen.MousePointer = vbHourglass
ScanFolder (folderSpec)
Screen.MousePointer = vbDefauit
TreeView1.Nodes(1).Expanded = True
MsgBox "File List created"
' (Список файлов создан)
End Sub
Sub ScanFolder(folderSpec As String)
Dim thisFolder As Folder
Dim sFolders As Folders
Dim fileItem As File, folderItem As Folder
Dim AllFiles As Files
Set thisFolder = FSys.GetFolder(folderSpec)
Set sFolders = thisFolder.SubFolders
Set AllFiles = thisFolder.Files
For Each folderItem In sFolders
TreeView1.Nodes.Add folderItem.ParentFolder.Path, _
tvwChild, folderItem.Path, folderItem.Name
ScanFolder (folderItem.Path)
Next
For Each fileItem In AllFiles
TreeView1.Nodes.Add fileItem.ParentFolder.Path, _
tvwChild, fileItem.Path, fileItem.Name
Next
End Sub
Заметьте, как метод Add элемента управления TreeView добавляет папку и имена файлов в надлежащее место в дереве. Узел каждой папки является потомком узла родительской папки. Выражение folderltem.ParentFolder.Path является именем текущего пути и используется как ключ узла. Ключ каждого элемента -это имя полного пути к нему, поэтому ключи файлов с одинаковыми именами из различных папках будут помещены в требуемую позицию в дереве.
Код проекта FSystem легко модифицировать, чтобы заполнить элемент TreeView не всеми именами файлов, а только именами выделенных файлов. Критерием для выделения могут быть атрибуты файлов, например, его размер, тип и т.д. Можно выбрать файлы с изображениями, размер которых превышает 100 Кб. Или текстовые файлы, которые не использовались в течение месяца, и т.д.
Рекурсивный просмотр папки
Contacts
В проекте Contacts из предыдущего параграфа подразумевалось, что все контакты хранятся в папке Contacts (точно также и в других проектах подразумевается, что все сообщения постоянно находятся в одной папке) Это приемлемо для пользователей с небольшим числом контактов (или полностью неорганизованных пользователей), но в общем случае это не так. Большинство пользователей организует контакты в подпапки для упрощения поиска. Но организовать просмотр папки Contacts вместе с подпапками не так-то просто. Для реализации такой возможности требуется использовать методы рекурсивного программирования. Если во время чтения гл. 11 " Использование рекурсивных методов" могло показаться, что рассматриваемые методы больше нигде не понадобятся, то в данном случае есть возможность убедиться в обратном. Пусть это не покажется вам навязчивой пропагандой в пользу применения рекурсии, но есть задачи, которые невозможно решить другими способами. Сколь трудным и непривычным не казался бы рекурсивный подход к программированию, но без него невозможно организовать циклический просмотр папки Contacts, при условии, что в ней содержатся подпапки (точно так же, как выполнить обход дерева Tree View).
VB6 в действии : проект AIIContacts
Одноименное приложение, демонстрирующее рекурсивную процедуру просмотра папки Contacts, может быть найдено в папке ALLCONTS, находящейся на компакт-диске в папке, посвященной этой главе. Если после загрузки формы приложения щелкнуть на кнопке Populate Tree, то окно элемента управления TreeView будет заполнено названиями всех подпапок папки Contacts (рис. 14.22). После этого можно открывать различные папки в окне элемента управления TreeView и просматривать список всех контактов в окне элемента управления ListBox (справа).
Рис. 14.22. В проекте AIIContacts в окне элемента управления TreeView (слева) выводится список (дерево) всех подпапок папки Contacts приложения Outlook
Исходный текст приложения
Программа, как всегда, начинается с описания переменных. Сначала объявляются следующие объектные переменные, используемые большинством процедур:
Public OutlookApp As outlook.Application
Public OlObjects As outlook.NameSpace
Public OlContacts.As outlook.MAPIFolder
Затем в событии Load формы введите следующие операторы для создания нового экземпляра Outlook и объектных переменных, необходимых для обращения к его папкам.
Программа 14.24. Создание объектной переменной Outlook
Private Sub Form Load()
Set OutlookApp = CreateObject ("Outlook.Application.8")
If Err Then
MsgBox "Could not create Outlook Application object!"
'(He удалось создать объект Outlook Application!)
End
End If
Set OlObjects = OutlookApp.GetNamespace("MAPI")
Set OlContacts = OlObjects.GetDefaultFolder(olFolderContacts)
If Err Then
MsgBox "Could not get MAPI NameSpace" , YbCritical
' (He удалось получить место расположения MAPI...)
End If
End Sub
Переменная
OutlookApp
представляет приложение. Переменная OlObjects - все папки, предоставленные Outlook, и переменная OlContacts -
папку Contacts. Эти переменные объявлены следующим образом:
Public OlObjects As outlook.NameSpace
Public OlContacts As outlook.MAPIFolder
Ядром приложения является обработчик события Click команды Populate Tree, который заполняет окно элемента управления TreeView с помощью рекурсивной процедуры.
Программа 14.25. Заполнение окна элемента управления TreeView
Private Sub Command1_Click ()
Dim allFolders As outlook.Folders
Dim Folder As outlook.MAPIFolder
Dim Folders As outlook.Folders
Dim thisPolder As outlook.MAPIFolder
Dim newNode As Node
' Добавление корневого узла
Set newNode = TreeViewl.Nodes.Add(, , OlContacts.EntryID, "Contacts")
newNode.Expanded =
True
' Получение списка подпапок в папке Contacts
Set allFolders = OlContacts.Folders
' Обработка отдельных подпапок в папке Contacts
For Each Folder In allFolders
Set newNode = TreeViewl.Nodes.Add(OlContacts.EntryID, _
tvwChild, Folder.Name, Folder.Name)
Set Folders = Folder.Folders
For Each thisFolder In Folders
Set newNode = TreeViewl.Nodes.Add(Folder.Name, _
tvwChild, thisFolder.EntryID,
thisFolder.Name)
newNode.Expanded = True
' теперь просматривается содержимое подпапок текущей папки
ScanSubFolders thisFolder
Next
Next
End Sub
Чтобы заполнить окно элемента управления TreeView, сначала добавляется корневой узел, который, в данном случае, является папкой Contacts. Этот узел не имеет родительского узла, а ключом для него является значение свойства Entry ID папки Contacts:
Set newNode = TreeViewl.Nodes.Add(, , OlContacts.EntryID, _
"Contacts")
newNode.Expanded = True
Как только узел добавлен, он дополняется таким образом, чтобы пользователь видел имена подпапок под ним и знак "плюс" перед их именами. Затем необходимо создать семейство allFolders,
которое содержит все подпапки папки Contacts:
Set allFolders = OlContacts.Folders
Цикл, приведенный в программе 14.26, просматривает каждый элемент этого семейства и добавляет имя текущей папки к содержимому окна элемента управления TreeView. Новый узел становится дочерним узлом узла Contacts, а его ключом является значение свойства EntryID родительского узла.
Затем следует создать другое семейство - Folders, содержащее подпапки текущей папки. Элементы этого семейства добавляются к содержимому окна элемента управления TreeView, после чего вызывается подпрограмма ScanSubFolders(), позволяющая просмотреть подпапки каждого элемента семейства. Код подпрограммы ScanSubFoldersO приведен ниже.
Программа 14.26.
Подпрограмма ScanSubFolders()
Sub ScanSubFolders(thisFolder As Object)
Dim subFolders As outlook.Folders
Dim subFolder As outlook.MAPIFolder
Set subFolders = thisFolder.Folders
If subFolders.Count <> 0 Then
strFolderKey = thisFolder.EntryID
For Each subFolder In subFolders
TreeViewl.Nodes.Add thisFolder.EntryID, _
tvwChild, subFolder.EntryID, subFolder.Name
ScanSubFolders subFolder
Next
End If
End Sub
Это очень простая программа (для рекурсивной процедуры, разумеется). Она позволяет создать семейство subFolders
подпапок текущей папки. Затем программа просматривает каждый элемент семейства, добавляет его имя к содержимому окна элемента управления TreeView и, при этом, выполняет этот просмотр рекурсивно. Это означает, что она вызывает сама себя, передавая в качестве параметра имя текущей папки.
Просмотр контактов папки
После заполнения окна элемента управления TreeView подпапками папки Contacts можно с помощью мыши в этом окне выбрать папку, чтобы отобразить ее контакты в окне элемента управления ListBox (с правой стороны формы). После того как в окне элемента управления TreeView выполнен щелчок, вызывается обработчик события NodeClick.
Это событие возвращает узел, на котором был выполнен щелчок, после чего можно получить ключ узла, который является ID выбранной папки. Как только стал известен ID выбранной папки, можно создать ссылку на эту папку (переменная thisFolder)
и использовать ее для просмотра содержащихся в ней элементов (т. е. контактов). Ниже приводится текст обработчика события NodeClick в окне элемента управления TreeView.
Программа 14.27. Получение списка содержимого выбранной папки
Private Sub TreeViewl NodeClick(ByVal Node As ComctlLib.Node)
Dim thisFolder As outlook.MAPIFolder
Dim contacts As outlook.Items
Dim Contact As outlook.Contactltem
On Error Resume Next
List1.Clear
Labell.Caption = "Selected Folder: " & Node.Text
' (Выбранная папка:...)
Set thisFolder = OlObjects.GetFolderFromID(Node.Key)
If Err Then
Exit Sub
Else
Set contacts = thisFolder.Items
For Each Contact In contacts
List1.AddItem Contact.LastName & ", " & _
Contact.FirstName
Next
End If
End Sub
Программа позволяет отобразить только значения свойств
LastName и FirstName контакта. Пользователь может изменить программу, чтобы можно было отображать содержимое любых полей. Например, можно получать адрес электронной почты контакта и автоматически разослать по этим адресам сообщения (как это было сделано в предыдущем примере). Если эти примеры представляются вам интересными, можете вставить фрагмент программы AlIContacts в проект Contacts.
Этим примером заканчивается введение в автоматизацию
OLE. Если добавить ссылки на различные Office-приложениям в пользовательских проектах, а затем открыть Object Browser, то можно обнаружить, что теперь они предоставляют много объектов, которые, в свою очередь, предоставляют многочисленные свойства и методы. Автоматизация Office-приложений с помощью VBA вполне по силам среднему программисту, и, кроме того. она предоставляет возможность ознакомиться с объектами, предоставляемыми Office-приложениями (или любыми другими приложениями, которые поддерживают VBA). После чтения этой главы читатель получит знания об основах программирования в VBA и понимание того обстоятельства, что программирование в VBA не многим отличается от программирования BVB6.
Глава 15 Конструирование компонентов ActiveX
• Модули и модули классов
• Конструирование модулей классов
• Реализация свойств и методов
• Инициирование событий из кода класса
• Создание и использование объектных переменных
• Регистрация компонентов ActiveX
• Обработка ошибок в классах
В предыдущей главе было показано, как установить связь с приложением-сервером и как управлять его работой с помощью объектов, которые оно предоставляет. В этой главе объясняется, как создавать свои собственные приложения-серверы или так называемые компоненты ActiveX. Компонент ActiveX — это общий термин, который относится к трем (в будущем, возможно, и более) типам проектов: ActiveX DLL, ActiveX EXE и элементам управления ActiveX. В этой главе мы познакомимся с конструированием программных компонентов
(ActiveX DLL и ActiveX EXE), которые являются приложениями-серверами, интерфейс которых состоит из свойств, методов и событий.
В следующей главе будет показано, как создавать свои собственные элементы управления ActiveX, которые могут быть добавлены на панель элементов управления любого проекта и использоваться разработчиками при конструировании пользовательских интерфейсов. В гл. 20 показано, как элементы управления ActiveX могут быть использованы на Web-страницах.
Главные отличия между элементами управления ActiveX и программными компонентами ActiveX заключаются в их интерфейсах и способе встраивания в среду разработки Visual Basic. В то время как элементы управления ActiveX полностью интегрированы в Visual Basic и имеют визуальный интерфейс, программные компоненты, напоминающие по функциональным возможностям элементы управления ActiveX, менее интегрированы со средой разработчика (их, например, нельзя поместить на форму, как это можно сделать с элементом управления) и не имеют визуального интерфейса. Программные компоненты ActiveX являются классами, которые доступны через объявляемую соответствующим образом объектную переменную.
Другой категорией компонентов ActiveX являются документы ActiveX — это приложения, которые могут располагаться в таких контейнерах, как Internet Explorer и Office Binder. В этой книге мы не будем рассматривать документы ActiveX, которые, на самом деле, очень похожи на программные компоненты ActiveX и элементы управления ActiveX.
Реляционные связи
Базы данных, используемые в настоящее время, являются реляционными, поскольку они основаны на отношениях между таблицами. Основой системы реляционных баз данных является разбиение данных на составные таблицы, связанные общей информацией (ключами).
Предположим, разрабатывается база данных для хранения счетов. Эта база данных должна иметь таблицу с именами заказчиков, названиями изделий, ценами, и, конечно, таблицу счетов. Каждый счет, выписанный заказчику, содержит ряд изделий. Вместо того чтобы хранить названия изделий и имена заказчиков в счете, хранятся числа, которые уникально идентифицируют заказчиков и изделия. Эти числа - ключи, связывающие строки одной таблицы со строками другой. Ключи устанавливают связи между таблицами и делают возможным разбиение информации на отдельные таблицы во избежание ее дублирования.
Примечание
Модель реляционной базы данных создана в 1970 году Коддом (E.F. Codd) из корпорации IBM, который разработал также язык запросов, впоследствии названный SQL.
Рассмотрим некоторые понятия реляционной модели, а затем разработаем приложения, демонстрирующие эти принципы.
Рисование на объекте
UserControl
Теперь уже есть функционирующий элемент управления, при создании которого не было особых проблем, поскольку Visual Basic создал его скелет. Элемент управления интегрирован в среду разработки, его пиктограмма появилась на панели элементов управления, и он может быть уже использован, как обычный элемент управления. Он даже имеет свое собственное окно свойств. Теперь настало время сделать элемент управления реально работающим. Необходимо добавить код, уникальный для данного элемента управления, который рисует надпись.
Код вывода на экран видимого интерфейса элемента управления обычно помещается в событие Paint. Visual Basic инициирует это событие каждый раз, когда элемент управления должен быть перерисован. Таким образом, нужно добавить код, перерисовывающий элемент управления. Сейчас давайте скопируем процедуру DrawCaption(), разработанную ранее в этой главе, в элемент управления. Откройте окно объекта UserControl, в котором находится код элемента управления, и вставьте туда процедуру DrawCaption(). В обработчике события Paint объекта UserControl вставьте следующую строку, которая вызывает процедуру DrawCaptionQ:
DrawSubroutine
Этот вызов в событии Paint гарантирует, что каждый раз, когда разработчик изменяет размеры элемента управления, или при обновлении формы, весь объект UserControl будет также перерисован.
Процедура DrawCaption() рисует на объекте Form. Объект UserControl фактически идентичен объекту Form, поэтому может использовать те же самые методы рисования. Откройте окно кода объекта UserControl, вставьте код подпрограммы DrawCaption() и замените все вхождения "Me" на "UserControl", чтобы процедура рисовала на объекте UserControl.
Подпрограмма DrawCaption() должна также вызываться для перерисовки надписи всякий раз, когда изменяется какое-либо из специальных свойств элемента управления. Свойствами, которые влияют на вид выводимого текста наряду со стандартными свойствами Picture и BackColor, являются Caption, TextAlignment и Effect. Вставьте в коды этих свойств элемента управления процедуру Property Let со строкой, вызывающей событие UserControl_Paint. Доработанная процедура Property Let для свойства Effect показана ниже (подчеркнута вставленная строка).
Public Property Let Effect (ByVal New_Effect As Effects)
m_Effect = New_Effect
PropertyChanged "Effect"
UserControl Paint
End Property
Рисование на объекте UserControl идентично рисованию на объекте Form. Элементы управления, которые подобно элементу управления FLEXLabel рисуют свой видимый интерфейс и не полагаются на стандартные элементы управления, называются user-drawn
(нарисованные пользователем). Позже в главе будет показано, как строить специальные элементы управления на основе конституэнтных.
Попробуйте изменить свойство, определяющее цвет элемента управления FLEXLabel. Появится знакомое диалоговое окно, в котором можно выбрать или задать новый цвет. Заметьте, мы не предпринимали никаких мер для реализации этого свойства. Если посмотреть код элемента управления, можно заметить, что мастер объявил тип свойств Backcolor и ForeColor как OLE_COLOR. Когда Visual Basic видит тип OLE_COLOR, он знает, как обрабатывать соответствующие свойства в окне свойств.
Примечание
OLE_COLOR не является общим типом данных, который можно использовать в объявлениях обычных переменных Visual Basic, но он имеет определенный смысл. Он выводит диалоговое окно Color Selection (Выбор цвета) всякий раз, когда пользователь пробует устанавливать новое значение для свойства, определяющего цвет. Если определить тип свойств Backcolor или Forecolor как Long, то пользователь элемента управления для задания цвета должен будет вводить в окне свойств целое значение (например, HOOFFOO для зеленого цвета).
Сценарии для объектов
ActiveX
Наиболее мощное свойство элемента управления Script, позволяющее использовать его для написания сценариев приложения — это его способность манипулировать элементами управления ActiveX. Из примера, приведенного в предыдущем параграфе, видно, как создавать объектные переменные для доступа к OLE-серверу. Если приложение использует классы, то можно получить к ним доступ посредством элемента управления VBScript. Необходимо только создать экземпляр класса (или нескольких классов) и сохранить его в элементе управления Script. После этого свойства и методы будут доступны с помощью объектной переменной, как обычные команды VBScript.
С помощью метода AddObject
можно добавить объект к элементу управления Script.
ScriptControll.AddObject Name, Object, members
Первый аргумент — Name —
это имя для доступа к классу в сценарии. Это переменная типа String. Второй аргумент - Object - действительное имя класса. Допустим, приложение предоставляет класс DisplayClass. Для добавления этого класса к элементу управления Script надо создать объектную переменную
Private Display As New DisplayClass
и воспользоваться следующим оператором
ScriptControll.AddObject "Output", Display
После выполнения этого оператора (обычно он помещается в событие Load формы) сценарий получает доступ к членам класса DisplayClass через объектную переменную Output. Если DisplayClass имеет метод Show, то к этому методу может обращаться любой сценарий.
Output.Show "some message"
' (некоторое сообщение)
(Метод Show выводит сообщение в нижний элемент управления TextBox формы.) Последний (необязательный) аргумент - members — это логическое значение, определяющее, будут ли доступны члены класса через объектную переменную. Если установить значение этого аргумента в True, то члены класса будут доступны по имени, как функции VBScnpt. Если добавить класс DisplayClass в элемент управления Script оператором
ScriptControll.AddOb]ect "Output", Display, True
то к методу Show можно обратиться из сценария без указания переменной имени объекта
Show "some message"
(некоторое сообщение)
VB6 в действии: класс Display
Одно из ограничений VBScnpt — он не поддерживает функций ввода/вывода. Так как VBScnpt — язык написания сценариев, то он по определению не поддерживает пользовательский интерфейс. Если необходимо разработать приложение с визуальным интерфейсом, то используйте Visual Basic. Но во время проектирования, особенно на этапах отладки и тестирования, необходим способ отображения промежуточных результатов.
Форма проекта SEditor имеет окно, в котором сценарий помещает свой вывод (подобно временному окну). Эта особенность реализуется с помощью класса DisplayClass, имеющего два метода.
• Show - для печати строки в нижнем элементе управления TextBox;
• Clear — для удаления содержимого нижнего элемента управления TextBox.
Реализация модуля класса DisplayClass требует всего нескольких строк кода.
Программа 20.9. Класс Display
Public Sub Show(message)
ScriptForm.Text2.Text = ScriptForm.Text2.Text _
& vbCrLf & message
End Sub
Public Sub Clear()
ScriptForm.Text2.Text = ""
End Sub
Для использования членов класса DisplayClass внутри сценария без регистрации Display DLL и создания объектной переменной с помощью функции CreateObject(), объект Display добавляется в элемент управления Script. Для этого необходимо добавить следующий оператор в событие Load формы.
Private Sub Form Load()
ScriptControll.AddObject "Output", Display, True
End Sub
Заметьте последний аргумент установлен в True, то есть Show и Clear доступны по имени.
Проект SEditor — простое приложение, позволяющее экспериментировать с VBScript. При разработке действительно сложных приложений, не требующих интенсивного ввода/вывода (не считая функции MsgBox() и метода Show), можно использовать и простой редактор. Однако на него нельзя рассчитывать, когда понадобится отобразить члены объектной переменной или проверить синтаксис.
Семейство
Documents u объект Document
Первым в иерархии объектов приложения Word является объект Document, представляющий любой документ, который можно открыть в Word, или иной документ, который можно отобразить в окне Word. Все открытые документы принадлежат семейству Documents (Документы), которое состоит из объектов Document. Подобно всем другим семействам, это семейство поддерживает свойство Count (Число открытых документов), метод Add (Добавить), с помощью которого можно добавить новый документ, и метод Remove (Удалить), который позволяет закрыть существующий документ. Чтобы обратиться к уже открытому документу, можно воспользоваться методом Item (Элемент) из семейства Documents (Документы), определив индекс документа следующим образом:
Application.Documents.Item(1)
Аналогичным образом можно определить имя документа:
Application.Documents.Item ("MasteringVB.doc")
Поскольку Item — это заданное по умолчанию свойство, то можно полностью опустить его имя:
Application.Documents(I)
Чтобы открыть существующий документ, можно воспользоваться методом Open (Открыть) семейства Documents (Документы):
Documents.Open(fileName)
Параметр
fileName — это путь и имя файла документа.
Для создания нового документа, следует воспользоваться методом Add семейства Documents (Документы), который принимает два необязательных параметра:
Documents.Add(template, newTemplate)
Параметр
template определяет имя файла шаблона, который нужно использовать в качестве основы для нового документа. Параметр newTemplate
является значением типа Boolean. Если он имеет значение True, Word создаст новый файл шаблона.
Большинство выполняемых операций воздействуют на активный документ (документ в активном окне Word), который представляется объектом ActiveDocument, являющийся свойством объекта Application. Чтобы обращаться к выделенному тексту в активном документе, следует воспользоваться следующим выражением:
Application ActiveDocument.Selection
Можно сделать активным любой документ, вызвав метод Activate (Активизировать) объекта Document. Чтобы сделать документ My Notes doc активным, можно воспользоваться следующим оператором:
Documents ("MyNotes doc"). Activate
После выполнения этого оператора документ MyNotes doc становится активным, и программа может обращаться к нему по имени Application ActiveDocument
Worksheets и объект Worksheet
Каждая рабочая книга в Excel может содержать один или несколько рабочих листов. Коллекция Worksheets, подобная коллекции Documents в Word, содержит объект Worksheet
для каждого рабочего листа в текущей рабочей книге. Чтобы добавить новый рабочий лист, следует воспользоваться методом Add:
Application.Worksheets.Add(before, after, count, type)
Параметры
before и after позволяют определить расположение нового рабочего листа в рабочей книге. Можно определить только один из двух параметров. Если опустить оба параметра, то новый рабочий лист будет вставлен перед активным рабочим листом (и станет активным). Параметр type определяет тип нового рабочего листа и может иметь одно из следующих значений.
• xlWorksheet. Значение, установленное по умолчанию.
• xIExcel4MacroSheet. Рабочий лист, содержащий макросы Excel 4.
• xlExcel4lntlMacroSheet. Рабочий лист, содержащий международные макросы Excel 4. Чтобы обратиться к рабочему листу, следует воспользоваться методом Item коллекции Worksheets, передавая в качестве параметра индекс или имя рабочего листа. Если второй рабочий лист называется SalesData.xIs, то следующие выражения эквивалентны:
Application.Worksheets.Item(2)
и
Application.Worksheets.Item ("Sales Data.xls")
Поскольку Item — это установленное по умолчанию свойство коллекции, имя его можно полностью опустить:
Application.Worksheets (2)
Объекты, предоставляющие доступ к ячейкам
Excel - это приложение, которое предназначено для обработки информации хранящейся в ячейках. Но основным объектом, используемым для организации доступа к содержимому рабочего листа, является объект Range, являющийся свойством объекта Worksheet. Имеются несколько способов идентификации объекта Range, но ниже приведено каноническое его описание:
Worksheet.Range(celll:се112)
Где cell1 и сеll2
—адреса двух ячеек, которые определяют прямоугольную область на рабочем листе. Это адреса левой верхней и правой нижней ячеек блока. В этом параграфе будет использована стандартная нотация Excel, в которой число определяет строку, а буква - столбец, например, СЗ или А103. Чтобы выбрать блок ячеек размером 10 х 10, занимающий левый верхний угол активного рабочего листа, следует воспользоваться выражением:
Files
Семейство Files содержит объект File для каждого файла папки. Следующий сценарий обрабатывает все файлы указанной папки с помощью оператора For Each... Next.
Set ThisFolder = FSys.GetFolder(folderName)
Set AllFiles = ThisFolder.Files
For Each file in AllFiles
{обработка текущего файла}
Next
Внутри тела цикла предоставляется доступ к свойствам текущего файла. Его имя - это file. Name, дата создания - file.DateCreated и т.д. В следующих параграфах перечислены свойства и методы объекта File.
Folders
Семейство Folders содержит объект Folder для каждой подпапки в папке. Следующий сценарий обрабатывает каждую подпапку в указанной папке, используя оператор For Each...Next.
Set FSys = CrateObject ("Scripting. FileSystemObject")
Set ThisFolder =
FSys.GetFolder(folderName)
Set AllFolders = ThisFolder.SubFolders
For Each folder in AllFolders
{обработка текущей папки}
Next
В теле цикла доступны свойства текущей папки. Ее имя – folder.Name, дата создания — folder. DateCreated и т.д.
Свойства объекта Folder описаны ниже. Рассмотрим метод AddFolder - единственный метод объекта Folder.
AddFolder. Этот метод добавляет новый объект Folder в семейство. Его синтаксис имеет вид:
FolderObject.AddFolders folderName
где
folderName - это имя новой добавляемой папки.
Объект Folder
Этот объект представляет папку на диске. Он позволяет манипулировать реальными папками на диске с помощью своих методов и свойств. Чтобы создать объект Folder, сначала создается объектная переменная типа FileSystem Object, а затем — вызывается ее метод GetFolder, которому в качестве аргумента передается путь к папке.
Set FSys = CreateObject ("Scripting.FileSystemObject")
Set thisFolder = FSys.GetFolder("c: \windows\desktop")
Теперь переменная thisFolder
задает папку c:\windows\desktop, и вы можете работать с ней, используя свойства и объекты переменной. Кратко опишем свойства объекта Folder.
Attributes.
Возвращает или устанавливает атрибуты файлов или папок. Подробно описано в параграфе свойств объекта File.
DateCreated.
Возвращает дату и время создания указанного файла или папки ("только для чтения").
DateLastAccessed, DateLastModified.
Возвращают дату и время последнего доступа/модификации файла или папки ("только для чтения").
Drive. Возвращает имя устройства (буква), на котором находится указанный файл или папка ("только для чтения").
ParentFolder.
Возвращает родительскую папку объекта Folder. Используется в примере свойства IsRootFolder.
Subfolders
Свойство Subfolders возвращает семейство Subfolders, содержащее все подпапки данной папки. Чтобы получить семейство Subfolders папки "C:\WINDOWS", создайте переменную FileSystem Object, воспользуйтесь методом GetFolder для получения ссылки на указанную папку, а затем создайте семейство ее подпапок, используя свойство SubFolders.
Set FSys =
CreateObject ("Scripting.FileSystemObject")
Set thisFolder = FSys.GetFolder ("c:\windows")
Set allFolders = aFolder.SubFolders
For Each subFolder in allFolders
{обработка папки subFolder}
Next
Чтобы отсканировать подпапки указанной папки, используйте оператор For Each...Next, как показано выше. Имя текущей папки в теле цикла - subFolder.Name.
При обработке текущей папки можно исследовать ее файлы, чему и посвящен следующий параграф.
Environment
Свойство Environment возвращает семейство переменных среды. Для обработки этих переменных создается объект Shell и обрабатывается семейство Environment.
Set WShell = Wscript.CreateObject ("Wscript.Shell")
Set AllVars = WShell.Environment
For Each evar In AllVars
txt = txt & evar & vbCrLf
Next
MsgBox txt
Переменная
evar задает переменные среды в этой форме.
Variable =
setting
Результат работы ENWARS.VBS показан на рис. 20.11. Для доступа к определенным переменным среды используется объект Environment, описанный ниже.
Рис. 20.11. Сценарий ENWARS.VBS отображает имена и значения переменных среды
Переменные, возвращаемые методом Environment, по умолчанию — переменные среды PROCESS. Это встроенные переменные, такие как WinDir или WinBootDir, и переменные, созданные командой SET (команда DOS, встречающаяся несколько раз в файле AUTOEXEC.BAT). Эти переменные перечислены в табл. 20.6 (некоторые из них могут отсутствовать в системе). Можно передать аргумент методу Environment, который укажет, какой набор переменных возвращать. Windows NT поддерживает несколько наборов переменных среды. Windows 98 — только наборы PROCESS и VOLATILE. Сценарий может использовать набор VOLATILE для обмена с другими сценариями или динамически создавать и удалять эти переменные.
Семейство SpecialFolders
Свойство SpecialFolders предоставляет доступ к специальным папкам системы. Специальные папки включают папку Desktop (Рабочий стол), папку Start-меню и папку с персональными документами.
Примечание
Свойство SpecialFolders возвращает путь к папке Desktop (Рабочий стол), а не объект Folder. Для доступа к файлам и подпапкам этой папки необходимо создать экземпляр объекта Folder с помощью метода GetFolder объекта FileSystemObject, как показано в следующем примере.
Семейство SpecialFolders используется для создания новых ярлыков на Рабочем столе или помещения новых приложений в меню Пуск. Следующий пример выводит список всех файлов, имеющихся в папке DeskTop, и их типы. Для просмотра файлов этот сценарий (DTOP.VBS на компакт-диске) использует объект FileSystemObject.
Скелет элемента управления ActiveX
Перед добавлением кода следует изучить, что именно сделал мастер. Переключитесь в окно Project Explorer и выполните двойной щелчок на имени созданного элемента управления, чтобы открыть режим разработки Затем выполните двойной щелчок на форме элемента UserControl, чтобы открыть окно с кодом и просмотреть строки, вставленные мастером.
Программа 16.2. ActiveX Control
Private m_Caption As String
Private m_Effect As Integer
Private m TextAlignment As Integer
' Значения свойств по умолчанию:
Const m_def_Caption = "3D Label"
Const m_def_Effect = 2
Const m_def_TextAlignment = 4
' Переменные свойств:
' Объявления событий:
Event DblClick()
Event Click()
Event KeyUp(KeyCode As Integer, Shift As Integer)
Event KeyPress(KeyAscii As Integer)
Event KeyDown(KeyCode As Integer, Shift As Integer)
Event MouseUp(Button As Integer, Shift As Integer, X As Single, _
Y As Single)
Event MouseMove(Button As Integer, Shift As Integer, X As Single, _
Y As Single)
Event OLEStartDrag(Data As DataObject, AllowedEffects As Long)
Event OLESetData(Data As DataObject, DataFormat As Integer)
Event OLEGiveFeedback(Effect As Long, DefaultCursors As Boolean)
Event OLEDragOver(Data As DataObject, Effect As Long, _
Button As Integer, Shift As Integer, X As Single, _
Y As Single, State As Integer)
Event OLEDragDrop(Data As DataObject, Effect As Long, _
Button As Integer, Shift As Integer, X As Single, _
Y As Single)
Event Resize ()
Public Property Get Font() As Font
Set Font = UserControl.Font
End Property
Public Property Set Font(ByVal New_Font As Font)
Set UserControl.Font = New_Font
PropertyChanged "Font"
End Property
Public Property Get BorderStyle() As Integer
BorderStyle = UserControl.BorderStyle
End Property
Public Property Let BorderStyle(ByVal New_BorderStyle As Integer)
UserControl.BorderStyle() = New_BorderStyle
PropertyChanged "BorderStyle"
End Property
Public Property Get BackStyle() As BackgroundStyle
BackStyle = UserControl.BackStyle
End Property
Public Property Let BackStyle(ByVal New_BackStyle As _
BackgroundStyle)
UserControl.BackStyle() = New_BackStyle
PropertyChanged "BackStyle"
End Property
Public Property Get Appearance () As Integer
Appearance = UserControl.Appearance
End Property
Private Sub UserControl_DblClick()
RaiseEvent DblClick
End Sub
Private Sub UserControl_Click()
RaiseEvent Click
End Sub
Public Property Get Enabled() As Boolean
Enabled = UserControl.Enabled
End Property
Public Property Let Enabled(ByVal New_Enabled As Boolean)
UserControl.Enabled() = New_Enabled
PropertyChanged "Enabled"
End Property
Public Property Get ForeColor() As OLE_COLOR
ForeColor = UserControl.ForeColor
End Property
Public Property Let ForeColor(ByVal New_ForeColor As OLE_COLOR)
UserControl.ForeColor() = New ForeColor
PropertyChanged "ForeColor"
End Property
Public Property Get hDC() As Long
hDC = UserControl.hDC
End Property
Public Property Get hWnd() As Long
hWnd = UserControl.hWnd
End Property
Private Sub UserControl_KeyUp( KeyCode As Integer, Shift As Integer)
RaiseEvent KeyUp(KeyCode, Shift)
End Sub
Private Sub UserControl_Keypress(KeyAscii As Integer)
RaiseEvent Keypress(KeyAscii)
End Sub
Private Sub UserControl_KeyDown(KeyCode As Integer, Shift As Integer)
RaiseEvent KeyDown(KeyCode, Shift)
End Sub
Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
RaiseEvent MouseUp(Button, Shift, X, Y)
End Sub
Public Property Get MousePointer() As Integer
MousePointer = UserControl.MousePointer
End Property
Public Property Let MousePointer(ByVal New_MousePointer As Integer)
UserControl.MousePointer() = New_MousePointer
PropertyChanged "MousePointer"
End Property
Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
RaiseEvent MouseMove(Button, Shift, X, Y)
End Sub
Private Sub UserControl_OLEStartDrag(Data As Data0bject, _
AllowedEffects As Long)
RaiseEvent OLEStartDrag(Data, AllowedEffects)
End Sub
Private Sub UserControl_OLESetData(Data As DataObject, _
DataFormat As Integer)
RaiseEvent OLESetData(Data, DataFormat)
End Sub
Private Sub UserControl_OLEGiveFeedback(Effect As Long, _
DefaultCursors As Boolean)
RaiseEvent OLEGiveFeedback(Effect, DefaultCursors)
End Sub
Public Property Get OLEDropMode() As Integer
OLEDropMode = UserControl.OLEDropMode
End Property
Public Property Let OLEDropMode(ByVal New_OLEDropMode As Integer)
UserControl.OLEDropMode() = New_OLEDropMode
PropertyChanged "OLEDropMode"
End Property
Private Sub UserControl_OLEDragOver(Data As DataObject, _
Effect As Long, Button As Integer, Shift As Integer, _
X As Single, Y As Single, State As Integer)
RaiseEvent OLEDragOver(Data, Effect, Button, Shift, X, Y, State)
End Sub
Private Sub UserControl_OLEDragDrop(Data As Data0b]ect, Effect As Long, _
Button As Integer, Shift As Integer, X As Single, _
Y As Single)
RaiseEvent OLEDragDrop(Data, Effect, Button, Shift, X, Y)
End Sub
Public Sub OLEDrag()
UserControl.OLEDrag
End Sub
Public Property Get Picture() As Picture
Set Picture = UserControl.Picture
End Property
Public Property Set Picture(ByVal New Picture As Picture)
Set UserControl.Picture = New_Picture
PropertyChanged "Picture"
End Property
Private Sub UserControl_Resize ()
RaiseEvent Resize
End Sub
Public Property Get Caption() As String
Caption = m_Caption
End Property
Public Property Let Caption(ByVal New_Caption As String)
m_Caption = New Caption
PropertyChanged "Caption"
End Property
Public Property Get Effect() As Integer
Effect = m_Effect
End Property
Public Property Let Effect(ByVal New_Effect As Integer)
m_Effect = New_Effect
PropertyChanged "Effect"
End Property
Public Property Get TextAlignment() As Integer
TextAlignment = m_TextAlignment
End Property
Public Property Let TextAlignment(ByVal New_TextAlignment As Integer)
m_TextAlignment = New_TextAlignment
PropertyChanged "TextAlignment"
End Property
' Инициализация свойств
Private Sub UserControl_InitProperties()
Set Font = Ambient.Font
m_Caption = m_def_Caption
m_Effect = m_def_Effect
m_TextAlignment = m_def_TextAlignment
UserControl.BorderStyle = 1
UserControl.BackStyle = 1
End Sub
' Загрузка значений свойств
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
Set Font = PropBag.ReadProperty("Font",Ambient.Font)
UserControl.BorderStyle = PropBag.ReadProperty ("BorderStyle", 0)
UserControl.BackStyle = PropBag.ReadProperty ("BackStyle", 1)
UserControl.Enabled = PropBag.ReadProperty ("Enabled", True)
UserControl.ForeColor = PropBag.ReadProperty ("ForeColor", _
&H80000012)
UserControl.MousePointer = PropBag.ReadProperty ("MousePointer", 0)
UserControl.OLEDropMode = PropBag.ReadProperty ("OLEDropMode", 0)
Set Picture = PropBag.ReadProperty ("Picture", Nothing)
m_Caption = PropBag.ReadProperty ("Caption", m_def_Caption)
m_Effect = PropBag.ReadProperty ("Effect", m_def_Effect)
m_TextAlignment = PropBag.ReadProperty ("TextAlignment", _
m_def_TextAlignment)
UserControl.BackColor = PropBag.ReadProperty ("BackColor", _
SH8000000F)
End Sub
' Сохранение значений свойств
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
Call PropBag.WriteProperty("Font", Font, Ambient.Font)
Call PropBag. WriteProperty("BorderStyle",
UserControl.BorderStyle,0)
Call PropBag.WriteProperty("BackStyle", UserControl.BackStyle, 1)
Call PropBag.WriteProperty("Enabled", UserControl.Enabled, True) Call PropBag.WriteProperty ("ForeColor", UserControl.ForeColor, _
&H80000012)
Call PropBag. WriteProperty ("MousePointer", _
UserControl.MousePointer, 0)
Call PropBag. WriteProperty ("OLEDropMode", _
UserControl.OLEDropMode, 0)
Call PropBag.WriteProperty("Picture", Picture, Nothing)
Call PropBag. WriteProperty ("Caption", m_Caption, _
m_def_Caption)
Call PropBag.WriteProperty("Effect", m_Effect,
m_def_Effect)
Call PropBag. WriteProperty ("TextAlignment", _
m_TextAlignment, m_def_TextAlignment)
Call PropBag.WriteProperty ("BackColor", _
UserControl.BackColor, &H8000000F)
End Sub
' ВНИМАНИЕ! НЕ УДАЛЯЙТЕ И НЕ ИЗМЕНЯЙТЕ
' СЛЕДУЮЩУЮ ЗАКОММЕНТИРОВАННУЮ СТРОКУ
' MappingInfo=UserControl,UserControl,-1,BackColor
Public Property Get BackColor() As OLE_COLOR
BackColor = UserControl.BackColor
End Property
Public Property Let BackColor(ByVal New_BackColor As OLE_COLOR)
UserControl.BackColor() = New_BackColor
PropertyChanged "BackColor"
End Property
Программа довольно длинная, но не так сложна, как выглядит. Рассмотрим каждый раздел кода подробно, начиная с раздела объявлений.
Option Explicit
' Значения свойств по умолчанию
Private m_Caption As String
Private m_Effect As Integer
Private m_TextAlignment As Integer
Эти переменные содержат значения специальных свойств элемента управления. Свойства элемента управления отображены на закрытые переменные кода элемента управления. Как и в случае с компонентом ActiveX, чьи свойства доступны извне, эти свойства являются, фактически, простыми переменными. Позже будет видно, как элемент управления получает значение, введенное пользователем в окне свойств (или код во время выполнения), и связывает их с закрытыми переменными. (Вспомните манипулирование свойствами OLE-сервера с помощью процедур Property Let и Property Get, рассмотренное в предыдущей главе. Тот же самый подход работает и с элементами управления ActiveX, но об этом позже.).
Дальше следуют определения нескольких констант, которые соответствуют значениям определенным в окне Set Attributes мастера. Эти константы будут использоваться дальше в коде как начальные значения для различных свойств. Учтите, что нет необходимости запускать мастер для того, чтобы просто поменять эти значения. Можно отредактировать код элемента управления. Обратите также внимание имена констант основаны на именах свойств, и код можно легко редактировать.
' Значения свойств по умолчанию:
Const m_def_Caption = "3D Label"
Const m_def_Effect = 2
Const m_def_TextAlignment = 4
Дальше следуют объявления событий. Это события, которые были определены в первых двух окнах мастера и отображены на объект UserControl. Щелчок на элементе управления генерирует событие Click, которое передается приложению, как будто оно было сгенерировано самим элементом управления ActiveX. В списке определено несколько больше событий, но нет нужды повторяться.
' Объявления событий:
Event DblCllck()
Event Click()
Event KeyUp(KeyCode As Integer, Shift As Integer)
Event Keypress(KeyAscii As Integer)
Event KeyDown(KeyCode As Integer, Shift As Integer)
Event MouseUp(Button As Integer, Shift As Integer,
X As Single, Y As Single)
Event MouseMove(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Примечание
Если событие Click не было отображено на объект UserControl, то только UserControl будет видеть событие Click. Если нужно выполнять специальные действия, когда на элементе выполнен двойной щелчок, следует запрограммировать событие Click в коде элемента управления. Пользователь не сможет программировать событие Click, пока оно не будет инициировано из кода элемента управления.
В нашем элементе управления не требуется как-то по особенному использовать событие Click (и другие обычные события мыши и клавиатуры), поэтому предоставим их приложению, которое использует элемент управления ActiveX.
Установка и чтение значений свойств
Теперь рассмотрим несколько подпрограмм: по две для каждого свойства.
Программа 16.3. Процедуры свойства Caption
Public Property Get Caption() As String
Caption =
m_Caption
End Property
Public Property Let Caption(ByVal New Caption As String)
m_Caption = New Caption
PropertyChanged "Caption"
End Property
Каждое свойство определено двумя Public-процедурами:
• Property Let,
• Property Get.
Процедура Property Let вызывается каждый раз, когда свойство изменяется либо через окно свойств (во времени конструирования) либо из программы (во время выполнения). При изменении свойства работает код, состоящий из двух строк. Первая строка получает значение, передаваемое в параметре процедуры (которое является новым значением свойства), и присваивает его закрытой переменной, которая представляет свойство в элементе управления. Остальной код видит только локальное свойство m_Caption, а не фактическое свойство. Вторая строка сообщает Visual Basic, что свойство изменило значение. Метод PropertyChanged важен и должен быть включен в процедуру Property Let, так как именно так VB сохраняет любые изменения свойства, сделанные во время конструирования, чтобы эти значения имели эффект во время выполнения.
Процедура Property Get вызывается всякий раз, когда программа обращается к значению свойства. Эта процедура читает значение закрытой переменной m_Caption и присваивает его свойству Caption. Для каждого свойства должны быть определены процедуры Property Get и Property Let, включающие приведенные строки. Они составляют минимальный механизм для установки или чтения значений свойств.
Конечно, в эти процедуры можно добавлять и код проверки допустимости значений. Значение свойства TextAlignmen должно быть в диапазоне от 0 до 9. На данный момент элемент управления позволяет пользователю ввести любое значение этого свойства в окне свойств. Добавим проверку допустимости значения в процедуру Property Let для свойства TextAlignment. Сам код прост: он отвергает любые значения меньше 0 и больше 8.
Программа 16.4. Код проверки допустимости свойства TextAlignment в процедуре Property Let
Public Property Let TextAlignment(ByVal New_TextAlignment As _
Integer)
If m_TextAlignment >=0 And m_TextAlignitient<=8 Then
m_TextAlignment = New_TextAlignment
PropertyChanged "TextAlignment"
Else
MsgBox "Invalid value for this property"
' (Недопустимое значение для этого свойства)
End If
End Property
Оператор If проверяет допустимость введенного значения, и, если новое значение находится вне допустимого диапазона, попытка изменить свойство отклоняется. Измените процедуру Property Let согласно приведенной схеме и затем переключитесь на тестовую форму проекта. Выберите элемент управления FLEXLabel на форме, откройте окно свойств и установите свойство TextAlignment в заведомо недопустимое значение (13 или 1000, например). При попытке изменить свойство, установив его в недопустимое значение, элемент управления выдаст предупреждение и отклонит изменения. Пока не совсем понятно, как добиться, чтобы допустимые значения свойства отображались в раскрывающемся списке, как в других элементах управления VB? Это требует написания еще небольшого количества кода, о чем чуть позже.
После процедур Property Let и Property Get
для всех свойств идет код инициализации некоторых переменных.
Программа 16.5. Код инициализации
' Инициализация свойств элемента управления
Private Sub UserControl_InitProperties ()
Set Font = Ambient.Font
m_Caption = m_def_Caption
m_Effect = m_def_Effect
m_TextAlignment = m_def_TextAlignment
UserControl.BorderStyle = 1
UserControl.BackStyle = 1
End Sub
Операторы подпрограммы InitProperties() присваивают начальные значения закрытым переменным, которые представляют свойства элемента управления. Константы m_def_Caption, m_def_TextAlignment и m_def_Effect были определены ранее в программе. При помещении этого элемента управления на форму Visual Basic читает значения переменных m_Caption, m_TextAlignment и m_Effect и выводит их в соответствующих строках окна свойств элемента.
Сохранение и чтение значений свойств
Далее в тексте идут две интересные подпрограммы:
• ReadProperties;
• WriteProperties.
При изменении каких-либо свойств через окно свойств новые значения должны быть где-то сохранены. Зачем?
Приложение может (и обычно так и делает) изменять значения некоторых свойств во время выполнения. Но когда приложение останавливает свою работу и возвращается обратно в режим конструирования, свойства, измененные во время выполнения, должны принять те значения, которые они имели до старта программы - не значения по умолчанию, а те значения, которые они имели в режиме конструирования.
Visual Basic предусматривает специальный объект для сохранения всех значений свойств - PropertyBag. Этот объект предусматривает два метода: один - для сохранения значения свойства, другой - для его чтения. Разработчику элемента управления необязательно знать все подробности сохранения значений. Visual Basic сохраняет значения свойств и при запросе предоставляет их.
Первый метод имеет следующий синтаксис:
WriteProperty propertyName, value, defaultValue
где
propertyName - имя свойства (например, Effect), value
может иметь буквальное значение(1 или "some sizzling effect"), но почти всегда - это имя закрытой переменной, которая содержит значение свойства, defaultValue - значение свойства по умолчанию.
Примечание
Зачем нужно указывать одновременно и собственно значение и значение по умолчанию при вызове метода? Дело в том, что VB сравнивает эти два параметра, и, если значения совпадают, то VB не выполняет сохранение (для ускорения процесса сохранения и восстановления значений свойства). При последующем запросе значения свойства с помощью метода ReadProperty Visual Basic просто возвращает значение по умолчанию.
Метод ReadProperty имеет следующий синтаксис:
ReadProperty propertyName, defaultValue
где propertyName — имя свойства, defaultValue — значение этого свойства, сохраненное ранее в объекте PropertyBag. В коде события Write Properties объекта UserControl необходимо вызвать метод WriteProperty для каждого из свойств. Аналогично, в коде процедуры ReadProperties для каждого свойства необходимо вызвать метод ReadProperty. Ниже приведен код процедур Write Properties и ReadProperties сгенерированный мастером для элемента управления FLEXLabel.
Программа 16.6. Процедура ReadProperties элемента управления
' Загрузка значений свойств
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
Set Font == PropBag.ReadProperty("Font", Ambient.Font)
UserControl.BorderStyle = PropBag.ReadProperty ("BorderStyle", 0)
UserControl.BackStyle = PropBag.ReadProperty ("BackStyle", 1)
UserControl.Enabled = PropBag.ReadProperty("Enabled", True)
UserControl.ForeColor = PropBag.ReadProperty ("ForeColor", _
&H80000012)
UserControl.MousePointer = PropBag.ReadProperty ("MousePointer", 0)
UserControl.OLEDropMode = PropBag.ReadProperty ("OLEDropMode", 0)
Set Picture = PropBag.ReadProperty ("Picture", Nothing)
m_Caption = PropBag.ReadProperty("Caption", m_def_Caption)
m_Effect = PropBag.ReadProperty("Effect", m_def_Effect)
m_TextAlignment = PropBag.ReadProperty ("TextAlignment", _
m_def_TextAlignment)
UserControl.BackColor = PropBag.ReadProperty ("BackColor", _
&H8000000F)
End Sub
Программа 16.7. Процедура WriteProperties элемента управления
' Сохранение значений свойств
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
Call PropBag.WriteProperty("Font", Font, Ambient.Font)
Call PropBag.WriteProperty ("BorderStyle", UserControl.BorderStyle, 0)
Call PropBag.WriteProperty("BackStyle", UserControl.BackStyle, 1)
Call PropBag.WriteProperty("Enabled", UserControl.Enabled, True)
Call PropBag.WriteProperty("ForeCoior", UserControl.ForeColor, _
&H80000012)
Call PropBag.WriteProperty ("MousePointer", _
UserControl.MousePointer, 0)
Call PropBag.WriteProperty ("OLEDropMode", _
UserControl.OLEDropMode, 0)
Call PropBag.WriteProperty ("Picture", Picture, Nothing)
Call PropBag.WriteProperty("Caption", m_Caption, m_def_Caption)
Call PropBag.WriteProperty("Effect", m_Effect, m_def_Effect)
Call PropBag. WriteProperty ("TextAlignment", _
m_TextAlignment, m_def_TextAlignment)
Call PropBag.WriteProperty ("BackColor", _
UserControl.BackColor, &H8000000F)
End Sub
Передача событий
Последний раздел кода отображает различные события элемента управления на эквивалентные события объекта UserControl. Когда пользователь щелкает мышью на элементе управления ActiveX, Windows отправляет событие Click объекту UserControl. Разработчик элемента управления может обработать это событие в самом элементе управления (в этом случае приложение, которое использует элемент, не видит события Click), или передать событие приложению-контейнеру (в этом случае разработчик приложения, использующего элемент управления, сможет обработать сообщение), или сделать и то, и другое (сначала обработать событие в элементе управления, а затем передать его контейнеру).
Передать событие приложению можно с помощью метода
RaiseEvent. Событие Click объекта UserControl определено таким образом. Private Sub UserControl_Click()
RaiseEvent Click
End Sub
Код остальных событий практически идентичен. Эти события вызывают оператор ReiseEvent для передачи события приложению-контейнеру. Если событие имеет параметры, например KeyPress, эти параметры перечисляются в круглых скобках после имени события.
Все, что сделал мастер — это вставил достаточно простой код. За исключением методов ReadProperty и WriteProperty, все остальное должно быть более или менее знакомо большинству программистов на Visual Basic. ActiveX — элемент управления, следовательно, не намного сложнее по сравнению со стандартным проектом. Осталось добавить еще несколько строк кода. В конце концов, необходимо указать элементу управления, как выравнивать надпись и обрисовывать ее с трехмерным эффектом.
Смешанные серверные и клиентские сценарии
ASP-файл может содержать текст как серверного, так и клиентского сценария. Если вы хотите включить раздел сценария в Web-страницу, то поместите команды сценария между тегами
Также рассмотрим разработку серверных сценариев: чтение данных, поступающих от клиента, их обработку на сервере (в большинстве случаев для этого используются элементы управления ActiveX, расположенные на сервере) и построение Web-страниц в реальном времени для передачи их обратно клиенту. Независимо от типа сервера этот процесс требует использования Си-подобного программирования. Однако при использовании ASP и встроенных объектов задачи, которые обычно требуют применения Peri или C++, разрешимы средствами VBScript.
В оставшейся части этой главы мы ознакомимся с этими объектами и узнаем, как с их помощью упростить написание серверных сценариев. В конце главы рассмотрены некоторые основные компоненты (например,
Database (База данных)), позволяющие сценарию получить доступ к базам данных на сервере.
Проверку правильности вводимых данных выполняет
Validate
Проверку правильности вводимых данных выполняет событие
Validate элемента управления Data. Объявим это событие.
Private Sub object_Validate (action As Integer, save As Integer)
Параметр
action (действие) — это целое число, задающее операцию, выполнение которой вызывает данное событие. Его значения приведены в табл. 17.7.
Таблица 17.7. Значения параметра action (действие) события Validate
Константа
Значение
Описание
vbDataActionCancel
0
Отмена операции при выходе из процедуры
vbDataAction Move First
1
Метод MoveFirst (Перейти к первой записи)
vbDataActionMovePrevious
2
Метод MovePrevious (Перейти к предыдущей записи)
vbDataActionMoveNext
3
Метод MoveNext (Перейти к следующей записи)
vbDataActionMoveLast
4
Метод Move Last (Перейти к последней записи)
vbDataActionAddNew
5
Метод AddNew (Добавить новую запись)
vbDataAction Update
6
Операция обновления (не LfpdateRecord)
vb DataAction Delete
7
Метод Delete (Удалить)
vb DataAction Find
8
Метод Find (Найти)
vbDataAction Bookmark
9
Установлено свойство
Bookmark (Закладка)
vb DataActionClose
10
Метод Close (Закрыть)
vbDataActionUnload
11
Выгрузка формы из памяти
Чтобы отменить операцию, вызвавшую событие Validate, значение vbDataActionCancel может устанавливаться с помощью кода. Например, если пользователь изменяет данные в элементе управления, а затем щелкает на кнопке MoveNext, то можно отменить изменения и операцию MoveNext.
Параметр
save (сохранить) — это выражение типа Boolean, указывающее, изменялись ли данные. Можно установить его значение в False, чтобы отменить изменения.
Error
Другим полезным событием при проверке правильности данных является событие Error (Ошибка). Когда модифицируется запись в базе данных, механизм JET гарантирует, что введенные данные не противоречат правилам, определенным при проектировании базы данных. Например, если требуется, чтобы указанное поле было уникальным, то запись не будет модифицирована, если введенное значение уже использовалось. Если поле превышает максимальную длину, изменения будут также отклонены. Другими словами, механизм JET производит проверку данных самостоятельно. Он также выполняет проверку данных в соответствии с правилами, определенными в поле Validation Rule.
Если данные не удовлетворяют правилам, определенным в проекте базы данных, то генерируется ошибка выполнения программы. Перед сообщением об ошибке генерируется событие Error. Можно выявить причину ошибки, вызвав ее обработчик.
Объявим событие Error.
Sub Error (dataerr As Integer, response As Integer)
Параметр
dataerr (данные об ошибке) — номер ошибки, a response
(отклик) — целое число, которое устанавливается при появлении события, чтобы затем в обработчике ошибки выполнить соответствующие действия. Значения параметра response
перечислены в табл. 17.8. Ошибку необходимо обработать внутри процедуры Error и затем установить параметр response в 0, чтобы предотвратить генерирование ошибки выполнения программы.
Таблица 17.8. Значения параметра Response события Error
Константа
Значение
Описание
vbDataErrContinue vbDataErrDisplay
0
1
Продолжать выполнение
Отображение сообщения об ошибке (установлена по умолчанию)
События элемента
WebBrowser и объекта InternetExplorer
События элемента управления WebBrowser и объекта InternetExplorer вызываются тогда, когда пользователь перемещается к другому URL с помощью кнопок навигации Internet Explorer или методов передвижения элемента управления WebBrowser. Они контролируют процесс каждой загрузки и позволяют приложению узнать, когда загрузка страницы завершена.
BeforeNavigate2 (Перед перемещением).
Генерируется, когда WebBrowser собирается переместиться к другому LJRL. Это может быть вызвано внешней (вызов метода Navigate) или внутренней автоматизацией из сценария или когда пользователь щелкает на гиперссылке в текущем документе. Можно отменить передвижение в приложении, установив значение параметра Cancel метода в True.
Совет
Событие BeforeNavigate2 не срабатывает, если гиперссылка недопустима. Элемент управления, прежде всего, устанавливает контакт с Web-сервером, а затем перемещается к документу.
Метод BeforeNavigate2 имеет следующее объявление.
Private Sub WebBrowserI BeforeNavigate2(ByVal pDisp As Object, _
URL As Variant, Flags As Variant,
TargetFrameName As Variant, PostData As Variant, _
Headers As Variant, Cancel As Boolean)
Первый параметр — pDisp — представляет объект, на котором документ воспроизводится. Обычно этот объект - WebBrowser. Этот параметр можно использовать, чтобы обратиться к свойствам элементам управления. Его имя — PDisp.Name, pDisp Width и pDisp. Height — размеры элемента управления и т.д.
Параметр URL — это адресат URL (определенный методом Navigate или гипер-ссылкой), Flags - зарезервированный параметр. Параметр TargetFrameName — имя фрейма, в котором воспроизводится документ или значение NULL, если документ не должен отобразиться ни в каком фрейме. Параметры PostData и Header подобны соответствующим параметрам метода Navigate.
Приложение может устанавливать параметр Cancel (обратите внимание: он передается по ссылке) для отмены перемещения. Если установить этот параметр в True, то перемещение не будет даже начато. Для остановки уже начатого перемещения используется метод Stop.
NavigateComplete (Перемещение завершено). Генерируется после того, как элемент управления успешно переместился к новому положению. Некоторые ресурсы документа все еще могут загружаться (загрузка большого изображения продолжительна), но часть документа загружена с сервера и выполнение началось. Для прерывания этого процесса вызывается метод Stop.
Событие NavigateComplete объявляется следующим образом.
Sub WebBrowserl_NavigateComplete(ByVal URL As String)
Параметр
URL — это URL загружаемого документа.
DownloadBegin (Начало загрузки). Генерируется, когда стартует операция передвижения. Это событие инициируется после того, как сгенерировано событие BeforeNavigate (если передвижение не было отменено), которое сообщает прилйжению, что необходимо отобразить сообщение о занятости программы или изменить форму указателя мыши.
Событие DownloadBegin объявляется следующим образом.
Sub WebBrowserl_DownloadBegin()
DownloadComplete (Загрузка закончена). Генерируется, когда операция передвижения закончена, остановлена или завершена неудачно. В отличие от события NavigateComplete, которое не инициируется в случае неудачи, это событие всегда инициируется после начала передвижения. Любая индикация о занятости приложения управляется из обработчика этого события. Событие DownloadComplete объявляется следующим образом.
Sub WebBrowserl_DownloadComplete()
ProgressChange (Состояние процесса загрузки). WebBrowser прослеживает развитие операции загрузки и периодически выдает событие ProgressChange, чтобы сообщить приложению о степени загрузки. Событие ProgressChange объявляется следующим образом.
Sub WebBrowserl_ProgressChange(ByVal Progress As Long, _
ByVal ProgressMax As Long)
Оба параметра являются длинными целыми числами. Параметр Progress — количество уже загруженных данных, a ProgressMax — общее количество данных, которые будут загружены.
Совет
Процент загруженных данных — это отношение Progress ProgressMax.
Необходимо всегда проверять значение ProgressMax, потому что его значение может быть нулевым (если элемент управления не знает общего объема данных, которые будут загружены). Более того, событие ProgressChange вызывается для каждого из ресурсов документа, и не существует способа узнать заранее полный размер элементов управления, которые загружаются. Отметим: InternetExplorer воспроизводит прогресс загрузки каждого элемента управления, а не всего документа.
TitleChange (Изменение заголовка). Генерируется, когда заголовок текущего документа изменяется. Заголовок HTML-документа может изменяться: когда документ загружается, его заголовком является URL. После того, как реальный заголовок (если он определен с помощью метки TITLE) проанализирован, вызывается событие TitleChange. Его можно использовать для модификации свойства Caption на форме Visual Basic. Событие TitleChange объявляется следующим образом.
Sub WebBrowserl_TitleChange(ByVal Text As String)
Параметр
Text - это строка, которая появляется в строке заголовка InternetExplorer.
NewWindow (Новое окно).
Хотя результат большинства гиперссылок воспроизводится в том же окне, что и содержащий их документ, некоторые гиперссылки требуют открытия нового окна для отображения документа. Событие NewWindow вызывается непосредственно перед созданием нового окна.
Это событие можно вызвать, если удерживать нажатой клавишу SHIFT и щелкнуть кнопкой мыши на гиперссылке или выбрать команду Open в меню New Window контекстного меню. Событие NewWindow позволяет приложению отменить создание нового окна. Когда это событие используется с InternetExplorer, то новое окно является еще одним экземпляром InternetExplorer.
Когда событие NewWindow используется при работе с элементом управления WebBrowser, то приложение должно создать новый элемент управления WebBrowser и показать в нем документ или потребовать, чтобы новый документ отображался в том же окне. Если приложение создает новый элемент управления WebBrowser, то необходимо передать все параметры из события NewWindow непосредственно методу Navigate последнего созданного элемента управления WebBrowser. При отображении нового документа на том же элементе управления необходимо опять-таки передать параметры этого события в метод Navigate существующего окна.
Событие NewWindow объявляется следующим образом.
Sub WebBrowser_NewWindow (ByVal uri As String, _
ByVal Flags As Long, ByVal TargetFrameName As String, _
PostData As Variant, ByVal Headers As String, _ Processed As Boolean)
Параметры события NewWindow идентичны параметрам метода Navigate, кроме последнего, принимающего значения True или False и указывающего, создаст приложение новое окно (True) или нет (False).
FrameBeforeNavigate, FrameNavigateComplete, FrameNewWindow. Эти события идентичны событиям BeforeNavigate, NavigateComplete и NewWindow, но вызываются из фреймов.
и Application поддерживают события Start
Start и End
Объекты Session и Application поддерживают события Start (Начать) и End (Завершить), которые сигнализируют о начале и завершении сеанса и приложения соответственно. Эти события имеют следующий вид:
• Scssion_OnStart
• Application_OnStart
• Session_OnEnd
• Application_OnEnd
Обработчики этих событий содержат код, который выполняется, когда приложение или сеанс стартуют и завершаются. Если приложение запускается одновременно с началом сеанса, то первым происходит событие Application_OnStart. Оба эти события важны при разработки ASP-приложсний. К сожалению, они недоступны из кода сценария. Их обработчики следует поместить в файл GLOBAL.ASA, который находится в корневой папке приложения (в ней находится первый ASP-файл, запрошенный клиентом). Обычно файл GLOBAL.ASA содержит обработчики событий Start и End объектов Session и Application, а также объявления переменных.
Например, если нужна переменная для хранения количества пользователей, подключенных к вашему узлу, то ее нужно инициализировать в обработчике события Application_OnStart. Для этого введите в файл GLOBAL.ASA следующие строки.
Это событие происходит каждый раз, когда запускается программное обеспечение сервера. Поскольку разумнее не инициализировать переменную при каждом рестарте сервера, сохраните значение переменой Visitors в текстовом файле на диске сервера, как показано в гл. 20. Теперь можно в обработчике события Application_0n Start читать значение этой переменной и увеличивать его на 1 в обработчике события Session_OnStart.
Эту процедуру также следует поместить в файл
GLOBAL.ASA. При таком подходе значение счетчика не увеличивается, когда пользователь обращается к начальной странице в течение одного сеанса, поскольку событие Session_OnStart происходит только при первом обращении к начальной странице.
Отображение счетчика в какой- либо оригинальной форме является отдельной задачей. Пока можно просто выводить его значение шрифтом большого размера или генерировать GIF-файл и отображать его на стартовой странице. Элемент управления Structured Graphics, поставляемый с Internet Explorer 4.0, позволяет создавать достаточно сложные изображения несколькими строками кода. Использование этого элемента — простейший способ красочного отображения счетчика пользователей.
Если ваши Web-страницы во время сеанса часто обращаются к некоторому компоненту, то можно объявить объектную переменную в событии
Session_OnStart. Эта переменная будет доступна всем страницам в течение текущего сеанса. Приведем пример, в котором создается объектная переменная, ссылающаяся на компонент MyObject.
Sub Session_OnStart
Set Session ("MyObj") "Server.CreateObject ("MyObject")
End Sub
Во время текущего сеанса любая страница может обращаться к пергменной MyObj, и одноименные переменные, принадлежащие разным сеансам, являются абсолютно независимыми.
Составные документы
Документ, содержащий объекты нескольких типов, называется составным. Например, Word-документ, содержащий таблицу Excel или изображение, является составным документом. Попытки разработать многофункциональные прикладные программы, позволяющие работать с текстом, числами, изображениями, средствами связи и выполнять прочие функции, необходимые среднему пользователю, были неудачными до тех пор, пока не появилась технология OLE.
Парни из Microsoft учли потребность среднего пользователя в средстве, позволяющем объединять любимые прикладные программы. Они также поняли, что создать универсальное приложение невозможно и придумали OLE, позволяющее приложениям обмениваться данными и функциями. Поскольку OLE-приложения могут быть связаны друг с другом, пользователи могут использовать их отдельные компоненты для создания собственных приложений. Красота OLE состоит в том, что для использования в вашем приложении возможностей другого приложения нет необходимости знать детали его реализации. Аналогично, тому, кто программирует на Visual Basic, нет нужды знать подробности выполнения операций элементом управления RichTextBox или функционирования элемента MSFlexGrid.
Создание активных серверных страниц
Простейшим способом создания ASP является изменение расширения файла, содержащего HTML-документ, с НТМ на ASP. Перенесите этот файл в новую папку корневой папки Web-сервера. Во всех примерах этой главы предполагается, что ASP-страницы находятся в папке ASPages, а сами примеры - на прилагаемом компакт-диске в папке с тем же именем.
ASP-файлы и права исполнения
Содержимое ASP-файлов является текстом, но, с другой стороны, это -программа. При вызове этого файла его содержимое компилируется, и его исполняемая часть помещается в кэш. Поэтому ASP-файлы хранятся в папках, обладающих правом Scripts.
С помощью административной утилиты Web-сервера создайте виртуальную папку, назовите ее ActivePages и отобразите ее на ASPages в корневом каталоге Web. Назначьте этой папке право Scripts. Назначать право Execution (Выполнение) необязательно, поскольку ASP-файлы не являются исполняемыми.
Начнем с тривиального примера (см. гл. 20). Это простой HTML-файл, который отображает время на экране клиента (рис. 22.3).
Рис. 22.3. Страница DATETIME.HTM
Программа 22.1. Файл DATETIME.HTM
Simple ASP Demo<\TITLE>
Active Server Pages contain text, HTML code and scripts that
are executed on the client, ]ust like ordinary HTML documents. The
DateTime.asp file contains a client-side script, which prints the
date and the time on the client and then displays the document's
body.
Это клиентский сценарий, который вызывает функции
Date() и Time(). Он выполняется на компьютере клиента и, как следствие, отображает дату и время, считанные с его системных часов.
Изменим эту страницу так, чтобы она отображала дату и время сервера. Для этого необходимо добавить операторы, которые будут исполняться на сервере. Скопируйте файл DATETIME.HTM в файл SRVRTIME.ASP и замените сценарий следующим.
Response. Write ""
Response.Write "Welcome to the Active Server Pages "
Response. Write "The date is " & Date() & " and the time is "
& Timef) & " "
Response.Write ""
Объект Response (Отклик) эквивалентен объекту Document (Документ), но сервер, в отличие от клиента, не имеет доступа к объекту Document. Вместо этого он должен использовать метод Write (Писать) объекта Response для вывода на экран клиента. Все, что вы "пишете" в объект Response, помещается в выходной поток и пересылается клиенту, как если бы это был существующий HTML-документ. Переработанная страница осуществляет вывод, аналогичный выводу предыдущей страницы, однако при этом отображается дата и время сервера. Модификатор RUNAT в теге
Строка, возвращаемая функцией, может использоваться в сценарии.
Создание базового прототипа элемента управления
Начнем с создания прототипа элемента управления.
Для этого выполните следующие шаги.
1 . Выберите команду New Project меню File, чтобы открыть окно нового проекта.
2 . Щелкните на пиктограмме ActiveX Control. Visual Basic создаст новый проект, который содержит UserControl, с названием UserControll. Он представляет собой форму, на которой будет построен видимый интерфейс.
3 . Выберите команду Add Project меню File, чтобы добавить Standard ЕХЕ-проект. Visual Basic создаст новый проект с одной формой Formi, которую будем использовать в качестве тестовой (Formi часто называют тест-формой, а проект, которому она принадлежит - тест-проект). Перед вами базовый прототип элемент управления.
4 . Сейчас можно переименовать и сохранить проект. Для данного проекта можно использовать имена, заданные по умолчанию.
5 . Закройте окно конструирования элемента управления для активизации его пиктограммы на панели элементов управления.
6 . Поместите экземпляр нового элемента управления на форму. Вновь созданная форма элемента управления не должна имеет цвета фона или рамки, что отличало бы ее от формы, на которой она лежит.
7 . Выберите элемент управления и откройте окно Properties.
По умолчанию, объект UserControl имеет следующие свойства:
Draglcon
Left
Top Left
DragMode
Tablndex
Visible
Height
TabStop
WhatIsThisHelpID
HelpContextID
Tag
Width
Index
ToolTipText
Эти свойства, фактически, поддерживаются контейнером. Свойство Left определено контейнером и имеет значение только в контексте контейнера. Аналогично, Tablndex и TabStop не управляются элементом непосредственно, потому что элемент управления не знает, какие еще элементы управления существуют на форме. Только форма знает это и, следовательно, должна поддерживать эти свойства для элементов управления.
Испытайте несколько свойств. Присвойте значение "My generic control" свойству ToolTipText. Запустите приложение, а затем наведите указатель мыши на элемент управления. Введенная строка появится над элементом управления. Подобным способом можно проверить свойство Tag, присваивая ему строку или свойство Index, создавая экземпляры одного элемента управления на форме с одинаковым именем и различным значением Index. При этом не нужно добавлять ни строчки кода для реализации этих свойств.
Создание элементов меню, содержащих растровые изображения
Элементы меню, создаваемые средствами Menu Editor (Редактор меню) Visual Basic, не всегда содержат только текст. В некоторых прикладных программах может потребоваться, чтобы элемент меню содержал растровое изображение. Добавить растровые изображения к элементам меню можно с помощью нескольких API-функции. Разработка таких элементов меню занимает немало времени, но результат того стоит Приложение MenuBMP (рис 13.4) позволяет создавать элементы меню с растровыми изображениями.
VB6 в действии: проект MenuBMP
В этом приложении используются такие API-функции:
• GetMenu()
• GetSubMenu()
• ModifyMenu()
• CreateCompatibleDC()
• CreateCompatibleBitmap()
• Select0bject()
Рис. 13.4. Приложение MenuBMP
Чтобы манипулировать элементами меню с помощью API-функций, необходимо получить дескриптор элемента меню. Элементы меню являются объектами, и поэтому им поставлены в соответствие дескрипторы, которые идентифицируют их с точки зрения операционной системы (точно так идентифицируются формы и растровые изображения). Более того, можно манипулировать элементами меню других приложений, запущенных в настоящий момент, если получить дескриптор этого элемента меню.
Для получения дескриптора элемента меню используется функция GetMenu(). Объявим ее:
Private Declare Function GetMenu Lib "user32" (ByVal hWnd _
As Long) As Long
Параметр
hWnd является дескриптором формы, элементами меню которой требуется манипулировать. Для получения дескриптора меню текущей формы используется следующее выражение.
MenuHandle = GetMenu(Me.hWnd)
Меню первого уровня содержат подменю, которые идентифицируются их порядком в главном меню. Подменю имеют свои дескрипторы, которые можно получить с помощью функции
GetSubMenu().
Private Declare Function GetSubMenu Lib "user32" _
(ByVal hMenu As Long, ByVal nPos As Long) As Long
Параметр
hMenu - это дескриптор меню, возвращаемый функцией GetMenu(), а параметр nPos — номер текущей позиции подменю. Если значение параметра nPos равно 0, то функция GetSubMenu() возвращает дескриптор первого подменю (им часто оказывается меню File (Файл)).
После того как дескриптор подменю получен, его можно модифицировать с помощью функции
ModifyMenu().
Private Declare Function ModifyMenu Lib "user32" Alias _
"ModifyMenuA" (ByVal hMenu As Long, ByVal nPosition _
As Long, ByVal wFlags As Long, ByVal wIDNewItem As _
Long, ByVal IpString As Any) As Long
Эта функция позволяет изменить элемент меню. Поясним это. Параметр hMenu — это дескриптор подменю, полученный с помощью функции GetSubMenu() Параметр nPosition
идентифицирует элемент меню, который требуется изменить. Если в параметре wFlags установлен флаг MF_BYCOMMAND, то этот параметр относится к ID (Идентификатору) команды меню, которая будет изменена. Если же установлен флаг MF_BYPOSITION, то параметр определяет номер позиции элемента подменю. Параметр wFlags является комбинацией флагов, описанных в табл. 13.4.
Таблица 13.4. Флаги меню
Значение
Описание
MF_BITMAP
Указывает, что элемент меню содержит растровое
изображение. Растровое изображение остается в
памяти, пока используется указанный элемент меню
MF_BYCOMMAND
Определяет элемент меню командой ID меню
MF_BYPOSITION
Определяет элемент меню его позицией в подменю:
номер позиции первого объекта равен нулю
MF_CHECKED
Отображает метку выбора, устанавливая ее слева от
элемента меню
MF_DISABLED
Делает элемент меню недоступным
MF_ENABLED
Делает элемент меню доступным
MF_G RAYED,
Делает элемент меню недоступным и выводит его,
заливая изображение серым цветом (вместо того, чтобы
сделать его невидимым)
M F_MENUBARBREAK
Помещает элемент меню в новый столбец, отделяя его
вертикальной линией
MF_MENUBREAK
Помещает элемент меню в новый столбец
MF_POPUP
Подключает дополнительное раскрывающееся меню к
элементу меню
MF_SEPARATOR
Помещает горизонтальную линию разделителя под
элементом меню
MF_STRING
Помещает строку в элемент меню
MF_JJNCHECKED
Снимает метку выбора слева от элемента меню (если
элемент был выделен)
<
Чтобы связать растровое изображение с пунктом меню, необходимо установить флаг MF_BITMAP в параметре wFlags
функции ModifyMenuO. Процедура изменения меню относительно проста, но с заданием растрового изображения, помещенного в заголовок элемента меню, дело обстоит иначе. Сначала необходимо создать контекст устройства (т.е. область памяти, в которой будет храниться растровое изображение) с помощью функции CreateCompatibleDC().
Набор данных, составляющих растровое изображение (обычно это BMP-файл), загружается в скрытый элемент управления PictureBox. Из него растровое изображение копируется в контекст устройства с помощью функции CreateCompatibleBitmap(). После того как растровое изображение помещено в контекст устройства, его можно связать с элементом меню, как строку текста Фрагмент программы 13.5 содержит код, реализующий добавление растрового изображения к элементу меню приложения MenuBMP.
Обратите внимание размеры растрового изображения должны быть переданы как параметры функции CreateCompatibleBitmap(). Создавая растровое изображение с помощью графического редактора, необходимо задавать изображению такие размеры, чтобы они соответствовали размерам элемента меню. Не следует делать его слишком высоким или слишком узким Растровые изображения в рассматриваемых примерах были созданы в программе PaintShopPro. Для создания растровых изображений можно использовать любой графический редактор, включая ImageEdit (папка Tools прилагаемого компакт-диска).
Меню Bitmaps приложения MenuBMP содержит три команды, соответствующие трем различным шрифтам (см. рис. 13.4). Три растровых изображения хранятся в файлах Verdana.bmp, Serif.bmp и Comic.bmp в той же папке, что и приложение. После разработки растровых изображений можно начинать работать с программой. Полный текст программы MenuBMP приведен ниже.
Программа 13.5. Приложение MenuBMP
Option Explicit
Private Declare Function GetMenu Lib "user32" _
(ByVal hwnd As Long) As Long
Private Declare Function GetSubMenu Lib "user32"
( ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function GetMenuItemID Lib "user32"
(ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function ModifyMenu Lib "user32"
Alias "ModifyMenuA" (ByVal hMenu As Long, _
ByVal nPosition As Long, ByVal wFlags As Long, _
ByVal wIDNewItem As Long, ByVal IpString As Any) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" _
(ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" _
(ByVal hdc As Long, ByVal nWidth As Long,
_
ByVal nHeight As Long) As Long
Private Declare Function SelectObject Lib "gdi32" _
(ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function BitBIt Lib "gdi32" _
(ByVal hDestDC As Long, ByVal x As Long, ByVal у As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal hSrcDC As Long, ByVal xSrc As Long, _
ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" _
(ByVal hdc As Long) As Long
Const SRCCOPY &HCC0020
Const MF_BYPOSITION - &H400&
Const MF_BITMAP &H4&
Private Sub Form_Load()
Dim Width As Integer, Height As Integer
Dim hTmpDC As Long, hMenuID As Long
Dim hBitmap As Long, retValue As Long
Dim tmpID As Long
Dim fileName As String
Dim menuPos As Integer, menuID As Long
‘ Установка позиции меню и имени файла
menuPos = 0
fileName = App.Path & "\verdana.bmp"
Picturel.Picture = LoadPicture(fileName)
Width = 64
Height = 16
‘ Получение дескриптора меню
hMenuID = GetSubMenu(GetMenu(Me.hwnd), menuPos)
‘ Создание контекста устройства для хранения растрового
‘изображения
hTmpDC = CreateCompatibleDC(Picturel.hdc)
‘ Создание растрового изображения
hBitmap = CreateCompatibleBitmap(Picturel.hdc, Width, Height)
‘ Выбор растрового изображения во временный контекст
tmpID = SelectObject(hTmpDC, hBitmap)
‘ Копирование содержимого из элемента управления в контекст
‘ устройства
retValue = BitBIt(hTmpDC, 0, 0, Width, Height, _
Picturel.hdc, 0, 0, SRCCOPY)
‘ Отмена выбора
tmpID = SelectObject(hTmpDC, tmpID)
‘ Модификация меню
menuID = GetMenuItemID(hMenuID, menuPos)
retValue = ModifyMenu(hMenuID, menuPos, _
MF_BYPOSITION Or MF_BITMAP, menuID, hBitmap)
‘ Второй пункт меню
menuPos = 1
fileName = App.Path & "\serif.bmp"
Picture1.Picture = LoadPicture(fileName)
‘ Создание растрового изображения для элемента меню
hBitmap = CreateCompatibleBitmap(Picturel.hdc. Width, Height)
‘ Выбор растрового изображения во временный контекст
‘ устройства
tmpID = SelectObject(hTmpDC, hBitmap)
retValue = BitBIt(hTmpDC, 0, 0, Width, Height, _
Picture1.hdc. О, О, SRCCOPY)
tmpID = SelectObject(hTmpDC, tmpID)
menuID = GetMenuItemID(hMenuID, menuPos)
retValue = ModifyMenu(hMenuID, menuPos,
MF_BYPOSITION Or MF_BITMAP, menuID, hBitmap)
‘Третий пункт меню menu
Pos = 2
fileName = App.Path & "\comic.bmp"
Picture1.Picture = LoadPicture(fileName)
‘ Создание растрового изображения для элемента меню
hBitmap = CreateCompatibleBitmap(Picturel.hdc, Width, Height)
‘ Выбор растрового изображения во временный контекст устройства
tmpID = SelectObject(hTmpDC, hBitmap)
retValue = BitBIt(hTmpDC, 0, 0, Width, Height, _
Picturel.hdc. О, О, SRCCOPY)
tmpID = SelectObject(hTmpDC, tmpID)
menuID = GetMenuItemID(hMenuID, menuPos)
retValue = ModifyMenu(hMenuID, menuPos, _
MF_BYPOSITION Or MF_BITMAP, menuID, hBitmap)
‘ Очистка
retValue = DeleteDC(hTmpDC)
End Sub
Private Sub MyMenu Click(Index As Integer)
Dim fName(3) As String
fName(0) = "Verdana"
fName(l) = "Serif"
fName(2) = "Comic Sans MS"
Me.CIs
Me.CurrentX = (Me.ScaleWidth - TextWidth(fName(Index)))/2
Me.CurrentY = (Me.ScaleHeight - TextHeight(fName(Index)))/2
Me.Font.Name = fName(Index)
Me.Print fName(Index)
End Sub
Создание набора записей
Если связь с базой данных установлена, то можно использовать SQL-операторы для манипулирования записями. Чтобы выполнить SQL-оператор, используйте метод Execute объекта Connection, передав ему этот оператор в качестве аргумента.
DBConnection.Execute SQLStatement
Аргумент
SQLStatement - это строка, содержащая SQL-оператор или имя сохраненной процедуры. Если SQL-оператор возвращает набор записей (Recordset), как оператор SELECT, то его следует вызывать следующим образом.
Set SelRecords = DBConnection.Execute(SQLStatement)
Метод Execute принимает два необязательных аргумента:
• количество записей, на которые воздействует данная операция (значение этого параметра устанавливается драйвером);
• признак, указывающий, является аргумент SQLStatement SQL-оператором или именем сохраненной процедуры.
Полный синтаксис метода имеет следующий вид.
DBConnection.Execute SQLStatement, numRecords, SQLText
Аргумент
SQLText принимает значения adCmdText (для SQL-оператора) и adCmdStoredProc (для сохраненной процедуры).
Другим способом выполнения SQL-оператора является создание объекта Command с помощью оператора:
Set SQLCornmand = Server. CreateObject ("ADODB. Command")
и выполнение SQL-оператора с помощью метода
Execute объекта SQLCommand. Объект Command предоставляет несколько свойств, позволяющих уточнить, какой оператор и каким образом будет выполняться.
Например, можно указать объект Connection, к которому будет применяться объект Command (в случае нескольких открытых соединений), задать значения параметров для сохраненных процедур и т.п.
Обычно объект Command используется следующим образом.
Set DBConnection = Server.CreateObject ("ADODB.Connection")
Set SQLCommand = Server. CreateObject ("ADODB. Command")
Set Paramltetri = Server. CreateObject ("ADODB. Parameter")
SQLCommand.ActiveConnection = DBConnection
SQLCommand.CommandText = "ProductsByCategory"
SQLCommand.CommandType = adCmdStoredProc
ParamItem.Name = "@ProductCategory"
ParamItem.Value = 31
SQLCommand.Parameters.Append ParamItem
SQLCommand.Execute
Здесь
ProductCategory — имя параметра, который одновременно является именем сохраненной процедуры. Во время выполнения этой переменной присваивается значение (в предыдущем примере - 31). Приведенные операторы используют объект Command для выполнения сохраненной процедуры с параметрами. Этот код можно упростить с помощью оператора With.
Set DBConnection = Server.CreateObject("ADODB.Connection")
Set SQLCommand = Server. CreateObject ("ADODB. Command")
Set Paramltem = Server.CreateObject ("ADODB. Parameter")
With SQLCommand
.ActiveConnection = DBConnection
.CommandText = "ProductsByCategory"
.CommandType = adCmdStoredProc
With Paramltem
.Name = "@ProductCategory"
.ParamItem.Value =31
.Parameters.Append ParamItem
EndWith
.Execute
End With
Создание объектных переменных
В предыдущей главе было показано, как получать доступ к объектам посредством объектной переменной. Также были изучены два метода объявления объектной переменной:
1 . Объявление объектной переменной с ключевым словом New.
Private objectVar As New objectType
2 . Объявление объектной переменной с последующим присваиванием ей объекта, который необходимо использовать:
Private objectVar As objectType
Set objectVar = New objectType
Оба метода требуют, чтобы Visual Basic знал тип объекта.
Можно ожидать, что Visual Basic знает о формах, элементах управления и других типах встроенных объектов, но что можно сказать об объектах, созданных разработчиком? Так как Visual Basic ничего не знает об вновь созданном объекте, необходимо обеспечить доступ проекта к объекту посредством добавления в него ссылки на этот объект. Например, если нужно добавить к проекту класс CTimer, откройте меню Project и выберите References. В появившемся диалоговом окне References найдите объект, на который нужно сослаться в коде, и нажмите ОК.
Если после добавления в проект новой ссылки открыть окно Object Browser, можно увидеть список Type Library (Библиотеку типов) с только что добавленным объектом. Выберите его в списке Type Library для просмотра классов, которые он предоставляет. Проект CTimer предоставляет один класс - CTimer. Щелкните на его имени для просмотра его членов.
Итак, пока к проекту не добавлена ссылка на определенный объект, невозможно объявить переменную этого типа. Существует третий метод объявления объектных переменных - функция Create0bject(), которая требует предоставления имен приложения и класса. Сначала объявите объектную переменную, а затем присвойте ей экземпляр объекта:
Private TMR As Object
Set TMR = CreateObject ("TimerProject.CTimer")
Оператор Set обычно помещается в событии Form_Load или в процедуре, которой необходим доступ к объекту. Можно заменить объявление объектной переменной TMR в тестовом приложении на способ, использующий функцию CreateObject. Остальная часть программного кода останется прежней.
Создание проекта
Data
Чтобы увидеть новый визуальный инструмент в действии, создайте новый проект и в диалоговом окне типа проекта выберите Data Project. Проект Data — это не специальный тип проекта, а стандартный ЕХЕ-проект, но Visual Basic при этом загружает, на панель элементов управления все инструменты для работы с базами данных.
В окне проводника проекта отобразится, как обычно, новая форма и два конструктора ActiveX. Конструктор ActiveX - это специальная надстройка (add-in), предназначенная для упрощения разработки двух типов компонентов:
• DataEnvironment,
• DataReport.
Компонент
Data Environment
предназначен для подключения к базе данных и получения из нее записи. Компонент DataReport позволяет создавать отчеты и использовать их в приложении. Оба компонента основаны на визуальных инструментах для работы с базами данных и не требуют программирования. Конечно, нельзя обойтись без программирования, но его способы программирования напоминают способы, рассмотренные в предыдущей главе.
Панель элементов управления проекта Data содержит большое количество элементов управления ActiveX. Перечислим некоторые из них.
• ADODC (ADO Data Control — элемент управления данными ADO) — эквивалентен элементу управления Data.
• DataList и DataCombo — усовершенствованные версии элементов управления ListBox и ComboBox, предназначенные для работы с базами данных (data-bound -связанные с данными). Работают с элементами управления ADO, но не с элементами управления DAO.
• MSHFlexGrid - иерархический элемент управления Grid (Сетка), который работает с элементами управления DAO. Элемент MSHFlexGrid похож на элемент управления MSFlexGrid (см. гл. 9), но заполняется автоматически с помощью конструктора DataEnvironment.
В следующем параграфе будут рассмотрены конструкторы ActiveX — DataEnvironment и DataReport. Чтобы понять, что такое конструктор ActiveX и как он облегчает разработку проекта Data, рассмотрим основные требования к приложению, работающему с базами данных.
Для доступа к базе данных с помощью ADO (или другого инструмента) необходимы объекты двух типов:
• один или более объектов Connection и
• один или более объектов Command.
Объект Connection соединяет приложение с базой данных, a Command —
извлекает записи из базы данных. Он может использоваться и для изменения содержимого базы данных, но мы не будем это рассматривать подробно. Объект Command принимает, а затем выполняет SQL-оператор. Если это — SQL-запрос, то командный объект возвращает набор записей (RecordSet), соответствующих запросу. Если это — SQL-операция, то командный объект выполняет ее, и одна или больше записей обновляются (командный объект может возвращать записи, измененные операцией).
Другая операция, широко используемая при разработке приложений для баз данных - генерация отчетов. Получить нужные данные из базы данных несложно, но создание многостраничного отчета (с подведением итогов и т.д.) в общем случае является нетривиальной задачей. Многие разработчики используют инструменты третьих фирм для создания отчетов, особенно если они печатаются на разных принтерах — для них это действительно проблема. Конструктор
DataReport позволяет создавать структуры отчетов, используя операции типа "укажи и нажми". При этом сначала нужно определить данные, которые будут включены в отчет с помощью объекта DataEnvironment, работающего в связке с конструктором ActiveX элемента DataReport. Он позволяет без программирования реализовать дополнительные операции для работы с базами данных (запросы и отчеты).
Создание строки параметров
Можете воспользоваться одним из двух способов построения URL для запроса приложения на сервере и передачи ему параметров.
• Поместите требуемые параметры в тег и предоставьте броузеру право соединения с сервером и передачи параметров, заданных значениями элементов управления на форме.
• Создайте строку параметров с использованием команд VBScript и передайте ее на сервер, вызвав метод Navigate объекта Window.
Рассмотрим первый и наиболее простой способ. Для этого вернемся к странице FORM.HTM (см. гл. 19). Раздел Form на странице (рис. 22.2) создан с помощью следующего тега.
Атрибут ACTION указывает URL приложения, которое нужно запустить. В данном случае — это ASP-приложение в виртуальной папке ASPages на Web-узле, на который передается страница. Атрибут METHOD определяет один из двух методов передачи данных от клиента на сервер. В примерах этой главы используется метод GET. Альтернативным является метод POST, который имеет ограничения на длину строки, передаваемой на сервер.
Раздел Form страницы FORM.HTM (рис. 22.2) содержит элементы управления и значения, перечисленные в табл. 22.1.
После нажатия кнопки Submit (Передать) в нижней части формы, клиент передает на сервер показанную ниже строку. При этом броузер автоматически создает ее (на этой странице сценарий не требуется).
http://127.0.0.I/Register.asp?LName=Brannon&FName=Andrea&Mail= ABrannon@USA.net&hardware=PC&browser=IE&Sports=ONSStock=ON& Bargains=ON&mail=YESsRegister=Register+Now%21
Рис. 22.2. Страница FORM.HTM запускает приложение на сервере и передает значения элементов управления в виде параметров
Таблица 22.1. Элементы управления и их значения из раздела Form
Элемент управления
Значение
Lname
Brannon
Fname
Andrea
Email
Abrannon@USA.net
Hardware
PC
Browser
IE
Sports
ON
News
OFF
Stock
ON
Weather
OFF
Bargains
ON
Mail
YES
Другой способ передачи параметров на сервер — создание строки параметров с помощью команд VBScript и передача ее на сервер вызовом метода Navigate объекта Window. Вот как может выглядеть обработчик события Click кнопки Command, выполняющий эту функцию.
Sub button1_onClick()
URLString =
"http://www.servername.com/Register.asp?Lname=
Brannon&Fname=Andrea&Email=Abrannon@USA.net"
Window.Navigate URLString
End Sub
Переменная
URLString является обычной длинной строкой. Однако чтобы поместить ее на печатной странице, ее придется разорвать. Обычно такие строки строятся по частям с использованием операции сцепления строк.
Как видите, первый способ намного проще. Если нет необходимости передавать значения, хранящиеся в элементах управления, то используйте именно этот способ.
Создание
Internet-совместимых элементов управления
С приходом эры Интернет и объединения рабочего стола с Web, что демонстрируют Active Desktop и последняя версия Internet Explorer, средства управления ActiveX должны обладать возможностью подсоединения к Интернет и загрузки информации с HTTP-серверов. Независимо от того, как много информации можно получить с помощью имеющихся средств, на сервере всегда остается новейшая информация. Интересная, и во многих случаях необходимая, возможность, которую можно добавить к элементам управления - соединение с HTTP и загрузка информации по запросу.
Элементы ActiveX, разрабатываемые с помощью Visual Basic, поддерживают асинхронную загрузку значений свойств. Это значит, что значением свойства может быть файл на Web-сервере, а элементы управления пользователя могут обращаться к серверу и загружать с него информацию. Для загрузки файла из URL используют метод AsyncRead со следующим синтаксисом.
UserControl_AsyncRead Target, AsyncType [, PropertyName]
Строка
Target определяет адрес, по которому находятся данные. Это URL удаленного HTTP-сервера или путь к файлу на локальном или сетевом диске. Например, URL - http://www.servername.corn/Updates/Latest.txt, путь к локальному файлу - file://m:\Software\Updates\Latest.txt.
Тип файла для загрузки определяется аргументом AsyncType, значения которого перечислены в табл 21.5.
Таблица 21.5. Возможные значения аргумента AsyncType метода AsyncRead
Константа
Описание
vbAsyncTypeFile
vbAsyncTypeByteArray
vbAsyncTypePicture
Данные находятся в файле, который можно будет открыть с помощью Visual Basic
Данные в виде массива байтов. Приложение должно обрабатывать элементы массива
Данные — объект
Picture (изображение)
Последний необязательный аргумент — имя свойства, которое будет загружено. Имя - это просто идентификатор, использующийся для получения значения загруженного свойства или отказа от загрузки данных. Далее в примерах показано различие между аргументом PropertyName
и другими свойствами, подгружаемыми параллельно. Параметр PropertyName — произвольное имя. Его единственная функция — служить идентификатором загружаемых данных.
Когда данные запрашиваются методом AsyncRead, управление возвращается приложению, продолжающему обработку других задач. Загрузка требует времени, поэтому метод AsyncRead выполняется как асинхронная операция. Когда загрузка завершается, происходит событие AsyncReadComplete. Код обработчика события AsyncReadComplete имеет следующий вид.
Sub UserControl_AsyncReadComplete(PropertyValue As AsyncProperty)
Аргумент
PropertyValue является объектом, свойства которого описаны в табл. 21.6.
Таблица 21.6. Свойства объекта AsyncProperty
Константа
Описание
Value
PropertyName
AsyncType
Переменная, содержащая результат асинхронной загрузки.
Имя свойства, определяемое последним аргументом метода AsyncRead.
Целочисленное значение, определяющее тип данных, в свойстве Value. Принимает такие же значения, как и аргумент AsyncType метода AsyncRead.
Событие AsyncReadComplete происходит даже в случае, если во время передачи возникает ошибка. Если загрузка не завершилась успешно, то при обращении к свойству Value объекта AsyncProperty происходит ошибка исполнения. Необходимо включать оператор On Error в код обработчика события AsyncReadComplete, чтобы перехватить ошибки при загрузке.
Свойство Value является фактическим значением загружаемого свойства. Если тип запрошенных данных — VbAsyncTypeFile, то свойство Value — имя временного файла, который Visual Basic создает на диске в папке Temp. Для работы с таким файлом используются стандартные функции ввода/вывода. Если тип запрошенных данных - VbAsyncType Picture, то свойство Value является объектом Picture, содержащим битовое представление. Можно присвоить свойство Value свойству Picture элемента управления (или объекту UserControl) или преобразовать битовое представление с помощью метода PaintPicture. Если тип запрошенных данных — VbAsyncTypeByteArray, то свойство Value
является массивом байтов.
Прекратить асинхронную загрузку данных можно с помощью метода CancelAsyncRead. Метод CancelAsyncRead имеет следующий синтаксис.
UserControl.CancelAsyncRead PropertyName
PropertyName — это имя загружаемого свойства (последний аргумент метода AsyncRead). Если PropertyName не был передан при последнем вызове метода AsyncRead, то его выполнение отменяется.
VB6 в действии: разработка элемента управления
Rates
Асинхронная разгрузка значений свойства из Интернет демонстрируется в проекте Rates (Курсы обмена валюты) (рис. 21.12). Rates Control Demo имеет графический интерфейс, содержащий элемент управления ListBox, в котором отображаются последние курсы валюты Rates Control Demo обеспечивает методы поиска курсов различных валют, чтобы элемент управления мог остаться скрытым.
Рис. 21.12. Rates Control Demo: загрузка и вывод данных из Интернет с HTTP-сервера
Спецификации элемента управления
FLEXLabel
Элемент управления FLEXLabel должен отображать надпись (как и обычный элемент Label), то есть в нем должны быть предусмотрены свойства Caption и Font, которые позволяют разработчику задавать текст и его вид. В дополнение, элемент управления FLEXLabel может выравнивать надпись по вертикали и горизонтали. Эта возможность будет обеспечиваться свойством TextAlignment, возможные значения которого показаны в табл. 16.1.
Таблица 16.1. Значения свойства TextAlignment элемента управления FLEXLabel
Значение Описание
0 Слева вверху
1 Вверху посередине
2 Справа вверху
3 В центре слева
4 В центре
5 В центре справа
6 Слева внизу
7 Внизу посередине
8 Справа внизу
Названия, указанные в колонке Описание,
отображаются в раскрывающемся списке свойства TextAlignment. Заметим, что свойства с ограниченным набором значений отображаются в виде раскрывающегося списка в окне свойств. Этот список содержит описательные имена (вместо чисел), и разработчик может выбрать только корректное значение.
Аналогично, текстовые эффекты управляются с помощью свойства
Effect, чьи значения приведены в табл. 16.2.
Таблица 16.2. Значения свойства Effect элемента управления FLEXLabel
Значение
Описание
0
Нет
1
Слабо тисненный
2
Средне тисненный
3
Сильно тисненный
4
Слабо выпуклый
5
Средне выпуклый
6
Сильно выпуклый
Подобно свойству TextAlignment, свойство Effect имеет мало значений, которые задаются в окне свойств содержательными именами.
В дополнение к новым свойствам, элемент FLEXLabel должен также предусматривать стандартные для элемента управления Label свойства, такие как Font, Tag, BackColor и т.д. Разработчики ожидают увидеть эти свойства в окне свойств и, следовательно именно там необходимо их реализовать. Элемент управления FLEXLabel не имеет никаких дополнительных методов, но он должен предусматривать стандартные методы элемента управления Label, как например, метод Move. Аналогично, хотя элемент не инициирует никаких специальных событий, он должен поддерживать стандартные события элемента управления Label например, события мыши и клавиатуры.
Большая часть функциональных возможностей элемента управления уже реализованы, и должен существовать простой способ заимствования их у других элементов вместо того чтобы реализовывать их самостоятельно. На самом деле так и есть Visual Basic снабжен мастером который генерирует код стандартных частей элемента управления а разработчику только остается написать код для дополни тельных свойств.
SQL-объединения
Объединения определяют, как связываются несколько таблиц в запросе. Существует три типа объединений.
• Left Outer (Левое внешнее)
• Right Outer (Правое внешнее)
• Inner (Внутреннее)
Операция объединения соединяет все строки одной таблицы со строками другой таблицы. Объединения обычно сопровождаются условием, которое определяет какая запись на каждой стороне объединения появится в RecordSet.
Left Outer (Левое внешнее объединение). Это объединение отображает все записи из левой таблицы и только те записи правой таблицы, которые удовлетворяют задаваемым пользователем критериям. Это объединение имеет следующий синтаксис.
FROM (первичная таблица) LEFT JOIN (вторичная таблица) ON
(первичная таблица).(поле) (сравнение) (вторичная таблица).(поле)
В левом внешнем объединении всем записям в первичной таблице поставлены в соответствие записи из вторичной таблицы, отвечающие заданным критериям. Записи из левой таблицы (имя которой указано слева от ключевого слова LEFT JOIN) включаются даже тогда, если для них нет соответствующих записей во вторичной таблице.
Right Outer (Правое внешнее объединение). Это объединение подобно левому внешнему объединению, но в данном случае отображаются все записи правой таблицы и соответствующие критерию записи левой таблицы. Это объединение имеет следующий синтаксис.
FROM (вторичная таблица) RIGHT JOIN (первичная таблица) ON
(вторичная таблица).(поле) (сравнение) (первичная таблица).(поле)
В правом внешнем объединении всем записям в первичной таблице поставлены в соответствие отвечающие заданным критериям записи вторичной таблицы. Записи первичной таблицы включаются даже тогда, если для них нет соответствующих записей во вторичной таблице.
Внешние объединения возвращают огромные наборы записей. Поэтому необходимо избегать их использования без особой необходимости. С другой стороны, внутренние объединения просты и с ними строят большинство команд SQL.
Inner (Внутреннее объединение). Это объединение возвращает строки обеих таблиц включаемых в операцию, которые соответствуют заданным критериям. Внутреннее объединение имеет следующий синтаксис.
FROM (первичная таблица) INNER JOIN (вторичная таблица) ON
(первичная таблица).(поле) (сравнение) (вторичная таблица).(поле)
Рассмотрим подробнее несколько примеров. В простейшем виде внутренние объединения похожи на предложения WHERE. Следующий SQL-оператор объединяет записи из таблиц Titles и Publishers базы данных BIBLIO, если у них совпадают поля PubID. Она возвращает набор записей с именами всех книг и их издателей.
SELECT Titles.Title, Publishers.Name FROM Titles, Publishers
WHERE Titles.PubID = Publishers.PubID
Можно получить такой же RecordSet, используя внутреннее объединение.
SELECT Titles.Title, Publishers.Name FROM Titles, Publishers,
INNER JOIN Titles ON Titles.PubID = Publishers.PubID
Результаты работы этой команды показаны ниже.
Рассмотрим более сложную операцию объединения. На этот раз необходимо получить из базы данных BIBLIO все названия изданий наряду с их авторами и издателями. Следующее утверждение действительно сложно и отражает реальную ситуацию.
SELECT Titles.Title, Titles.ISBN, Authors.Author,
Titles.[Year.Published], Publishers.[Company Name] FROM
(([title author] INNER JOIN Titles ON
[title author].ISBN = Titles.ISBN) INNER JOIN Authors ON
[title author].Au ID = Authors.Au ID) INNER JOIN Publishers ON
Titles.PubID = Publishers.PubID ORDER BY Titles.Title
Результаты работы команды показаны ниже.
В предыдущей команде в квадратные скобки заключены имена полей, которые содержат пробелы. Все имена полей предваряются соответствующим именем таблицы (хотя большинство имен полей уникально), чтобы сделать команду более легкой для чтения.
В списке полей устанавливаются следующие поля:
• Titles.TitIe - название книги;
• Titles.ISBN - ISBN код книги;
• Authors.Author — автор книги;
• Titles.[Year Published] — год публикации книги;
• Publishers. [Company Name] — издатель книги.
Вы, возможно, помните, что база данных BIBLIO содержит четыре таблицы, а наш запрос требует данных из всех таблиц Фактически, никакие данные из таблицы Title Author в результатах запроса не отображаются, но эта таблица связывает названия и имена авторов (через ISBN код книги), поэтому ее необходимо использовать в SQL-запросе.
Поля не выбираются из каждой конкретной таблицы непосредственно. Их получают из ряда внутренних объединений. Первое внутреннее объединение следующее.
[title author] INNER JOIN Titles ON [title author].ISBN =
Titles.ISBN
Это выражение извлекает (и соединяет) каждое название издания с иден тификатором его автора, если ISBN код в обеих таблицах совпадает. В сущности, будет получен идентификатор автора для каждого издания. Назовем это выражение (которое является объектом RecordSet) Title-AuthorIDs. Этот RecordSet помещен в круглые скобки и соединен с другим RecordSet.
(Title-AuthorIDs) INNER JOIN Authors ON [title author].Au_ID =
Authors Au ID
Этот RecordSet соединяет идентификаторы авторов предыдущего RecordSet с фактическими именами авторов. Мы создали RecordSet с именами авторов и названиями изданий. Назовем его Titles-Author. Последняя операция объединения соединяет RecordSet, который содержит имена авторов и изданий, с таблицей Publishers следующим образом.
(Titles-Author) INNER JOIN Publishers ON Titles.PubID =
Publishers.PubID
На этот раз идентификаторы издателей должны совпадать. Результирующий RecordSet содержит названия изданий, авторов и издателей и является источником данных. Последнее ключевое слово в этой SQL-команде — ORDER BY — задает порядок отображения заказов.
Страница
ALLPRODS.ASP
Страница ALLPRODS.ASP отображает список категорий товаров в базе NWIND (рис. 22.8).
ASP-страница читает наименования категорий товаров и отображает их в виде гиперссылок. Когда пользователь выбирает гиперссылку, он переходит на другую страницу (PRODCAT.ASP), которая отображает все товары, принадлежащие этой категории, их цены и количество (рис. 22.9).
Если посмотреть на код страницы PRODCAT.ASP, то можно заметить, что в ней мало HTML-кода, поскольку это серверный сценарий, который открывает базу данных NWIND, создает набор записей с наименованиями категорий и отображает их в виде гиперссылок.
Наибольший интерес представляет строка, создающая гиперссылки. Если не обращать внимания на обрамление этого выражения тегами серверного сценария, то выглядит оно как обычный HTML-тег для создания гиперссылки. Поскольку имя гиперссылки и ее целевая страница в момент создания этого файла неизвестны, поместим в него выражения, которые будут замещены при обработке файла активной серверной страницей.
Рис. 22.8. Страница ALLPRODS.ASP: категории товаров в базе данных NWIND в виде гиперссылок
Рис. 22.9. файл PRODCAT.ASP: товары в категории, выбранной на рис. 22.8
Обратите внимание: все гиперссылки обращаются к одному
URL на сервере (файл PRODCAT.ASP), но каждая ссылка передает другое значение параметра. Этим значением является идентификатор (ID) категории - поле записи, хранящей сведения о каждом товаре. Страница PRODCAT ASP использует это значение для выбора товаров заданной категории. В качестве второго параметра передается наименование категории. Этот параметр не используется при выборке записей -он нужен только для отображения наименования категории. Если опустить этот параметр, то страница PRODCAT.ASP откроет таблицу Categories (Категории), чтобы найти наименование выбранной категории, отобразить его в заголовке страницы, а затем открыть таблицу Products (Товары) для извлечения наименований товаров. Передавая наименование категории в качестве второго параметра, мы избавляем сценарий от необходимости установления еще одной связи с базой данных для получения уже известной информации.
Программа 22.8. Файл ALLPRODS ASP
<%
Set DBObj =
Server.CreateObject("ADODB.Connection")
DBObj.Open "NWindDB"
SQLQuery = "SELECT CategoryID, CategoryName FROM Categories"
Set RSCategories = DBObj.Execute(SQLQuery)
%>
List Of Product Categories
<% Do While Not RSCategories.EOF %>
<% CategoryName = RSCategories ("CategoryName") %>
&CategoryName= _
<% =CategoryName %> "> <% = CategoryName %>
<%
RSCategories.MoveNext
Loop
DBObj.Close
%>
Файл PRODCAT ASP, обрабатывающий запросы, сделанные страницей ALLPRODS ASP, несколько сложнее Сначала он извлекает значения параметров, переданных клиентом Операторы
ReqCategory=Request.QueryString ("CategoryID")
ReqName=Request.QueryString ("CategoryName")
сохраняют эти значения в переменных ReqCategory и ReqName
Семейство QueryString хранит эти значения для дальнейшего использования Прочесть их, воспользовавшись соответствующими именами, не составляет труда Значение переменной ReqCategory необходимо для построения SQL-оператора, извлекающего записи из таблицы Products
SQLQuery = "SELECT ProductName, UnitPrice, UnitInStock _
FROM Products WHERE CategoryID = " & ReqCategory & " _
ORDER BY ProductName"
Этот SQL-оператор возвращает набор записей, содержащий сведения о товарах из выбранной категории. Затем сценарий просматривает записи и выводит их в строках таблицы. Фрагмент кода, который строит таблицу, выглядит достаточно сложно, поскольку в него входят HTML-операторы и операторы сценария. Чтобы понять, как он работает, замените каждое выражение, заключенное в теги <% и %>, соответствующем значением (например, наименованием товара в выражении <% = RSProducts ("ProductName") %> и т.д.).
Программа 22.9. Файл PRODCAT.ASP
<%
ReqCategory=Request. QueryString ("CategoryID")
ReqName=Request. QueryString ("CategoryName")
Set DBObj = Server.CreateObject ("ADODB.Connection")
DBObj.Open "NWindDB"
SQLQuery = " SELECT ProductName, UnitPrice, UnitsInStock FROM Products
WHERE CategoryID = " & ReqCategory S " ORDER BY ProductName"
Set RSProducts = DBObj.Execute(SQLQuery)
%>
Query Results
List of products in category <% = ReqName %>
<% Do While Not RSProducts.EOF %>
<% = RSProducts ("ProductName") & " (" &
RSProducts ("UnitPrice") & ")" %>
<% = RSProducts ("UnitsInStock") %>
<%
RSProducts.MoveNext
Loop
%>
Этот пример достаточно прост. Если некоторые его фрагменты выглядят непонятно, то отделите выражения, вычисляющиеся на сервере, от HTML-кода. При этом можно использовать символические имена - ProductName и UnitPrice. Убедившись, что код работает, замените их действительными переменными серверного сценария.
Структура базы данных
BIBLIO
Одна из двух стандартных баз данных, поставляемых с Visual Basic, называется BIBLIO. База данных BIBLIO имеет простую структуру, почти тривиальную, но демонстрирует многие из рассмотренных ранее тем. Откройте базу BIBLIO с помощью Visual Data Manager и исследуйте ее структуру.
База BIBLIO содержит заголовки книг имена авторов и издателей в виде четырех таблиц (рис. 17.11). Вместо имен полей каждой таблицы на рисунке отображены некоторые содержащиеся в них данные. Приведены только те поля, которые необходимы, чтобы показать связи между таблицами. Имена полей отображены как заголовки столбцов. Первое правило при проектировании базы данных — не дублировать данные. Хранение имени автора совместно с заголовками нарушило бы это правило, поскольку автор обычно пишет больше одной книги. В этом случае необходимо было бы повторить имя автора в более чем одной строке таблицы Titles. Имена авторов хранятся в отдельной таблице – Authors. Это же справедливо и для издателей. Так как каждый издатель появляется во многих книгах то информация об издателях в таблице Titles не хранится. Зачем повторять адрес издателя с каждым заголовком?
Пока обосновано существование трех таблиц в базе данных. Но в базу данных BIBLIO входит четвертая таблица. Каждая книга может иметь более одного автора, а имя автора может появляться не только в одном заголовке Хранение имен каждого из авторов или их ID для каждого наименования книги потребовало бы соответствующих полей в таблице Titles. Отличие поля с ID автора от поля PubID (ID издателя) состоит в том, что книга может иметь несколько авторов, и необходимо предусмотреть ряд полей для хранения идентификаторов Author ID (AuthorIDl, AuthorID2 и т.д.). Очевидно, что имена авторов не могут обрабатываться подобно именам издателей.
Рис. 17.11. Структура базы данных BIBLIO
Таблица Title Author находится между таблицами Titles и Authors и соединяет их с парой полей — ISBN книги и ID автора. Для просмотра имени автора конкретной книги необходимо выполнить следующие действия.
1 . Найдите искомый заголовок в таблице Titles.
2 . Прочитайте значение ISBN в Title и используйте его как ключ для нахождения соответствующей строки (строк) в таблице Title Author.
3 . Из каждой соответствующей строки таблицы Title Author прочтите ID автора и используйте его в качестве ключа для поиска имени автора в таблице Authors.
Тем, кто не знаком с программированием баз данных, эта процедура может показаться сложной, но это не так. Далее в этой главе показаны два способа поиска конкретных записей с помощью ключей. Описанная методика не сможет эффективно работать, если нет способа быстрого поиска записи по значению конкретного поля. А он может быть выполнен при соответствующей индексации таблиц.
Как видно, индексы - неотъемлемая часть разработки базы данных. Например, таблица Title Author (Автор книги) индексируется по полю ISBN. Если необходимо обеспечить поиск в противоположном направлении (дано имя автора, а требуется найти книги, в которых оно появляется), необходимо проиндексировать таблицу Title Author по полю AuID. Очевидно, таблица Authors (Авторы) должна быть индексирована по полю AuID, так как в таблице Title Author хранятся ID авторов, а не их имена. Таблица Publishers (Издатели) индексируется по полю PubID, чтобы можно было быстро перейти от названия книги к ее издателю.
Структура HTML-документов
HTML-файлы — это файлы, которые содержат текст и команды форматирования. Командами являются строки со специальным синтаксисом, что позволяет броузеру отличить их от текста. Каждый тег HTML заключен в угловые скобки (<>). Тег подключает атрибут курсива, и текст выделяется курсивом, пока не встретится тег . Следующая строка
HTML is the language of the Web.
воспроизводится броузером без тегов, а слово the выделяется курсивом.
HTML is the
language of the Web.
Большинство тегов (обычно они следуют парами) влияет на часть текста. Один тег включает данный атрибут, а другой - отключает его. Примером может служить тег , <В> и , которые включают атрибуты курсив, полужирный и подчеркивание. Тегу, отключающему атрибут, всегда предшествует символ "/". Для отображения части текста полужирным шрифтом ее заключают в теги <В> и В>.
Теги не чувствительны к шрифтам. Можно ввести теги курсива в виде и . В этой книге и на прилагающемся компакт-диске используются заглавные буквы для HTML-команд (чтобы выделить их из остального текста документа). Большинство WYSIWYG-редакторов HTML вставляют HTML-теги в виде строчных символов.
Примечание
Наличие второго тега — для отключения атрибута — не всегда является обязательным. Например, не нужно использовать пару
<Р> и Р> для вставки новой строки: это с успехом сделает один тег <Р>.
Структура HTML-документа показана ниже. Если сохранить следующие строки в текстовом файле с расширением htm, а затем открыть его с помощью Internet Explorer, то вы увидите традиционное приветствие.
Your Title Goes Here
Hello, World!
Базовый HTML-документ следует начинать тегом
и завершать тегом . Раздел заголовка документа выделяется тегами
и . Обычно в него помещаются следующие элементы:
• название документа;
• теги МЕТА и BASE;
• сценарий.
Название документа — это текст в заголовке окна броузера. Он задается тегами и . МЕТА-теги не отображаются на экране, но содержат полезную информацию о содержании документа: описание и ключевые слова, используемые устройством поиска. Например:
Your Title Goes Here
"health, nutrition, weight control, _
chronic illness">
Атрибуты
Многие теги HTML распознают специальные ключевые слова, которые называются атрибутами. Например тег , отмечающий начало тела документа, распознает атрибуты BGCOLOR и BACKGROUND, задающие цвет фона и изображение являющееся фоном документа. Можно задать цвет фона документа (если нет фонового изображения) и ею текста используя атрибуты BGCOLOR и TEXT
Your Title Goes Here
Tiled Background
The background of this page was created with a small image,
which is tiled vertically and horizontally by the browser.
(Фон страницы создан с помощью небольшого изображения,
воспроизведенного броузером в виде повторяющейся мозаики)
The image was designed so that its left edge matches with its
riqht edge and its top edge matches with the bottom edge. Notice
that you can't detect where one instance ends and the next one
begins.
(Верхний срез изображения соответствует нижнему срезу. Заметьте: обнаружить, где оно начинается и кончается, нельзя.)