59899
Visual Basic 6. Руководство разработчика
Книга
Информатика, кибернетика и программирование
Основные элементы управления ctiveX. Усовершенствованные элементы Visul Bsic. Усовершенствованные элементы управления ctiveX. Дополнительные элементы управления ctiveX. Специальные темы. Конструирование элементов управления ctiveX Часть V Программирование баз данных на Visul Bsic.
Русский
2014-06-05
7.18 MB
233 чел.
467
Евангелос Петрусос
Visual Basic 6
Руководство разработчика
Перевод с английского под редакцией Ю.М. Зорина
Том 2
"Ирина", BHV, Киев, 2000
Евангелос Петрусос
Visual Basic 6. Руководство разработчика: В 2 т.: Пер с англ. К.: Издательская группа BHV, 2000. Т 2 560 с., ил.
ISBN 966 552 056-3 (Том 2)
ISBN 966 552 044 X
Эта книга, написанная известным специалистом и неутомимым пропагандистом Visual Basic, представляет собой прекрасный путеводитель по одному из наиболее популярных визуальных средств разработки Windows-приложений. Подробно освещаются такие ключевые темы программирования на Visual Basic, как проектирование и использование элементов ActiveX, программирование баз данных и разработка Web-приложений. Несомненный интерес представляют главы, посвященные работе с графикой. Большое количество тщательно продуманных примеров облегчает восприятие материала.
Подбор материала и стиль изложения делают издание интересным и полезным для программистов разных уровней.
Перевод издан и распространяется в соответствии с соглашением с издательством SYBEX, имеющим все права на печать и реализацию оригинала.
Обложка А. А. Стеценко.
Макет подготовлен ТОО «ВЕК+»
ISBN 0-7821-2272-8 © SYBEX Inc , 1998
ISBN 966-552-056-3 (Том 2) © PWN Publishing Group S. A., 2000
ISBN 5-7315-0085-1 (Том 2) © Издательская группа BHV, Киев, 2000
© Издательство "Ирина", Киев, 2000
ISBN 966-552-044-Х
ISBN 5-7315-0073-8
Структура книги
Том 1
Введение
Часть I
Основы Visual Basic
Глава 1. Знакомство с Visual Basic
Глава 2. Проекты Visual Basic
Глава 3. Visual Basic: описание языка
Глава 4. Работа с формами
Глава 5. Основные элементы управления ActiveX
Часть II
Усовершенствованные элементы Visual Basic
Глава 6. Рисование средствами Visual Basic
Глава 7. Цвет и пиксели в Visual Basic
Глава 8. Усовершенствованные элементы управления ActiveX
Глава 9. Дополнительные элементы управления ActiveX
Часть III
Специальные темы
Глава 10. Работа с многодокументными формами
Глава 11. Использование рекурсивных методов
Глава 12. Оптимизация VB-приложений
Предметный указатель
Том II
Часть IV
Расширение возможностей Visual Basic
Глава 13. API-функции Windows
Глава 14. Автоматизация OLE и VBA
Глава 15. Конструирование компонентов ActiveX
Глава 16. Конструирование элементов управления ActiveX
Часть V
Программирование баз данных на Visual Basic
Глава 17. Программирование баз данных на Visual Basic
Глава 18. Элементы управления Active Data Object
Часть VI
Visual Basic и Web
Глава 19. Введение в Web
Глава 20. Объекты, используемые в сценариях
Глава 21. Visual Basic и Web
Глава 22. Активные серверные страницы
Приложение. О прилагаемом компакт-диске
Предметный указатель
Содержание
Глава 13. API-функции Windows
Глава 14. Автоматизация OLE и VBA
Глава 15. Конструирование компонентов ActiveX
Глава 16. Конструирование элементов управления
• Доступ к 32-разрядным API-функциям из Visual Basic
• Передача аргументов по значению и по ссылке
• Определение свободного дискового пространства
• Использование растрового изображения для создания меню
• Распознавание перемещения мыши
• Доступ к системным ресурсам
• Манипулирование графическими объектами
Итак, вы уже освоились с ограничениями Visual Basic: разрабатываете приложения, воспринимающие команды, генерируемые мышью, и используете операторы Visual Basic для управления формой. Знаете, как много разных вещей можно сделать в Visual Basic и сколь далеко можно продвинуться в программах. Но иногда возникает необходимость обратиться непосредственно к операционной системе и получить доступ к ее функциям. Например, чтобы отследить перемещение мыши за пределами окна формы, требуется использовать некоторые дополнительные функции. Доступ к этим функциям предоставляется интерфейсом прикладных программ Win32 API (Application Programming Interface).
Win32 API это набор функций, используемых, главным образом, программистами, работающими на С, но нет причин, по которым их нельзя было бы использовать в приложениях Visual Basic. Многие программисты, работающие в среде Visual Basic, обращаются к API-функциям для выполнения таких действий, которые невозможно (или очень сложно) выполнить средствами самого Visual Basic. Как отмечалось в гл. 12, использование API-функций позволяет значительно повысить быстродействие некоторых приложений, созданных средствами Visual Basic, которые работают недопустимо медленно (например, графических приложений).
API-функции не являются чем-то сложным и экзотическим. Основная проблема заключается в том, что документация по этим функциям ориентирована на программистов, работающих на С, и поэтому могут возникнуть определенные трудности при поиске требуемых функций и объявлении типов данных.
Можно обратиться ко всем API-функциям непосредственно из Visual Basic. Фактически, все графические методы, используемые в Visual Basic - это "замаскированные" API-функции. В гл. 7 рассматривался метод PaintPicture, используя который можно скопировать растровое изображение из окна одного элемента управления в окно другого. Впервые он появился в Visual Basic 4. Ранее программистам, работающим в Visual Basic, приходилось использовать API-функцию, выполняющую аналогичные действия. Функция BitBlt() позволяет выполнять процедуры копирования пикселей из окон элементов управления Visual Basic на Рабочий стол (Desktop) и наоборот. Чтобы скопировать часть изображения, содержащегося на Рабочем столе, в окно элемента управления PictureBox (например, для демонстрации возможностей утилиты копирования экрана), придется воспользоваться функцией BitBIt(), а не методом PaintPicture.
API-функции используются во многих Windows-приложениях. К счастью, Visual Basic берет на себя большинство проблем в процессе работы с API-интерфейсом. В этой главе не делается даже попыток рассмотреть все API-функции (их около 1000). Мы рассмотрим лишь некоторые из них.
Цель данной главы - ознакомление с основами обращения к API-функциям и изучение способов использования API Viewer для добавления объявлений API-функций к коду вашей программы. Вместо краткого перечисления большого количества API-функций, подробно будут рассмотрены всего несколько наиболее полезных функций и разработаны небольшие приложения с их использованием. Эти приложения демонстрируют не только вызов соответствующих функций, но и их использование в приложениях. Многие API-функции достаточно просты как в понимании, так и в использовании. Кроме того, они имеют аналоги в Visual Basic.
Прежде чем приводить примеры использования определенных 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" ("Использование элементов мультимедиа для расширения приложений") на компакт-диске.
Единственное отличие функций 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 функции пере числены ниже.
При использовании 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), так как они указывают на область памяти, в которой хранится значение переменной.
В некоторых 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 (Модуль): тогда другие процедуры смогут получить к ним доступ.
8. Добавьте новый Module (Модуль) к проекту, и вставьте в него из буфера обмена скопированные объявления:
Type POINTAPI
х As Long
у As Long
End Type
Declare Function GetCursorPos Lib "user32"
Alias "GetCursorPos" (IpPoint As POINTAPI) As Long
Совет
Если хотите вставить объявления в форму так, чтобы их нельзя было использовать вне этой формы, то поместите перед объявлением ключевое слово Private.
Теперь можно использовать функцию GetCursorPos() в вашей программе. Предположим, вы хотите определить положение указателя мыши с помощью события Click. Событие Click в Visual Basic не сообщает координаты точки, в которой был выполнен щелчок, но можно организовать запрос для определения этих координат, используя функцию GetCursorPos(). Воспользовавшись имеющимися объявлениями в модуле приложения, введите в текст обработчика события Click (Щелчок) формы следующий фрагмент программы.
Private Sub Form_Click()
Dim MouseLoc As POINTAPI
Dim retValue As Boolean
retValue = GetCursorPos(MouseLoc)
Debug.Print "X Pos = " & MouseLoc.x
Debug.Print "Y Pos = " & MouseLoc.у
End Sub
Функция GetCursorPos() возвращает значения координат указателя в пикселях. Значения, которые вы видите в окне проверки, соответствуют пикселям экрана. Начало системы координат пикселей экрана находится в левом верхнем углу (точка с координатами (0,0)). Если монитор работает в режиме с разрешением 800 х 600, то координаты правого нижнего угла экрана будут иметь значения (799, 599). Чтобы щелчок был выполнен в точке с этими координатами, переместите форму в правый нижний угол и выполните щелчок. Функция GetCursorPos() возвращает координаты указателя мыши в абсолютной системе координат, но событие Form_Click генерируется только тогда, когда щелчок мыши происходит где-нибудь в пределах окна формы. Поэтому сначала необходимо переместить форму в другое место, а затем выполнить щелчок. Позднее вы узнаете, как отслеживать перемещение мыши за пределами окна формы.
В этом разделе описаны функции для определения типа диска и свободного пространства на нем, а также для поиска каталога 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
В этом параграфе описываются 32-х разрядные API-функции Windows, расширяющие возможности Visual Basic при создании форм, окон и меню Используя эти функции, можно создавать элементы меню, содержащие растровые изображения и динамически изменять объекты меню. Вы узнаете, как отслеживать перемещение мыши и манипулировать окнами других активных приложении, размещенных на рабочем столе.
Элементы меню, создаваемые средствами 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
В процессе работы программы можно изменить элементы меню. Эти возможности показаны на примере программы MenuMod (созданной на основе программы MenuBMP).
VB6 в действии: проект MenuMod
Приложение MenuMod позволяет организовать переключение отображения элементов меню либо в виде растрового изображения, либо в виде текста. Меню приложения MenuMod соответствует меню приложения MenuBMP, но, кроме того, добавлен третий пункт Display Graphics (вывести изображение, если элемент меню содержит текст) или Display Text (вывести текст, если элемент меню содержит графику). Обработчик события Click этого пункта меню вызывает функцию DisplayTextMenu() или DisplayBitmap Мепи(), что позволяет переключаться из одного режима в другой. В процедуре ModifyMenu() для организации замены графики на текст в элементе меню следует использовать флаг MF_STRING, а для обратной замены флаг MF_BITMAP.
Программа 13.6. Приложение MenuMod
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 Select0b]ect 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 x Src As Long, _
ByVal уSrc As Long, ByVal dwRop As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Const MF_STRING = &HO&
Const SRCCOPY = &HCC0020
Const MF_BYPOSITION - &H400&
Const MFJ3ITMAP - &H4&
Private Sub Exit_Click()
Unload Me
End Sub
Private Sub Form Load()
Call DisplayBitmapMenu
End Sub
Private Sub Graphics_Click()
Отображение текста
If Graphics Checked Then
Graphics Checked = False
Call DisplayTextMenu
Else
Graphics.Checked = True
Call DisplayBitmapMenu
End If
End Sub
Private Sub MyMenu_Click(Index As Integer)
Me CIs
Me Font Name - MyMenu(Index) Caption
Me CurrentX - (Me ScaleWidth - __
Me.TextWidth(MyMenu(Index).Caption))/2
Me CurrentY = (Me.ScaleHeight _
Me TextHeight(MyMenu(Index) Caption))/2
Me.Print MyMenu(Index).Caption
End Sub
Private Sub DisplayTextMenu()
Dim hMenuID As Long, menuID As Long
Dim menuPos As Integer
Dim retValue As Long
Получение дескриптора меню
hMenuID = GetSubMenu(GetMenu(Me.hwnd),0)
menuPos = 0
menuID - GetMenuItemID(hMenuID, menuPos)
retValue = ModifyMenu(hMenuID, menuPos, _
MF_BYPOSITION Or MF_STRING, menuID, "Verdana")
menuPos = 1
menuID = GetMenuItemID(hMenuID, menuPos)
retValue - ModifyMenu(hMenuID, menuPos,
MF_BYPOSITION Or MF_STRING, menuID, "Serif")
menuPos - 2
menuID - GetMenuIteitiID (hMenuID, menuPos)
retValue = ModifyMenu(hMenuID, menuPos, _
MF_BYPOSITION Or MF_STRING, menuID, "Comic Sans")
End Sub
Private Sub DisplayBitmapMenu()
Dim Width As Integer, Height As Integer
Dim hTmpDC As Long, hMenuID As Long
Dim hBitmap As Long
Dim retValue As Long
Dim tmpID As Long
Dim fileName As String
Dim menuPos As Integer, menuID As Long
Установка позиции меню и имени файла
menuPos - О
fileName - Арр 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 - Select0b;ect(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)
Второй пункт меню
menuPos = 1
fileName = App.Path & "\serif.bmp"
Picturel.Picture = LoadPicture(fileName)
Создание растрового изображения для элемента меню
hBitmap = CreateCompatibleBitmap(Picturel.hdc. Width, Height)
Выбор растрового изображения во временный контекст устройства tmpID = SelectObject(hTmpDC, hBitmap)
retValue = BitBIt(hTmpDC, 0, 0, Width, Height, _
Picturel.hdc, 0, 0, SRCCOPY)
tmpID = Select0b;ect(hTmpDC, tmpID)
menuID = GetMenuItemID(hMenuID, menuPos)
retValue = ModifyMenu(hMenuID, menuPos,
MFJ3YPOSITION Or MF_BITMAP, menuID, hBitmap)
Третий пункт меню
menuPos = 2
fileName = App.Path & "\comic.bmp"
Picturel.Picture = LoadPicture(fileName)
Создание растрового изображения для элемента меню
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)
Очистка
retValue = DeleteDC(hTmpDC)
End Sub
В практике программирования на 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, который находится в соответствующей папке на компакт-диске.
Для работы с различными элементами управления можно использовать метод 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 возвращает их значения, выраженные во внутренней системе координат (в твипах).
Часто приходится сталкиваться с приложениями, которые размещают свое окно поверх окон других приложений независимо от того. какое именно из них является активным. Примером такого окна может служить окно 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, тогда пользователь не сможет изменить размер окна.
API-функции, описываемые в этом разделе, позволяют организовать просмотр других выполняющихся программ непосредственно из VB-приложения и получить не только информацию о приложении, но и его родительском окне.
Чтобы организовать запрос к другому приложению, необходимо указать вашей программе, о каком именно приложении идет речь. Один из способов, позволяющий это сделать, заключается в установке указателя мыши в окно другого приложения (информацию о состоянии которого требуется получить). Именно так сделано в приложении Query (рис. 13.8). Эта программа позволяет наблюдать за другими активными приложениями, используя уже известные функции GetCursorPos() и SetWindowPos(), а также нескольких новых функций, рассматриваемых в следующем параграфе.
VB6 в действии: проект Query
В окне приложения Query содержится информация о текущем активном окне и его родительском окне.
Рис. 13.8. Приложение Query
Для получения информации об остальных открытых окнах в этой программе используются следующие функции:
• SetWindowPos()
• GetCursorPos()
• WindowFromPoint()
• GetClassName()
• GetWindowText()
• GetParent()
SetWindowPos(). Функция используется для того, чтобы поместить окно данного приложения поверх окон других приложений. Ключевым элементом в ней является флаг HWND_TOPMOST, установка которого предписывает Windows располагать данное окно перед (либо позади, в зависимости от установки z-order) остальными окнами. Пользователь устанавливает указатель мыши в интересующее его окно и получает о нем информацию. Это достигается за счет использования функций GetCursorPos () и WindowFromPoint().
GetCursorPos(), WindowFromPoint(). Функция GetCursorPosQ возвращает координаты указателя мыши (в системе координат окна). Затем эти координаты используются в функции WindowFromPointO для отыскания имени окна (видимого в точке с указанными координатами). Объявление функции WindowFromPointO имеет вид:
Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As _
Long, ByVal yPoint As Long) As Long
Параметры xPoint и yPoint являются парой координат. Функция возвращает число типа Long Integer, которое является дескриптором окна, расположенного в данной точке.
GetClassName(), GetWindowText(). Эти функции используются для организации наблюдения за другими приложениями. Функция GetClassName() позволяет получить имя класса окна, a GetWindowText() текст заголовка окна, если таковой имеется. Если выбранное окно является элементом управления, функция возвращает его текст.
GetParent(). Позволяет получить дескриптор родительского окна для данного окна.
Ниже приведен текст программы Query.
Программа 13.10. Приложение Query
Option Explicit
Private Declare Function SetWindowPos Lib "user32"
(ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _
ByVal X As Long, ByVal Y As Long, ByVal ex As Long, _
ByVal cy As Long, ByVal wFlags As Long) As Long
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 GetParent Lib "user32" _
(ByVal hwnd 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 Declare Function GetWindowText Lib "user32" _
Alias "GetWindowTextA" (ByVal hwnd As Long, _
ByVal IpString As String, ByVal cch As Long) As Long
Const HWND_TOPMOST = -1 ,
Const SWP_SHOWWINDOW = &H40
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 tmpStr As String
Dim parentWnd As Long, 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
tmpStr = String$(256, " ")
prevWindow = curWindow
retValue = GetClassName(curWindow, tmpStr, 255)
tmpStr = Left$(tmpStr, InStr(tmpStr, vbNullChar) - 1)
Text1(0).Text = curWindow
Textl(1).Text « tmpStr
retValue = GetWindowText(curWindow, tmpStr, 255)
Text1 (2).Text = tmpStr
Получение дескриптора родительского окна
parentWnd = GetParent(curWindow)
retValue = GetClassName(parentWnd, tmpStr, 255)
tmpStr = Left$(tmpStr, InStr(tmpStr, vbNullChar) - 1)
Text1(3).Text = parentWnd
Text1(4).Text = tmpStr
retValue = GetWindowText(parentWnd, tmpStr, 255)
Text1(5).Text = tmpStr
End If
DoEvents
Loop
Прекращение отслеживания мыши
Else
Commandl.Caption = "Start"
gStop = True
End If
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, _
UnloadMode As Integer)
gStop = True
End Sub
Private Sub Form_Load()
Dim retValue As Long
If Commandl.Caption = "Start" Then
gStop = False
Commandl.Caption = "Stop"
retValue = SetWindowPos(Me.hwnd, HWND_TOPMOST, _
Me.CurrentX, Me.CurrentY, _
Me.Width, Me.Height, SWP_SHOWWINDOW)
Else
gStop = True
Commandl.caption = "Start"
End If
End Sub
Registry Windows 95/98 - это иерархическая база данных (часто называемая реестром), содержащая информацию об установках Windows. В нее входит информация о пользователях, о конфигурации аппаратных средств системы и прикладных программах. Registry заменила INI-файлы (использовавшиеся в предыдущих версиях Windows), которые предназначались для хранения информации в перерывах между сеансами работы.
Для доступа к Registry воспользуйтесь программой Regedit. Для ее запуска выполните следующие действия.
1. Выберите команду Run в меню Start (команда Выполнить в меню Пуск).
2. В окне Run (Пуск) наберите regedit и нажмите клавишу Enter, чтобы открыть окно Registry Editor, показанное на рис. 13.9.
Если выполнить двойной щелчок на одном из объектов в главном окне Regedit, то данные, записанные в Registry, появятся на экране в виде древовидной структуры. Объект самого верхнего уровня обычно называют Registry key (раздел базы данных), а находящиеся в нем объекты нижнего уровня - подразделами Registry включает следующие разделы.
• HKEY_CLASSES_ROOT хранит информацию о зарегистрированных расширениях и файловых ассоциациях, данные OLE.
• HKEY_CURRENT_USER относится к текущему пользователю Если он единственный, то содержание этого раздела полностью совпадает с подразделом HKEY_USERS.
• HKEY_LOCAL_MACHINE хранит информацию о конфигурации аппаратных средств, установленных на компьютере Подразделы HKEY_LOCAL_MACHINE.
• HKEY_USERS содержит информацию о конфигурации рабочего стола, параметры сети и другие сведения об отдельных пользователях, которые могут регистрироваться на данном компьютере
• HKEY_CURRENT_CONFIG содержит информацию об установленных шрифтах и принтерах.
• HKEY_DYN_DATA хранит сведения о производительности компьютера. После старта системы они загружаются в оперативную память и могут там динамически изменяться.
Рис. 13.9. Главное окно Registry Editor
Предупреждение
Следует предельно аккуратно обращаться с информацией, расположенной в реестре. Повреждение нескольких объектов, находящихся в нем, может привести к прекращению работы системы вплоть до невозможности загрузки. Прежде чем выполнять какие-либо действия с содержимым реестра, пользуясь средствами Visual Basic, убедитесь, что сделаны резервные копии файлов SYSTEM.DAT и USER.DAT. С их помощью всегда можно восстановить исходное состояние базы данных Registry. Прежде чем выполнять с ним какие-либо действия, следует обратиться к Windows по вопросам процедур резервного копирования и восстановления. Лучше всего начинать с использования функций, встроенных в Visual Basic, которые являются вполне "безопасными" (они описаны в Приложении А на компакт-диске), а затем переходить к использованию API-функции.
Можно воспользоваться Regedit, чтобы выяснить, какого типа информация требуется определенным приложениям. Относительно безопасно использовать Registry для хранения информации о приложении. Например, можно сохранить информацию об инициализации приложения, чтобы при следующем запуске можно было просмотреть информацию об установках предыдущего сеанса работы. Список недавно открывавшихся файлов, которые можно найти почти в каждом приложении Windows, хранится в Registry. Манипулируя содержимым реестра, следует внимательно следить за тем, чтобы не изменить информацию о других приложениях. Изменяйте информацию, имеющую отношение только к вашим собственным приложениям.
Работа с реестром заслуживает того, чтобы надолго на ней остановиться. В этом параграфе будет рассмотрена процедура создания новой ветви в базе данных Registry для сохранения информации, которую приложение считывает. Это несложная процедура, полезная для всех, кто работает с Registry.
VB6 в действии: проект Registry
Приложение Registry позволяет продемонстрировать процесс создания разделов в реестре Windows (Registry), записи соответствующих значений и получения данных из него. В приложении создаются три подраздела HKEY_LOCAL_ MACHINE, в которых хранятся размеры формы, запущенной при предыдущем сеансе работы:
• \Sybex\Mastering VB 6.0
• Window Width (Ширина Окна)
• Window Height (Высота Окна)
В программе (рис. 13.10) используются подразделы Window Width (Ширина Окна) и Window Height (Высота Окна) для хранения ширины и высоты окна (данные записываются приложением Registry).
Рис. 13.10. Программа Registry запоминает размеры формы, установленные во время предыдущего сеанса работы
Когда программа запускается, она пытается получить значения, хранящиеся в подразделах Window Width и Window Height с помощью функции RegQueryValue Ex(). Если эти подразделы содержат значения, то программа просто получает их и устанавливает, соответственно, ширину и высоту окна. Если эти подразделы не содержат значений, значит, в Registry нет соответствующих элементов. Затем программа устанавливает высоту и ширину текущего окна и сохраняет эту информацию в реестре с помощью функции RegSet Value Ех(). Функция RegCreateKeyO позволяет создать определенный элемент реестра. Если такой элемент существует, то функция открывает к нему доступ.
Если размеры окна изменяются пользователем, программа сохраняет новые значения высоты и ширины окна в реестре с помощью метода QueryUnload. При последующем запуске программы окно будет иметь именно эти размеры. Таким образом, можно организовать сохранение установок инициализации программы в реестре, а затем получать их при запуске приложения. Чтобы проверить проект Registry, закройте форму щелчком на кнопке Close. Если работа приложения завершена с помощью команды End меню Run (команда Закончить в меню Выполнить) в IDE-среде Visual Basic, то событие QueryUnload не вызывается.
Ниже приводится текст программы Registry.
Программа 13.11. Программа Registry
Option Explicit
Private Declare Function RegCreateKey Lib "advapi32.dll" _
Alias "RegCreateKeyA" (ByVal hKey As Long, _
ByVal IpSubKey As String, phkResult As Long) As Long
Private Declare Function RegDeleteKey Lib "advapi32.dll"
Alias "RegDeleteKeyA" (ByVal hKey As Long,
ByVal IpSubKey As String) As Long
Private Declare Function RegDeleteValue Lib "advapi32.dll" _
Alias "RegDeleteValueA" (ByVal hKey As Long, _
ByVal IpValueName As String) As Long
Private Declare Function RegQueryValueEx Lib "advapi32.dll" _
Alias "RegQueryValueExA" (ByVal hKey As Long,
ByVal IpValueName As String, ByVal IpReserved As Long, _
IpType As Long, IpData As Any, IpcbData As Long) As Long
Private Declare Function RegSetValueEx Lib "advapi32.dll" _
Alias "RegSetValueExA" (ByVal hKey As Long, _
ByVal IpValueName As String, ByVal Reserved As Long, _
ByVal dwType As Long, IpData As Any, _
ByVal cbData As Long) As Long
Const ERROR_SUCCESS = 0&
Const ERROR_BADDB = 1009&
Const ERROR_BADKEY = 1010&
Const ERROR_CANTOPEN = 1011&
Const ERROR_CANTREAD = 1012&
Const ERROR_CANTWRITE = 1013&
Const ERROR_REGISTRY_RECOVERED = 1014 &
Const ERROR_REGISTRY_CORRUPT = 1015&
Const ERROR_REGISTRY_IO_FAILED = 1016&
Const HKEY CLASSES ROOT = &H80000000
Const HKEY_CURRENT_USER = &H80000001
Const HKEY_LOCAL_MACHINE = &H80000002
Const REG_SZ = 1
Dim regKey As String
Const regKey = "\Sybex\Mastering VB 6.0"
Private Sub ForraLoad()
Dim retValue As Long, result As Long
Dim keyID As Long, keyValue As String
Dim subKey As String
Dim bufSize As Long
Label 6.Caption = regKey
Создание раздела
retValue = RegCreateKey(HKEY_LOCAL_MACHINE, regKey, keyID)
If retValue = 0 Then
Сохранение значения ширины
subKey = "Window Width"
retValue = RegQueryValueEx(keyID, subKey, 0&, _
REG_SZ, OS, bufSize)
Если значение не задано, установить его
If bufSize < 2 Then
keyValue = Me.Width
retValue = RegSetValueEx(keyID, subKey, 0&, _
REG_SZ, ByVal keyValue, Len(keyValue) + 1)
Else
keyValue = String(bufSize + 1, " ")
retValue = RegQueryValueEx(keyID, subKey, _
0&, REG_SZ, ByVal keyValue, bufSize)
keyValue = Left$(keyValue, bufSize - 1)
Me.Width = keyValue
End If
Установка значений для формы
Label4.Caption = subKey
Label5.Caption = Me.Width
Запись значения высоты
subKey = "Window Height"
retValue = RegQueryValueEx(keyID, subKey, 0&, _
REG_SZ, 0&, bufSize)
If bufSize < 2 Then
keyValue = Me.Height
retValue = RegSetValueEx(keyID, subKey, 0&, _
REG_SZ, ByVal keyValue, Len(keyValue) + 1)
Else
keyValue = String(bufSize + 1, " ")
retValue = RegQueryValueEx(keyID, subKey, 0&, REG_SZ, _
ByVal keyValue, bufSize)
keyValue = Left$(keyValue, bufSize - 1)
Me.Height = keyValue
End If
Установка значений для формы
Label8.Caption = subKey
Label7.Caption = Me.Height
End If
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, _
UnloadMode As Integer)
Dim keyValue As String
Dim retValue As Long, keyID As Long
retValue = RegCreateKey(HKEY_LOCAL_MACHINE, regKey, keyID)
keyValue = Me.Width
retValue = RegSetValueEx(keyID, "Window Width", 0&,
REG_SZ, ByVal keyValue, Len(keyValue) + 1)
keyValue = Me.Height
retValue = RegSetValueEx(keyID, "Window Height", 0&, _
REG_SZ, ByVal keyValue, Len(keyValue) + 1)
End Sub
Приложение Registry успешно работает в Windows 95/98 (но не в Windows NT 4).
Графические объекты являются важной частью любого приложения. Графическим объектом может быть и простой значок, и сложное растровое изображение. В параграфе рассмотрены некоторые методы вывода графических изображений с помощью API-функций. Рассмотрены функции BitBlt() и StretchBlt(), в определенном смысле эквивалентные методу PaintPicture в Visual Basic. Основное различие между ними заключается в том, что метод PaintPicture можно применять только к определенному объекту (элементу управления PictureBox или форме), а с помощью функций BitBltQ и StretchBltQ можно выполнять копирование пикселей изображения в пределах рабочего стола. Их можно использовать для создания разнообразных приложений, например программ копирования экрана, чего не позволяет метод PaintPicture.
Функция BitBlt() используется для выполнения операции копирования отдельных битов из области-источника изображения в область-получатель. Функция позволяет передавать прямоугольную область из контекста устройства-источника в контекст устройства-получателя. Ранее в этой главе (приложение MenuBMP) приводился пример использования функции BitBlt(). Рассмотрим эту функцию более подробно и сравним ее с методом PaintPicture, встроенным в Visual Basic.
Функция BitBlt() объявляется следующим образом.
Declare Function BitBIt Lib "gdi32" Alias "BitBIt" (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
В отличие от метода PaintPicture, для вызова функции BitBlt() требуется указать все параметры. Необходимо указать начальные координаты Х и Y получателя, высоту и ширину передаваемого изображения, а также начальные координаты источника.
Прежде чем вызвать функцию BitBlt(), необходимо создать контекст устройства для объекта-источника и объекта-получателя с помощью функций CreateCompatibleDC() и CompatibleBitmapO. Если планируется использовать функцию BitBlt() для копирования содержимого элемента управления PictureBox, то контекстом устройства элемента управления является значение его свойства hWnd. Функцию BitBlt() можно использовать с любым контекстом устройства, даже с контекстом устройства растрового изображения, загруженного в память.
За исключением дескрипторов hDestDC и hSrcDC, параметры функции BitBlt() такие, как и у метода PaintPicture. Они определяют координаты области-источника, содержимое которой будет скопировано (параметры источника), и координаты и размеры области-получателя, куда должны быть скопированы пиксели, образующие изображение (параметры получателя). Размеры областей источника и получателя должны быть одинаковыми. В табл. 13.7. приведены значения кодов растровых операций для параметра dwRop. Эти коды определяют, каким образом пиксели из области-источника объединяются с пикселями в области-получателе.
Для обработки растровых изображений можно воспользоваться функцией StretchBlt(). С помощью этой функции можно выполнять масштабирование (сжимать или растягивать) растровых изображений в процессе копирования. Функция StretchBlt() объявляется следующим образом.
Declare Function StretchBIt Lib "gdi32" Alias "StretchBIt" _
(ByVal hdc 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 nSrcWidth As Long, ByVal nSrcHeight As Long, _
ByVal dwRop As Long) As Long
Функция StretchBlt() имеет те же параметры, что и функция BitBlt(), плюс два дополнительных параметра, которые определяют размер области-источника. С помощью функции Stretch Bit() изображение можно сжимать, растягивать и даже выворачивать наизнанку, задавая параметры с разными знаками. Коды растровых операций, содержащиеся в табл. 13.7, определяют способ объединения цветов пикселей области-источника и области-получателя.
Эти коды рассматривались в гл. 7. Можно запустить приложение PaintPic, рассмотренное там же, чтобы поэкспериментировать с различными кодами растровых операции. В приложении PaintPic используется метод PaintPicture, но растровые операции выполняют аналогичные преобразования.
Таблица 13.7. Коды растровых операций функций BitBlt() и StretchBlt()
Значение |
Описание |
BLACKNESS |
Заполняет область-получатель черным цветом |
DSTINVERT |
Инвертирует область-получатель |
MERGECOPY |
Изображение определяется результатом выполнения операции побитового И над копируемым изображением и шаблоном |
MERGEPAINT |
Результирующее изображение определяется результатом выполнения операции побитового ИЛИ над инвертированным копируемым и областью-получателем |
NOTSRCCOPY |
Изображение определяется инвертированным исходным изображением |
NOTSRCERASE |
Результирующее изображение определяется результатом выполнения операции побитового ИЛИ над областью-источником и областью-получаталем с последующим инвертированием цвета |
PATCOPY |
Шаблон копируется в область получатель |
PATINVERT |
Изображение определяется результатом выполнения операции побитового исключающего ИЛИ над шаблоном и областью-получателем |
PATPAINT |
Изображение определяется результатом выполнения операции побитового ИЛИ над областью-источником и шаблоном с последующим объединением операцией ИЛИ с областью-получателем |
SRCAND |
Изображение определяется результатом выполнения операции побитового И над областью-источником и областью-получателем |
SRCCOPY |
Область-источник копируется в область-получатель без изменений |
SRCERASE |
Изображение определяется результатом выполнения операции побитового И над областью-источником и инвертированной областью-получателем |
SRCINVERT |
Изображение определяется результатом выполнения операции побитового исключающего ИЛИ над областью-источником и областью-получателем |
SRCPAINT |
Изображение определяется результатом выполнения операции побитового ИЛИ над областью-источником и областью-получателем |
WHITNESS |
Область-получатель заливается белым цветом |
Visual Basic предоставляет несколько методов для рисования на формах элементов управления PictureBox (см. гл. 6). Этих методов немного, но разнообразие их параметров делает эти методы достаточно гибкими. Однако они работают не так быстро, как их "двойники" из набора API-функций. Система Windows содержит много графических объектов и достаточное количество API-функций для рисования
и заливки изображений. В этом параграфе рассмотрены некоторые API-функции, которые помогут повысить быстродействие приложений, создаваемых в Visual Basic (рассмотрение всех API-функций для работы с графикой выходит за пределы этой книги). В последнем параграфе главы рассмотрены основные положения графических API-функций Windows, контекстов устройств и растровых структур. Эти методы помогут написать быстродействующие программы, позволяющие организовать вывод графических изображений и манипулировать отдельными пикселями.
Примечание
Обратите внимание: значительная часть данной главы посвящена графическим функциям и методам вывода растровых изображений. Графические операции являются самыми медленными в Windows, поэтому Visual Basic с благодарность примет от вас любую помощь. Примеры, приведенные в данном параграфе, помогут вам ускорить выполнение графических операций.
Вывод линий и окружностей
Двумя основными API-функциями являются функции LineTo() и Ellipse(), позволяющие выводить прямые линии и эллипсы (окружности). Объявление функции LineTo() приведено ниже.
Public Declare Function LineTo Lib "gdi32" Alias ''LineTo" _
(ByVal hdc As Long, ByVal x As Long, ByVal у As Long) As Long
Функция LineTo() позволяет нарисовать отрезок прямой, соединяющий текущую точку и точку с координатами (X, Y) в указанном контексте устройства. Чтобы определить текущую точку, воспользуйтесь функцией MoveToEx():
Private Declare Function MoveToEx Lib "gdi32" Alias "MoveToEx" _
(ByVal hdc As Long, ByVal x As Long, ByVal у As Long,
IpPoint As POINTAPI) As Long
Параметры х и у функции MoveToEx() являются координатами новой текущей точки. Последний параметр - структура POINTAPI - содержит координаты текущей точки перед их изменением данной функцией. Структура POINTAPI рассматривалась ранее в параграфе "Объявление 32-х разрядных функций и структур" этой главы.
Координаты точек в обеих функциях (как и во всех графических API-функциях) задаются в пикселях. Если возникает необходимость в совместном использовании графических методов Visual Basic и API-функций, то необходимо установить значение соответствующего свойства элемента управления равным 3 (пиксели). Чтобы в окне формы Form1 нарисовать отрезок прямой линии от точки с координатами (10,10) до точки (85,130), используется следующий набор операторов.
Dim point As POINTAPI
MoveToEx Forml.hDC, 10, 10, point
LineTo Forml.hDC, 85, 130
Функция Ellipse(), объявленная ниже, предназначена для вывода эллипсов и кругов.
Public Declare Function Ellipse Lib "gdi32" Alias "Ellipse" _
(ByVal hdc As Long, ByVal XI As Long, ByVal Yl As Long, _
ByVal X2 As Long, ByVal Y2 As Long) As Long
Эта функция позволяет нарисовать эллипс в контексте устройства, определенном дескриптором hdc. Эллипс вписан в прямоугольник, определенный координатами противоположных вершин (XI, Y1) и (X2,Y2). Чтобы нарисовать квадрат, нужно задать прямоугольник с одинаковыми сторонами.
Если эти команды используются для создания изображений на формах или элементах управления PictureBox, то цвет линии определяется значением свойства ForeColor формы или PictureBox, а ширина - значением их свойства DrawWidth. Можно изменить значения свойств либо воспользоваться API-функцией CreatePen().
Public Declare Function CreatePen Lib "gdi32" Alias "CreatePen" _
(ByVal nPenStyle As Long, ByVal nWidth As Long, _
ByVal crColor As Long) As Long
Параметр nPenStyle целое число, которое может принимать любое из значений, приведенных в табл. 13.8. Указанные значения соответствуют значениям свойства DrawMode.
Таблица 13.8. Значения параметра nPenStyle функции CreatePenQ
Константа |
Значение |
PS_SOLID |
0 |
PS_DASH |
1 |
PS_DOT |
2 |
PS_DASHDOT |
3 |
PS_NULL |
5 |
PS_DASHDOTDOT |
4 |
PS_JNSIDEFRAME |
6 |
Для создания сплошного пера красного цвета шириной два пикселя необходимо вызвать функцию CreatePen() со следующими параметрами:
myPen = CreatePen (0, 2, RGB (255, 0, 0))
Создание объекта Pen не означает, что данный объект будет автоматически использоваться в последующих операциях вывода графики. Чтобы использовать новое перо в дальнейшем, "свяжите" объект Pen с контекстом устройства, в котором он применяется. Вызовите для этого функцию Select0bject().
Public Declare Function Select0bject Lib "gdi32" Alias _
"SelectObject" (ByVal hdc As Long, ByVal h0bject As _
Long) As Long
Первый параметр дескриптор контекста устройства, в котором будет выполняться процедура рисования, а второй параметр дескриптор объекта Pen. Чтобы указать, что объект myPen будет использоваться в последующих операциях, вызовите такую функцию:
Select0bject Forml.hDC, myPen
После того как этот оператор выполнится, функции Line() и Ellipse() смогут использовать перо myPen при выводе изображений в контекст устройства. Аналогичным объекту Pen является объект Brush, который используется для заливки областей (эта процедура будет рассмотрена позже). Воспользуемся функцией CreateSolidBrush() для создания объекта Brush.
Public Declare Function CreateSolidBrush Lib "gdi32" Alias _
"CreateSolidBrush" (ByVal crColor As Long) As Long
Цвет кисти задается функцией RGB() или свойством Color в диалоговом окне Color. Чтобы использовать объект Brush в дальнейших операциях, выберите его в контексте устройства с помощью функции SelectObject().
VB6 в действии: проект APIDraw
В проекте APIDraw показана работа графических API-функций, рассмотренных в предыдущем параграфе. APIDraw - достаточно простое приложение, которое рисует круг, эллипс и описанные вокруг них (ограничивающие) прямоугольники (рис. 13.11). В следующем параграфе рассмотрена процедура заливки созданных изображений.
Рис. 13.11. Приложение APIDraw: круг и эллипс, созданные с помощью API-функции Ellipse()
В начале программы объявляются API-функции.
Private Declare Function LineTo Lib "gdi32" (ByVal hdc As Long,
ByVal x As Long, ByVal у As Long) As Long
Private Declare Function Ellipse Lib "gdi32" (ByVal hdc As Long,
ByVal XI As Long, ByVal Yl As Long, ByVal X2 As Long, _
ByVal Y2 As Long) As Long
Private Declare Function MoveToEx Lib "gdi32" (ByVal hdc As Long, _
ByVal x As Long, ByVal у As Long, IpPoint As POINTAPI) _
As Long
Private Declare Function CreateSolidBrush Lib "gdi32" _
(ByVal crColor As Long) As Long
Private Declare Function ExtFloodFill Lib "gdi32" (ByVal hdc _
As Long, ByVal x As Long, ByVal у As Long, ByVal crColor _
As Long, ByVal wFillType As Long) As Long
Private Declare Function SelectObject Lib "gdi32" _
(ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" _
(ByVal hObject As Long) As Long
Фрагмент программы, обрабатывающий щелчок на клавише Draw Now (см. рис. 13.11) содержит функции MoveToEx() и LmeTo(), позволяющие нарисовать ограничивающие прямоугольники, и функцию Ellipse() для вывода эллипса. Первый эллипс ограничен прямоугольником, противоположные вершины которого расположены в точках с координатами (10, 10) и (500, 300), а второй - ограничен прямоугольником, который простирается из точки (10, 10) в точку (300, 300). Так как второй прямоугольник является квадратом, второй эллипс является окружностью. Фрагмент программы, обрабатывающий нажатие кнопки Draw Now, приведен ниже
Программа 13.12. Вывод эллипсов
Private Sub Commandl Click()
Dim point As POINTAPI
Forml.CIs
Forml.ForeColor = RGB(255, О, О)
MoveToEx Forml.hdc, 10, 10, point
LineTo Forml.hdc, 500, 10
LineTo Forml.hdc, 500, 300
LineTo Forml.hdc, 10, 300
LineTo Forml.hdc, 10, 10
Ellipse Forml.hdc, 10, 10, 500, 300
Forml.ForeColor = RGB(0, 0, 255)
MoveToEx Forml.hdc, 10, 10, point
LineTo Forml.hdc, 300, 10
LineTo Forml.hdc, 300, 300
LineTo Forml.hdc, 10, 300
LineTo Forml.hdc, 10, 10
Ellipse Forml.hdc, 10, 10, 300, 300
End Sub
Заливка замкнутых фигур
Очень полезным режимом (отсутствующим в Visual Basic) является режим заливки замкнутых фигур (областей). Можно легко нарисовать окружность и прямоугольник, залитые определенным цветом, но как быть с фигурами, контуры которых определяются пересечением базовых фигур (см. рис. 13.11)? Для заливки фигур неправильной формы необходимо использовать API-функцию ExtFloodFill().
Public Declare Function ExtFloodFill Lib "gdi32" _
Alias "ExtFloodFill" (ByVal hdc As Long, ByVal x As Long, _
ByVal у As Long, ByVal crColor As Long, ByVal _
wFillType As Long) As Long
Эта функция позволяет залить сплошную область, начинающуюся в точке с координатами (x, у) цветом, определенным параметром crColor. Последний параметр (wFillType) определяет тип заливки и может принимать одно из следующих значений.
• FLOODFILLBORDER (0) - функция выполняет заливку области цветом crColor. Точка (х, у) должна находиться в пределах закрашиваемой области.
• FLOODFILLSURFACE (1) - параметр cIColor определяет только цвет обрамления.
Поскольку область заливается с помощью кисти, сначала необходимо создать объект Brush, затем выбрать его в контекст устройства и вызвать функцию ExtFloodFill(). Фигуры, появляющиеся на экране после щелчка на кнопке Draw Now (приложения Ellipse), содержат весьма причудливые области, для заливки которых применяется функция ExtFloodFill(). К этой программе добавлен небольшой фрагмент, позволяющий заливать замкнутые области цветом, выбранным пользователем в диалоговом окне Color. Чтобы заполнить область, щелкните на кнопке Fill Color (в общем диалоговом окне Color) и выберите цвет заливки, а затем щелкните на точке, расположенной в пределах области, которую вы хотите залить. Заливка выполняется в обработчике события MouseUp, текст которого приведен ниже.
Программа 13.13. Заливка замкнутой области
Private Sub Form MouseUp(Button As Integer, Shift As Integer, _
x As Single, у As Single)
brush = CreateSolidBrushe(CommonDialogI.Color)
SelectObject Me.hdc, brush
ExtFloodFill Me.hdc, x, y, Me.point(x, y), FLOODFILLSURFACE
DeleteObject brush
End Sub
Программа извлекает информацию о выбранном цвете из элемента управления CommonDialogI и использует ее для создания сплошной кисти. Затем кисть выбирается в контекст устройства формы и вызывается функция ExtFloodFill(), с помощью которой выполняется заливка требуемой области.
В большинстве случаев можно не беспокоиться о быстродействии приложений, в которых выводится всего несколько линий (даже если этот процесс занимает пару миллисекунд), за исключением, быть может, отдельных случаев, связанных с выводом сложных с математической точки зрения кривых. Но даже тогда, вероятно, нет смысла возиться с использованием API-функций. Если вспомнить о приложении Image (см. гл. 7), в котором в процессе обработки изображения необходимо было устанавливать значения цвета примерно для миллиона пикселей, то там все выглядит иначе: каждая лишняя миллисекунда, затраченная на обработку одного пикселя, будет приводить к значительной задержке всего цикла в целом. В гл. 12 рассматривались функции GetPixelV() и SetPixelV(), которые работают значительно быстрее, чем их аналоги в Visual Basic (методы Point и PSet соответственно) для чтения и установки значения пикселя.
Функция GetPixelV() возвращает значения пикселя в координатах (х, у) в контексте устройства, определенном параметром hdc, следующим образом.
Public Declare Function GetPixel Lib "gdi32" Alias "GetPixel" _
(ByVal hdc As Long, ByVal x As Long, ByVal y As Long) _
As Long
Значение пикселя возвращается как тип Long так же, как это сделал бы метод Point. Первый параметр функции GetPixel() - значение свойства hDC формы, элемента управления PictureBox или любого другого элемента управления, в который можно осуществить вывод графики.
Объявим функцию SetPixel().
Public Declare Function SetPixel Lib "gdi32" Alias "SetPixel" _
(ByVal hdc As Long, ByVal x As Long, ByVal у As Long, _
ByVal crColor As Long) As Long
Здесь hdc - дескриптор контекста устройства управления, x и у - координаты пикселя, а crColor его цвет.
На рис 13.12 приведено окно приложения CopyPix, которое выполняет копирование пикселей из левого PictureBox в правый с помощью программы, использующей операторы Visual Basic (кнопка Сору VB), или API-функции GetPixelV() и SetPixelV() (кнопка Сору API). Запустите приложение, чтобы увидеть, насколько быстрее работают API-функции по сравнению с их эквивалентами в Visual Basic. При этом можно не засекать время, требуемое для выполнения этих операций разница будет заметна даже "на глаз". Не забудьте, что значение свойства AutoRedraw второго элемента PictureBox должно иметь значение False, чтобы можно было заметить разницу в скорости выполнения операций копирования.
Проект CopyPix необходимо запускать на системе, способной отображать более 256 цветов. Если система поддерживает только 256 цветов, необходимо удостовериться, что цвет, выбранный для заливки области, является цветом из палитры, а не псевдоцветом. Если цвет является псевдоцветом, то область будет заполнена с помощью шаблона, состоящего из точек разного цвета. Если снова попытаться залить эту же область, то программа выполнит заливку только одного пикселя, поскольку функция ExtFloodFill() позволяет выполнить заливку области, имеющей сплошной цвет, а не псевдоцвет.
Рис. 13.12. В проекте CopyPix демонстрируется различие в быстродействии между методами Visual Basic и эквивалентными API-функциями
Текст программы настолько прост, что здесь приводится только фрагмент, обслуживающий кнопку Copy API. В программе выполняется просмотр каждого пикселя исходного (левого) изображения (с помощью двойного цикла), считывается
значение цвета пикселя, а затем это значение присваивается пикселю с теми же координатами в правом PictureBox. Фрагмент программы приведен ниже.
Программа 13.14. Копирование пикселей с помощью API-функций
Private Sub Conmiand2_Click ()
Dim i As Integer, 3 As Integer
Dim cIrValue As Long
For i = 0 To Picturel.ScaleWidth - 1
For j = 0 To Picturel.ScaleHeight - 1
SetPixel Picture2.hdc, i, ~j, GetPixel(Picturel.hdc, i, j)
Next
' DoEvents
Next
End Sub
Чтобы копировать изображение из окна одного элемента управления в другое, можно использовать либо метод PaintPicture, либо API-функцию BitBlt(). Они работают одинаково быстро. Если же возникает необходимость обработать отдельные пиксели, то использование двух API-функций, рассмотренных ранее, позволит значительно ускорить процесс обработки. В гл. 12 рассматривалось использование соответствующих функций для оптимизации быстродействия приложения Image, в котором большая часть времени уходила на чтение и установку значений пикселей.
Операции вывода пикселей с помощью функций SetPixelV() и GetPixelV() занимают гораздо меньше времени, чем при использовании их аналогов в Visual Basic, но все же они выполняются не очень быстро. Для значительного увеличения быстродействия требуется использовать дополнительные API-функции.
Если вывод изображения в окно формы выполняется с помощью методов Visual Basic, то изображение, фактически, записывается в область памяти, содержимое которой затем отображается в окно формы. Visual Basic работает с этой областью памяти, в результате чего появляются несколько уровней обработки, которые лежат между программой и реальным окном на экране. API-функции, рассмотренные в предыдущем параграфе, позволяют выполнить те же операции, но они работают гораздо быстрее, чем программа Visual Basic. (На самом деле Visual Basic выполняет вызов этих же функций, однако, этот процесс скрыт от программиста VB. За счет этого использование функций упрощается, а время выполнения - увеличивается.)
Windows не позволяет приложению выполнять вывод графики непосредственно на экран. Следует помнить о том, что в Windows можно запускать одновременно несколько приложений, переключаться между ними и при этом не беспокоиться о том, как будут происходить перерисовка окон и переключение между палитрами -это делает Windows. Но Windows была бы не в состоянии уследить за всеми подробностями, если бы приложениям был предоставлен прямой доступ к растровым изображениям окон на экране. Именно поэтому процедуры рисования в Windows выполняются медленно.
Независимо от того, как Windows выполняет вывод объектов и их заливку, в конечном счете, растровое изображение должно быть сохранено где-нибудь в памяти. Имеются соответствующие API-функции, которые позволяют приложениям обращаться к этой области памяти и осуществлять вывод изображения, устанавливая значения битов и байтов. Вывод изображения непосредственно в область памяти выполняется значительно быстрее, чем в контекст устройства, но его организация сложнее. Кроме того. когда вывод изображения выполняется в область памяти, на экране ничего не появляется. Необходимо написать программу, которая передает изображение из области памяти в окно на экране. Но даже с учетом этих дополнительных шагов вывод изображения в область памяти выполняется значительно быстрее, чем вывод в контекст устройства.
Чтобы вывести изображение в область памяти, необходимо выделить в памяти место для растрового изображения. Такая структура должна быть совместимой с контекстом устройства, в которое выполняется вывод изображения. Иными словами, для организации вывода изображения на принтер и на монитор требуется определять различные структуры. Чтобы создать в памяти растровую структуру для хранения изображения, требуется вызвать функцию CreateCompatibleBitmap().
Public Declare Function CreateCompatibleBitmap Lib "gdi32" _
Alias "CreateCompatibleBitmap" (ByVal hdc As Long, _
ByVal nWidth As Long, ByVal nHeight As Long) As Long
Первый параметр функции это контекст устройства, с которым совместимо растровое изображение. С другой стороны, это контекст устройства, в который помещается растровое изображение, чтобы его можно было вывести на экран. Два оставшихся параметра определяют размер растрового изображения в пикселях.
Так как изображение будет выводиться на экран, необходимо создать контекст устройства с помощью функции CreateCompatibleDC(), а затем выбрать растровую структуру в контекст устройства с помощью функции SelectObject(). Функция CreateCompatibleDCO объявляется так:
Public Declare Function CreateCompatibleDC Lib "gdi32" _
Alias "CreateCompatibleDC" (ByVal hdc As Long) As Long
Ее параметром является контекст элемента управления (или формы), в которую выводится изображение. Если требуется сначала подготовить растровое изображение в памяти, а затем вывести его в окно элемента управления PictureBoxl, то можно воспользоваться следующими операторами.
hBMPSource = CreateCompatibleBitmap(Picturel.hdc, _
Picturel.ScaleWidth, Picturel.ScaleHeight)
hSourceDC = CreateCompatibleDC(Picturel.hdc)
SelectObject hSourceDC, hBMPSource
После того как эти операторы выполнены, можно выполнить вывод изображения в контекст устройства hSourceDC, используя рассмотренные выше функции. Обратите внимание: содержимое контекста устройства hSourceDC не выводится на монитор непосредственно. Это изображение остается в памяти и может быть изменено очень быстро. А вот чтобы вывести его на монитор (т.е. передать его содержимое в окно элемента управления PictureBox2), следует воспользоваться функцией BitBlt().
Для обработки команды Сору Fast (третья кнопка на форме проекта CopyPix) используется именно такой прием при чтении значений цвета пикселей из окна левого элемента управления PictureBox и записи в правый PictureBox. Текст программы обработчика команды Сору Fast приведен ниже.
Программа 13.15. Обработчик команды Сору Fast
Private Sub Command3_Click()
Picture2.CIs
' Задание области-источника растрового изображения
hBMPSource = CreateCompatibleBitmap(Picurel.hdc, _
Picturel.ScaleWidth, Picturel.ScaleHeight)
hSourceDC = CreateCompatibleDC(Picturel.hdc)
SelectObject hSourceDC, hBMPSource
' Задание области-получателя растрового изображения
hBMPDest = CreateCompatibleBitmap(Picture2.hdc, _
Picture2.ScaleWidth, Picture2.ScaleHeight)
hDestDC = CreateCompatibleDC(Picture2.hdc)
SelectObject hDestDC, hBMPDest
' Копирование растрового изображения в область-источник
BitBIt hSourceDC, 0, 0, Picturel.ScaleWidth - 1, _
Picturel.ScaleHeight - 1, Picturel.hdc, 0, 0, &НСС0020
' Копирование пикселей из одной области в другую
For 1 = 0 То Picturel.ScaleWidth - 1
For j = 0 To Picturel.ScaleHeight - 1
clr = GetPixel(hSourceDC, i, j)
SetPixel hDestDC, i, j, clr
Next
Next
' Передача скопированных пикселей в другое окно PictureBox
BitBIt Picture2.hdc. О, О, Picturel.ScaleWidth - 1, _
Picture1.ScaleHeight - 1, hDestDC, 0, 0, &НСС0020
' Picture2.Refresh
' Заключительная очистка области памяти
Call DeleteDC(hSourceDC)
Call DeleteObject(hBMPSource)
Call DeleteDC(hDestDC)
Call DeleteObject(hBMPDest)
End Sub
Программа начинается с создания в памяти двух контекстов устройств, hSourceDC (соответствующего растровому изображению в окне левого элемента управления PictureBox) и hDestDC (соответствующего растровому изображению в правом элементе управления PictureBox). Затем выполняется копирование пикселей из окна элемента управления PictureBox 1 в соответствующий контекст устройства (при создании контекст устройства содержит произвольные данные). Затем в двойном цикле выполняется копирование пикселей из контекста hSourceDC в контекст hDestDC с помощью API-функций GetPixelV() и SetPixelV(). Нетрудно заметить, что методы для вывода изображения в контекст устройства и в контекст области памяти одинаковы.
Во время копирования пикселей содержимое экрана не изменяется. Если создание изображения выполняется в памяти, то Windows неизвестно о том, что предполагается делать с этим изображением в дальнейшем, поэтому никаких изменений на экране не происходит. В конце концов, когда пиксели будут скопированы, следует переместить растровое изображение из памяти (контекст hDestDC) в окно элемента-получателя (окно элемента управления PictureBox2). Это выполняется с помощью функции BitBlt(). В заключение программа освобождает
все ресурсы, созданные во время выполнения операции, с помощью функций DeleteDC() и Delete Object().
Запустите проект CopyPix и щелкните на кнопке Сору Fast, чтобы увидеть, насколько быстрее он работает по сравнению с двумя другими методами. Недостаток этого метода состоит в том, что невозможно наблюдать за скоростью выполнения операции копирования пикселя. Второе изображение появится на экране только тогда, когда все пиксели буду скопированы. Если обрабатываются большие изображения, то функцию BitBlt() придется вызывать чаще (например, при копировании каждого столбца пикселей). Это приводит к появлению некоторой задержки, но метод, описанный в этом параграфе, все равно быстрее двух других. Можно добавить в программу индикатор, позволяющий пользователю получить представление о скорости выполнения программы и времени, оставшемся до ее завершения.
Этим примером заканчивается рассмотрение API-функций. В следующей главе рассмотрены организация взаимодействия программ Visual Basic с внешними приложениями (такими, как Excel и Word) и управление их объектами с помощью VBA. Офисные приложения предоставляют много возможностей, которые можно использовать в VB-приложениях, поэтому не имеет смысла заново их разрабатывать в Visual Basic.
• Расширение возможностей Visual Basic с помощью OLE
• OLE-терминология
• Связывание и встраивание
• Применение элемента управления OLE Container
• Автоматизация OLE и VBA
• Программирование объектов Word
• Программирование объектов Excel
• Программирование объектов Outlook
Visual Basic весьма эффективный объектно-ориентированный язык, позволяющий скрывать от пользователя многие подробности использования объектов и управления ими. Элементы, используемые для организации интерфейса пользователя, являются объектами, и управление ими осуществляется с использованием соответствующих свойств и методов. Предполагается, что в данный момент пользователь уже хорошо знаком со свойствами объектов Visual Basic.
В этой главе рассматриваются два достаточно сложных аспекта применения объектов Visual Basic: OLE и автоматизация OLE Automation. Средства OLE позволяют организовать взаимодействие приложений, созданных с помощью Visual Basic, с приложениями, работающими в среде Windows. Средства управления, использовавшиеся до сих пор, были встроенными средствами Visual Basic. Они находятся на панели элементов управления (Tool-box), и их можно поместить в окно формы с помощью мыши. Однако некоторые объекты Windows не входят в состав встроенных средств Visual Basic. Они поставляются вместе с другими приложениями, но их можно использовать и в прикладных программах.
К таким объектам относятся документы, созданные в текстовом процессоре Word, поэтому DOC-файлы можно встраивать в собственные приложения. При этом нет необходимости выяснять детали организации этих файлов или способ записи их на диск. Если нужно редактировать файлы, встроенные в приложение, то можно почти мгновенно вызвать на экран меню Word и соответствующие панели инструментов и отобразить их непосредственно в прикладной программе. После этого можно редактировать документ так, как если бы он находился в Word.
Можно организовать управление приложением, например. Word, манипулируя его объектами с помощью средств, предоставляемых VBA (Visual Basic for Applications). VBA популярный и мощный язык, позволяющий программистам быстро приспосабливать популярные прикладные программы (подобные Word и Excel) под выполнение определенных задач, а не разрабатывать новые прикладные программы, удовлетворяющие специфическим требованиям решаемых задач как в мелком бизнесе, так и в крупном. Знания, полученные при изучении Visual Basic, легко применимы при работе с VBA, но прежде следует ознакомиться со структурой и основными принципами функционирования VBA.
В первой части главы рассмотрено, как можно расширить возможности Visual Basic за счет использования OLE, позволяющего включать в ваши программы объекты, предоставляемые другими прикладными программами. Вторая часть главы является введением в VBA. В ней рассмотрены возможности использования всех средств Word, Excel и Outlook непосредственно из VB-приложений с помощью автоматизации OLE и VBA.
В прошлом инструментальные средства разработки программного обеспечения были практически одинаковы, и отличались, в основном, способностью обмена информацией с другими инструментальными средствами. Системы программирования можно было рассматривать как острова, изолированные друг от друга. При создании приложений использовались методы структурного программирования.
С появлением OLE в разработке программного обеспечения был осуществлен переход от процедурного к объектно-ориентированному программированию. Это позволило создавать самодостаточные модули или объекты, что значительно упростило программирование, в частности, при разработке крупных приложений. В предыдущих главах рассматривалось использование объектов, встроенных в Visual Basic, для построения приложений. С помощью OLE можно совместно использовать объекты Visual Basic и объекты, принадлежащие другим прикладным программам. Теперь ваши программы не "острова" в море функциональных возможностей, а органичная часть операционной системы и других прикладных программ.
Сущность технологии OLE состоит в использовании компонентов программного обеспечения. Компонент это объект (элемент управления или приложение) который кто-то уже разработал, и его можно использовать в вашей программе. Если компонент поддерживает OLE, то можно "позаимствовать" его функциональные возможности для собственных целей. Например, Microsoft Word содержит средства проверки правописания. Зачем же покупать другую программу проверки, или писать собственную, если можно позаимствовать эти функциональные возможности из Word?
Разработчик компонентного программного обеспечения рассматривает программу как совокупность работающих вместе компонентов, что позволяет обеспечить общий стандарт интерфейса для OLE-приложений. Например, функциональные возможности электронной таблицы могут быть доступными в текстовом процессоре, и наоборот. Прикладная программа, созданная средствами Visual Basic, может обладать функциональными возможностями и текстового процессора, и электронной таблицы.
Документ, содержащий объекты нескольких типов, называется составным. Например, Word-документ, содержащий таблицу Excel или изображение, является составным документом. Попытки разработать многофункциональные прикладные программы, позволяющие работать с текстом, числами, изображениями, средствами связи и выполнять прочие функции, необходимые среднему пользователю, были неудачными до тех пор, пока не появилась технология OLE.
Парни из Microsoft учли потребность среднего пользователя в средстве, позволяющем объединять любимые прикладные программы. Они также поняли, что создать универсальное приложение невозможно и придумали OLE, позволяющее приложениям обмениваться данными и функциями. Поскольку OLE-приложения могут быть связаны друг с другом, пользователи могут использовать их отдельные компоненты для создания собственных приложений. Красота OLE состоит в том, что для использования в вашем приложении возможностей другого приложения нет необходимости знать детали его реализации. Аналогично, тому, кто программирует на Visual Basic, нет нужды знать подробности выполнения операций элементом управления RichTextBox или функционирования элемента MSFlexGrid.
OLE позволяет сконцентрироваться на работе с данными. Пользователю достаточно знать, что необходимо сделать, а не как сделать, и какие программные средства использовать при этом. Например, пользователю многокомпонентной программы не обязательно для работы с электронными таблицами использовать только Excel или для работы с текстом - только WordPerfect. OLE-приложение предоставляет пользователю доступ к функциональным возможностям электронной таблицы, текстового процессора или графической программы, и все это внутри одной программы, называемой приложением-контейнером (container application). Visual Basic позволяет создавать компоненты, которые могут использовать функциональные возможности других прикладных программ, и приложения, содержащие составные документы.
Примечание
В прикладных программах, структурированных традиционным образом, главное внимание уделяется обработке данных, а в OLE-приложениях тому, чем будут обрабатываться эти данные. При изучении OLE-технологии следует помнить об этом простом принципе, выражающем сущность OLE и делающем OLE полезным для пользователя, удовлетворение интересов которого является целью разработчика. Программирование с использованием OLE может оказаться сложным, но конечный продукт должен быть простым и удобным в использовании.
Обычно в этом месте книги приводится несколько примеров, в которых рассматривается применение изученных ранее объектов. Мы же прежде рассмотрим некоторые термины OLE, использующиеся в этой главе. В OLE существует собственная терминология. Вы можете сразу не понять все описанные ниже термины, но они будут пояснены позже с помощью примеров.
OLE-объект
OLE-объект - это объект, который делается доступным для других приложений с помощью приложения-сервера OLE. Приложение-сервер OLE делает доступными объекты различных типов (или классов). OLE-объекты используются в приложениях-контейнерах (container applications). На рис. 14.1 показано, как приложение Excel (в данном случае оно является приложением-сервером) делает доступной электронную таблицу (OLE-объект), которую можно вставить в документ Word (приложение-контейнер).
Рис. 14.1. Таблица Excel, встроенная в документ Word
Приложение-сервер
Это приложение, функциональные возможности которого доступны для приложения, разработанного в Visual Basic. Когда вашей программе требуется отредактировать документ, созданный приложением-сервером, она просто устанавливает связь, и приложение-сервер используется для редактирования.
Приложение-контейнер
Это приложение, которое содержит OLE-объекты. Объекты могут быть связаны (linked) или встроены (embedded). Сам по себе, контейнер также является объектом. Примером контейнера может служить форма (FRM) - объект, содержащий элементы управления. О контейнере говорят как о клиенте (client), потому что он использует средства OLE-сервера для получения доступа к объектам. В примере, показанном на рис 14.1, Excel является приложением-сервером, a Word приложением-контейнером.
Встраивание объекта
Используя встраивание (часто называют внедрение), можно вставить объект из одного приложения (приложения-сервера) в другое (приложение-контейнер). Встроенный объект является копией оригинала, им можно манипулировать независимо от оригинала. Например, можно внедрить блок ячеек из таблицы Excel в документ Word. Для редактирования содержимого ячеек достаточно выполнить на них двойной щелчок, что приведет к вызову самой программы Excel. Если приложение-контейнер позволяет выполнять редактирование на месте (in-place editing), то меню Excel появится прямо в нем (см. параграф "Оперативное редактирование").
Связывание объекта
Этот метод напоминает встраивание, за исключением того, что данные связаны с документом, из которого они переданы. Изменения объекта в приложении-сервере автоматически отражаются в приложении-контейнере. При связывании происходит встраивание ссылки на объект, открытый приложением-сервером. Каждый раз, когда открывается документ, содержащий связанный объект, приложение-контейнер связывается с приложением-сервером, которое и открывает последнюю версию связанного объекта. Связываемые объекты не являются копиями. Это оригиналы, которые можно просматривать из различных контейнеров.
Оперативное редактирование
Оперативное редактирование (in-place editing) также известно под названием оперативной активации. При этом функциональные возможности приложения-сервера встраиваются в приложение-контейнер, позволяя редактировать объект, с помощью меню и инструментальных средств сервера приложения. Например, если документ Word содержит блок ячеек из таблицы Excel, то двойной щелчок на любой ячейке этого блока приведет к замене меню Word на меню Excel. Это позволяет редактировать содержимое ячеек без переключения в другую прикладную программу.
Оперативное редактирование это наиболее очевидное проявление того, что раньше называлось "заимствованием функциональных возможностей другой прикладной программы". Чтобы можио было выполнять оперативное редактирование, контейнер и сервер должны поддерживать автоматизацию OLE (рассматривается ниже).
Автоматизация OLE
Этот метод позволяет программно управлять объектами, предоставляемыми другими приложениями, непосредственно из приложений, созданных в Visual Basic. Он является стандартом, определяющим способ распределения программного кода между приложениями и способ управления одними приложениями из других. Например, если блок ячеек из таблицы Excel копируется в документ Word, то происходит встраивание этого блока. Используя автоматизацию OLE, приложение может потребовать, чтобы Excel выполнил определенные вычисления и передал результаты в Word. Можно передать таблицу в Excel, чтобы выполнить обработку данных, которую нельзя сделать средствами Word, а затем возвратить таблицу в Word. Далее в главе рассмотрены примеры приложений Visual Basic, которые управляют объектами, созданными в Word и Excel.
Применение метода "перетащить-и-опустить" в OLE
Используя этот метод можно брать объекты, предоставляемые приложением-сервером и помещать их в приложение-контейнер. Например, можно встроить объект в документ Word, перетащив в него блок ячеек из таблицы Excel. В гл. 4 рассматривались способы программирования метода "перетащить и-опустить" Далее в этой главе будет рассмотрено, как выделить часть документа (или весь документ) и перенести его в окно элемента управления, который распознает перетаскиваемые данные и элемент управления, от которого они поступили.
Давайте рассмотрим пример реализации связывания и встраивания с точки зрения пользователя. Чтобы создать составной документ с помощью программы 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. Во время редактирования связанного объекта средствами приложения-сервера, связанное с ним изображение в приложении-контейнере также модифицируется по мере редактирования исходного объекта
Примечание
Если объект, вставленный в приложение-контейнер, связан с исходным объектом (файлом-источником), то его нельзя отредактировать из приложения-контейнера. Это можно сделать из приложения-сервера. Сущность связывания заключается в том, что пользователь не может редактировать объект из какого-либо приложения. В памяти компьютера находится только один экземпляр объекта, и его можно изменить только с помощью программы, в которой он был создан. Как только объект будет изменен, все программы, имеющие на него ссылки, также изменятся.
Рассмотрим, как 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 можно как при разработке приложения, так и при выполнении.
В этом параграфе рассмотрено создание простого элемента управления OLE Container для демонстрации встраивания объектов во время проектирования. Встраивание во время разработки следует использовать тогда, если заранее известно, какие объекты понадобятся, или требуется ограничить пользователей приложения использованием только определенных объектов (например, документов Word). Этот метод позволяет выполнять и связывание объектов, но во время проектирования предпочтительнее организовывать встраивание. Встраивание объекта можно выполнить двумя способами:
• путем вставки существующего объекта методом "перетащить-и-опустить";
• путем вставки объекта с помощью диалогового окна Insert Object (Вставка объекта).
Встраивание методом "перетащить-и-опустить"
Чтобы внедрить объект с помощью этого способа, необходимо выполнить следующие действия.
1. Открыть в Visual Basic новый проект и выполнить двойной щелчок на значке элемента OLE Container в панели элементов управления, чтобы поместить его экземпляр на форму. Visual Basic отобразит диалоговое окно Insert Object (Вставка объекта), в котором можно указать объект, внедряемый в элемент OLE Container.
2. В диалоговом окне Insert Object (Вставка объекта) (см. рис. 14.2) щелкните на кнопке Cancel. (Это означает, что в форму будет помещен пустой элемент управления OLE Container, и позднее можно будет перетащить туда OLE-объект).
3. В окне Properties (Свойства) элемента OLE Container необходимо задать значение свойства SizeMode равным 1 Stretch (если объект рисунок, размеры которого можно изменять) или 2 AutoSize (если объект текст или рисунок, размеры которого изменять не следует).
Возможные значения свойства SizeMode приведены в табл. 14.1.
Таблица 14.1. Значения свойства SizeMode
Значение |
Описание |
Clip Stretch AutoSize Zoom |
Размеры отображаемого объекта равны исходным. Если его размеры превышают размеры окна элемента управления OLE Container, то часть изображения отсекается Размеры изображения объекта подгоняются под размер окна элемента управления OLE Container. При этом изображение может исказиться Размеры окна элемента управления изменяются автоматически, чтобы объект целиком поместился в окно Размеры объекта изменяются так, чтобы он занял максимально возможную часть окна элемента управления OLE Container, сохранив при этом свои первоначальные пропорции |
4. Запустите приложение, которое поддерживает OLE, и откроите файл. В нашем примере документ Word встраивается в элемент управления OLE Container с помощью перетаскивания документа из приложения-источника (Word) на пустой элемент OLE Container.
5. Когда на экране появятся окна запущенных Visual Basic и Word, перетащите документ (или его часть) в пустой элемент управления OLE Container.
Совет
Чтобы в окно элемента управления OLE Container поместить часть документа Word, нужно выделить часть документа, а затем перетащить ее, нажав левую кнопку мыши в любом месте выделенной части. Если окно Visual Basic в данный момент невидимо, то для перехода в него нажмите клавиши Alt+Tab, не отпуская кнопку мыши. При появлении на рабочем столе формы Visual Basic перетащите выделенную часть документа в окно элемента управления OLE Container. Выделенный текст будет удален из исходного объекта (документа Word). Чтобы встроить копию выделенного текста (текст в исходном документе сохраняется), во время переноса фрагмента удерживайте нажатой клавишу Ctrl. При выполнении обычной операции перетащить-и-опустить объект из источника удаляется.
6. Во время перемещения объекта под указателем-стрелкой появляется небольшой прямоугольник. Опустите перетаскиваемый объект на пустой элемент OLE Container. Через некоторое время документ Word появится в окне элемента управления OLE Container (рис. 14.5).
Теперь форма содержит документ Word. При запуске приложения документ Word будет отображаться в окне элемента управления OLE Container. Для его редактирования можно использовать меню и инструментальные панели Word.
Рис. 14.5. Объект, перемещаемый из документа Word, появляется в окне элемента управления OLE Container
Свойства Class, SourceDoc и Sourceltem. Рассмотрим несколько свойств элемента управления OLE Container. При создании объекта в форме окно Properties (Свойства) будет содержать следующую информацию:
• имя прикладной программы, с помощью которой создан объект (свойство Class);
• данные или ссылка на данные (свойство SourceDoc);
• образ данных (свойство Sourceltem), данное значение устанавливается только при связывании объектов и определяет данные (в пределах исходного файла), связанные с управлением OLE.
Свойство OLETypeAllowed. Будет исходный документ внедрен или связан с элементом управления OLE Container, зависит от установки значения свойства OLETypeAllowed. Выберите элемент управления OLE Container в форме и найдите в окне Properties свойство OLETypeAllowed. В табл. 14.2 перечислены допустимые значения этого свойства. По умолчанию установлено значение 2 Either.
Таблица 14.2. Значения свойства OLETypeAllowed
Константа |
Значение |
Описание |
vbOLELmked vbOLEEmbedded vbOLEEither |
0 1 2 |
Элемент управления OLE Container может содержать только связанный объект Элемент управления OLE Container может содержать только встроенный объект Элемент управления OLE Container может содержать либо встроенный, либо связанный объект (установлена по умолчанию) |
Создадим связанный объект, установив значение свойства OLETypeAllowed в О (Связанный). Значение этого свойства по умолчанию не задает тип создаваемого OLE-объекта, а лишь позволяет определить тип объекта, который может быть создан. Реально используемый тип OLE-объекта указан в диалоговом окне Insert Object (Вставка объекта). Например, если значение свойства OLETypeAllowed равно 2 то в диалоговом окне Insert Object (Вставка объекта) переключатели Create New и Create from File, а также флажок Link становятся доступными. Если же значение свойства OLETypeAllowed равно 0 (Связанный), то переключатель Create New блокируется (нельзя связаться с несуществующим объектом). Если устанавливается значение 1 (Встроенный), то блокируется флажок Link (Связь).
Связывание с помощью диалогового окна Insert Object
Метод перетащить-и-опустить не единственный способ внедрения или связывания объектов в OLE Container. Опишем, как это выполняется с помощью диалогового окна Insert Object (Вставка объекта).
1. Удалите элемент управления OLE Container из формы Form1 и создайте новый элемент управления OLE Container, воспользовавшись рассмотренными выше рекомендациями.
2. В диалоговом окне Insert Object установите переключатель Create from File (Создать из файла) и флажок Link (Связь) (рис. 14.6). Как уже упоминалось, флажок Link (Связь) иногда блокируется Это происходит, когда значение свойства OLETypeAllowed равно 1 (Встроенный). Чтобы разблокировать флажок Link (Связь), установите значение свойства OLETypeAllowed в 2 (Связанный).
3. Щелкните на кнопке Browse (Обзор), чтобы отыскать требуемый файл.
4. Выбранный файл появится в окне элемента управления OLE Container. При этом может быть видна только его часть. Чтобы увидеть весь объект, измените размеры окна элемента управления.
Рис 14.6 Чтобы связать объект, установите флажок Link (Связать) в диалоговом окне Insert Object
В зависимости от установленного свойства SizeMode изображение в связанном файле может быть искажено. Теперь в элементе управления содержится ссылка на объект, а не его копия. Всякий раз, когда приложение-сервер изменяет связанный объект, объект в контейнере также изменяется.
Примечание
Когда вставляемый объект связывается с оригиналом, приложение-контейнер не содержит никаких данных. После того, как объект вставлен, в приложении-контейнере вы уведете не его копию, как это происходит при внедрении, а изображение объекта, который был вставлен.
Если связанный объект является документом Word, то он появится в окне элемента управления OLE Container (см. рис. 14.5). В ячейке, содержащей значение свойства SourceDoc, содержится путь и имя файла связанного объекта.
5. Оставьте окно Visual Basic открытым, когда открыт документ Word. Внесите изменения в исходный документ и убедитесь, что связанный объект в окне Visual Basic изменяется в реальном масштабе времени. Чтобы это увидеть, запускать приложение не требуется. В режиме проектирования связанный документ модифицируется в реальном масштабе времени, как только редактируется оригинал.
Сохранение встроенных объектов и доступ к ним
Встроенные объекты создаются приложением-сервером, а сохраняются в приложении-контейнере. При встраивании объекта связь между содержимым элемента управления OLE Container и первоначальным объектом не устанавливается. Для редактирования встроенного объекта нужно обратиться к ресурсам программы, с помощью которой объект создан, но данные для нее предоставляет приложение-контейнер. Кроме того, данные во встроенном объекте не сохраняются автоматически. Для сохранения встроенного объекта и изменений, сделанных приложением-сервером, используется метод SaveToFile. Синтаксис этого метода:
OLEl.SaveToFile filenumber
Переменная filenumber - это числовое значение, определяющее номер открытого файла. Номер передается в двоичном коде.
Ниже приведен фрагмент программы для ввода имени файла и сохранения встроенного документа с помощью метода SaveToFile.
Программа 14.1. Сохранение OLE-данных
Private Sub mnuFileSaveas Click()
Dim fnum As Integer
On Error GoTo Cancel
fnum = FreeFile
CommonDialogI.ShowSave
' Вывод на экран диалогового окна Save As
Open CommonDialogI.FileName For Binary As ftfnum
OLE1.SaveToFile (fnum)
Close ttfnum
Exit Sub
Cancel:
MsgBox "Could not save file" ' (Файл сохранен не был)
Close #fnum
End Sub
Для загрузки объекта, сохраненного как файл данных, предназначен метод ReadFromfile. Его синтаксис подобен синтаксису метода SaveToFile. Следующий
фрагмент программы реализует возможность чтения содержимого элемента управления OLE Container из файла (в котором содержимое было сохранено методом SaveToFile).
Программа 14.2. Чтение OLE-данных
Private Sub mnuFileOpen_Click()
Dim fnum As Integer
On Error GoTo Cancel
CommonDialogI.ShowOpen ' вывод на экран диалогового окна Open
Fnum = FreeFile
Open CommonDialogI.FileName For Binary As #fnum
OLE1.ReadFromFile (fnum)
Close #fnum
Exit Sub
Cancel:
MsgBox "Could not load file" ' (Файл загружен не был)
Close #fnum
End Sub
Примечание
Если значение свойства OLEType 0 (vbOLELinked), то в указанном файле сохраняется только информация о связи и о данных изображения. Если значение свойства OLEType 1 (vbOLEEm), то данные из объекта сохраняются с помощью метода SaveToFile.
Если вы сохраняете файл с внедренным объектом, то с ним сохраняется следующая информация:
• имя прикладной программы, создавшей объект;
• данные объекта,
• метафайл изображения объекта;
Если вы сохраняете файл со связанным объектом, то с ним сохраняется следующая информация:
• имя прикладной программы, создавшей объект;
• имя файла-объекта;
• метафайл изображения объекта.
Данные, сохраненные методом SaveToFile, доступны только приложению-контейнеру и только с помощью метода ReadFromFile. Названные методы являются методами Visual Basic. Они вызываются непосредственно из прикладных программ, при этом информация о формате представления исходных данных не требуется.
Использование оперативного редактирования
При запуске приложения связанный или встроенный объект отображается прямо в форме Visual Basic. Выполнив двойной щелчок на объекте, пользователь может начать его редактирование. Открыть встроенный объект для редактирования можно несколькими способами (см. параграфы " Общие свойства элемента управления OLE Container" и " Общие методы элемента управления OLE Container” далее в главе). Самый простой способ открыть приложение, предоставляющее объект для встраивания и средства редактирования (меню и панели инструментов) - выполнить двойной щелчок на объекте.
Оперативное редактирование (или оперативная активация) применяется для встроенных объектов. Пользуясь этой возможностью, можно редактировать встроенный объект внутри OLE контейнера. Функциональные возможности приложения-сервера инкорпорируются в контейнер. Оперативное редактирование доступно, если приложение-сервер поддерживает автоматизацию OLE. Если выбрать встроенный объект, то меню и панели инструментов заменят меню и панели инструментов VB-приложения (рис. 14.7). Оперативное редактирование позволяет приложению-контейнеру заимствовать функциональные возможности приложения-сервера встроенного объекта.
Рис. 14.7. Оперативное редактирование документа Word в окне элемента управления в приложении Visual Basic
Предупреждение
Некоторые приложения, использующие OLE, не могут отобразить собственные панели инструментов для оперативного редактирования объекта. Эта проблема связана с самой программой, и средствами VB-приложения не решается.
Существует еще один способ внедрения объектов в элемент управления 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 не установлен. Кроме того, пути к связанным файлам должны быть указаны правильно. В противном случае, при запуске приложения другие пользователи смогут увидеть только изображение первоначальных данных.
Рассмотрим создание и встраивание объектов во время выполнения приложения на примере приложения OLERTime (папка этой главы на компакт диске). Приложение OLERTime демонстрирует следующие возможности:
• вставку объекта;
• выбор между связыванием и встраиванием;
• установку размеров окна контейнера элемента управления или размера объекта;
• отображение информации об объекте.
Возможность встраивания и связывания объектов с элементом управления OLE Container позволяет открыть диалоговое окно Insert Object (Вставка объекта) из кода программы. В предыдущих примерах это выполнялось вручную. Операции выполняются непосредственно из окна VB-приложения пользователь может выби рать объекты и самостоятельно устанавливать некоторые их свойства. Главная форма приложения показана на рис. 14.9.
Рис. 14.9. Главное окно приложения OLERTime
После щелчка на кнопке Insert Object (Вставка объекта), приложение отображает диалоговое окно Object Type (Тип объекта) (рис. 14.10), в котором можно установить режим изменения размеров (Stretch Object) и тип OLE-связи (встраивание или связывание). Если щелкнуть на кнопке ОК, то на экране появится диалоговое окно Insert Object, в котором определяется новый объект или выбирается существующий.
Рис. 14.10. Диалоговое окно Object Type приложения OLERTime
Для проверки приложения установите переключатели в диалоговом окне Object Type (Тип объекта) в положение Stretch Container Control и Embedded, после чего щелкните на кнопке ОК. В открывшемся диалоговом окне Insert выберите объект Excel Chart. В окне элемента управления появится диаграмма, содержащая произвольные данные. Из приложения OLERTime ее можно редактировать, масштабировать (так как установлен переключатель Stretch Container Control) и даже изменять, сохраняя в отдельном файле. Приложение можно остановить, запустить и загрузить в него диаграмму из отдельного файла.
VB6 в действии: приложение OLERTime
Для разработки приложения выполните следующие действия.
1. Откройте новый проект и присвойте форме имя frmOLE. Эта форма содержит элемент управления OLE Container, пять командных (Command) кнопок (см. рис. 14.9) и элемент управления Common Dialogs.
2. При помещении элемента управления OLE Container на форму появится диалоговое окно Insert Object (Вставка объекта). Щелкните на кнопке Cancel, чтобы поместить на форму пустой контейнер. Затем измените размеры окна элемента управления OLE Container и поместите на него командные кнопки (см. рис. 14.10).
3. Добавьте к проекту новую форму и поместите на нее элементы управления (см. рис. 14.10).
4. Сохраните все формы и проект в новой папке. После этого добавьте фрагмент программы, который позволит выполнять следующие действия:
• отображать на экране второе окно (frmType) и активизировать диалоговое окно Insert Object;
• отображать информацию об объекте.
Откройте программу обработчика события Click кнопки Insert Object и введите следующие строки.
Private Sub cmdInsObj_Click()
frmType.Show
End Sub
Для отображения информации об объекте предусмотрена кнопка Object Info (вскоре мы узнаем, как объект выбирается и вставляется). После щелчка на этой кнопке выполняется следующий фрагмент программы (oleDisplay имя элемента управления OLE).
Программа 14.3. Обработчик события Click для кнопки Object Info
Private Sub cmdObjInfo_Click()
Dim SourceText As String
Dim TypeText As String
Dim MsgText As String
SourceText = "The object's source file is " + oleDisplay. SourceDoc
' (Файл объекта источника:...)
TypeText = "The type of object is " + oleDisplay.Class
' (Тип объекта:...)
MsgText = SourceText + Chr(13) + TypeText
MsgBox MsgText, vblnformation, "Object Information"
' (Информация об объекте)
End Sub
Символ ввода новой строки (vbCrLF) позволяет разбить длинное сообщение на несколько коротких строк. Если встроенный (или связанный) объект - документ Word, то отобразится следующая информация.
The object's source file is C:\My Documents\FileName
The type of object is Word.Document
(FileName будет заменено именем файла, встроенным в элемент управления OLE) На рис. 14.11 показано, что отображает кнопка Object Info, если в элемент управления OLE Container встроен объект Excel Chart. Поскольку объект Excel Chart - вновь созданный, то поле SourceDoc пусто.
Рис. 14.11. Информация, выводимая приложением OLERTime, для связанного растрового изображения
Свойства SourceDoc и Class. Кнопка Object Info позволяет отобразить значения свойств SourceDoc и Class. Значение свойства SourceDoc это имя связанного или встроенного файла. Свойство Class устанавливает или возвращает имя класса встроенного объекта, которое, по сути, является его типом. Объекты других типов это таблицы Excel (Excel.Sheet), растровые изображения, созданные программой Paint, и объекты, которые мы создадим в этой главе чуть позже. Если создать новый объест с помощью Excel, Word или другого (поддерживающего OLE) приложения, то у него не будет свойства SourceDoc встроенный объект - это еще не документ, который хранится в файле на диске.
Свойство Sourceltem. Свойство Sourceltem указывает на часть документа, которая встроена или связана. Во многих случаях значение этого свойства не определено, поскольку связан весь объект. Впрочем, для встраивания можно выделить только часть объекта. Нельзя выбрать часть документа Word или растрового изображения, но можно выбрать часть рабочего листа Excel. Если выбрать блок ячеек, то значение свойства Sourceltem будет, например, таким "R1C1 R1C10". Хотя приложение OLERTime позволяет выбрать файл для операции встраивания, но метод перетащить-и-опустить им не поддерживается. Поэтому ячейка, содержащая значение свойства Sourceltem, будет пустой.
Если щелкнуть на кнопке Insert Object, то на экране появится окно, в котором пользователю будет предоставлена возможность выбора типов данных Можно выбрать
Linked (Связанный) или Embedded (Внедренный). Также можно задать размер отображаемого объекта, установив свойство SizeMode в окне Properties (Свойства) элемента управления OLE Container. Возможны такие варианты:
• "растянуть" окно элемента управления OLE Container, чтобы подогнать его к размерам объекта (2-AutoSize);
• "растянуть" объект, чтобы подогнать его к размерам контейнера (1-Stretch).
Если пользователь выполнит щелчок на кнопке ОК, то в открывшемся диалоговом окне Insert Object (Вставка объекта) можно выбрать данные для вставки.
Вставьте командные кнопки, кнопки переключателей и рамки, изображенные на рис. 14.10. Добавьте следующий фрагмент в программу для обработчика нажатия кнопки Cancel.
Программа 14.4. Обработчик события Click для кнопки Cancel формы frmType
Option Explicit
Private Sub cmdCancel_Click()
Unload frmType
End Sub
Эта процедура закрывает приложение, выгружая форму frmType.
Установка размера окна элемента управления OLE Container. Если встраивание объектов в OLE Container происходит во время выполнения приложения, то нужно учитывать, что пользователь не может изменить размер окна элемента управления с помощью мыши. Объявим переменные OLEHeight и OLEWidth так, чтобы размеры окна элемента управления приравнивались значениям, введенным во время разработки. Чтобы непосредственно не указывать в программе значения высоты и ширины, можно использовать более гибкий способ OLEHeight и OLEWidth. Добавим следующие операторы в раздел объявления формы frmOLE.
Public OLEHeight As Integer
Public OLEWidth As Integer
и в обработчик события Load формы:
OLEHeight = oleDisplay.Height
OLEWidth = oleDisplay.Width
Теперь можно вернуться к форме frmType и добавить фрагмент, который позволяет организовать вызов диалогового окна Insert Object после установки опций пользователем.
Программа 14.5. Вызов диалогового окна Insert Object
Private Sub cmdOK_Click()
With frmOLE oleDisplay
.Height = frmOLE.OLEHeight
.Width = frmOLE.OLEWidth
End With
If opt3tretch0b]ect Value - True Then
frmOLE oleDisplay SizeMode - 1 ' Stretch
Else
frmOLE oleDisplay SizeMode = 2 ' AutoSize
End If
Добавление следующей строки позволяет скрыть форму.
FrmType Hide
В завершение, следующие операторы открывают диалоговое окно Insert Object и выполняют вставку объекта.
frmOLE.oleDisplay.InsertObjDlg
If frmOLE.oleDisplay.Class <> "" Then
frmOLE.cmd0b]lnfo.Enabled = True
End If
Unload frmType
Если объект вставлен, то становится доступной кнопка Object Info.
InsertObjDIg - это метод элемента OLE Container, позволяющий выводить диалоговое окно Insert Object (Вставка объекта), для того чтобы пользователь мог создавать связанный или встроенный объект, выбирая его тип и приложение для создания объекта. Установки пользователя автоматически присваиваются значениям соответствующих свойств элемента управления OLE.
Чтобы изменить размер контейнера, выполните следующие действия.
1. Запустите приложение, а затем щелкните на кнопке Insert Object, чтобы отобразить диалоговое окно Object Type.
2. Щелкните на одной из кнопок Size Mode (Установка размера), а затем - на Object Type (Тип объекта). На экране появится диалоговое окно Insert Object (рис. 14.12).
Ниже приводится исходный текст формы frmOLE. Обратите внимание на обработчик события Resize элемента управления OLE Container. Если предусмотрена возможность изменения размеров элемента управления во время выполнения, то обработчик события Resize вызывается каждый раз, когда пользователь изменяет размеры окна. Событие Resize передает с помощью параметров HeightNew и WidthNew новые размеры окна элемента управления обработчику, который использует их для изменения размеров формы.
Insert Object
Рис. 14.12. В диалоговом окне Insert Object установлен переключатель Create from File и отображается путь к файлу данных
Программа 14.6. Форма frmOLE
Option Explicit
Private Sub cmdClose Click()
Dim Quit As String
Quit = MsgBox ("Are you sure you want to quit?" vbYesNo + vbQuestion)
' (Вы уверены, что хотите закрыть приложение?...)
If Quit = vbYes Then
End
End If
End Sub
Private Sub cmdInsObj_Click()
frmType.Show
End Sub
Private Sub cmdObjInfo_Click()
Dim SourceText As String
Dim TypeText As String
Dim MsgText As String
SourceText = "The object's source file is " + oleDisplay. SourceDoc
' (Файл объекта источника:...)
TypeText = "The type of object is " + oleDisplay.Class
' (Тип объекта:...)
MsgText = SourceText + Chr(13) + TypeText
MsgBox MsgText, vblnformation, "Object Information"
'(Информация об объекте)
End Sub
Private Sub bttnLoad_Click()
Dim fnum As Integer
On Error GoTo LoadCancel
fnum = FreeFile
CommonDialogl.ShowOpen ' Показать диалог Open File
Open CommonDialogI. FileName For Binary As #1 ' Открыть файл
oleDisplay.ReadFromFile (fnum) ' Прочитать файл No.1
Close #fnum
Exit Sub
LoadCancel:
MsgBox "Could not load file"
' (Файл не был загружен)
Close #fnum
End Sub
Private Sub bttnSave_Click()
Dim fnum As Integer
On Error GoTo SaveCancel
CommonDialogI.ShowSave ' Показать диалог Save As
fnum = FreeFile
Open CommonDialogI.FileName For Binary As #1 ' Открыть файл
oleDisplay.SaveToFile (fnum) ' Запись в файл No. 1
Close ttfnum ' Закрыть файл
Exit Sub
SaveCancel:
MsgBox "Could not save file"
' (Файл не был сохранен)
Close #fnum
End Sub
Private Sub oleDisplay_Resize(HeightNew As Single, WidthNew As Single)
frmOLE.Width = oleDisplay.Left + WidthNew + 20 * _
Screen.TwipsРеrPixelX
frmOLE.Height = oleDisplay.Top + HeightNew + 80 * _
Screen.TwipsPerPixelY
End Sub
Программа 14.7. Форма frmType
Option Explicit
Private Sub cmdCancel_Click()
Unload frmType
End Sub
Private Sub cmdOK_Click()
With frmOLE.oleDisplay
.Height = frmOLE.OLEHeight
.Width = frmOLE.OLEWidth
End With
If optStretchObject.Value = True Then
.SizeMode = 1
Else
.SizeMode = 2
End If
If optTypeEmbedded.Value = True Then
frmOLE.oleDisplay.OLETypeAllowed = 1 ' Связывание
Else
frmOLE.oleDisplay.OLETypeAllowed = 0 ' Встраивание
End If
' Скрыть форму frmType
frmTipe.Hide
' Вставка объекта
frmOLE.oleDisplay.InsertOb]Dlg
If frmOLE.oleDisplay.Class <> "" Then
frmOLE.cmdOb]Info.Enabled = True
End If
Unload frmType
End Sub
Можете попробовать встраивать различные объекты в окно элемента управления OLE формы OLERTime и редактировать их, выполняя на объекте двойной щелчок.
Вы увидите, что у элемента управления OLE Container все еще несколько расплывчатые края. Для встраивания или связывания объекта требуется время, поэтому иногда при переключении в режим редактирования панель инструментов приложения-сервера может оказаться невидимой. При программировании на Visual Basic встраивание объектов в элемент управления OLE Container используется достаточно редко. Позднее мы узнаем, как использовать автоматизацию OLE, чтобы заставить приложение-сервер выполнять требуемые действия и возвращать результаты VB-приложению.
В этом параграфе рассмотрены свойства и методы, которые используются при работе с документами, встраиваемыми или связываемыми во время выполнения программы. Эти свойства можно установить в среде 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). Объект активизируется, когда элемент управления получает фокус либо на объекте выполняется двойной щелчок.
Чтобы управлять встроенными или связанными объектами, в элементе управления 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.
В гл. 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")
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.
OLE Automation (Автоматизация OLE) это еще один шаг вперед по сравнению со связыванием При выполнении связывания объектов выполняется заимствование функциональных возможностей другого приложения. Используя автоматизацию OLE можно управлять исходным документом непосредственно из вашего приложения. Приложения, которые поддерживают автоматизацию OLE, предоставляют свои объекты другим приложениям. Например, объектом, который предоставляет Word, может быть и предложение, и абзац, и весь документ. Объектом, который может предоставить Excel, может быть макрос, блок ячеек или весь рабочий лист.
Управлять предоставленными объектами из приложения Visual Basic можно с помощью свойств и методов, предоставленных приложением-источником. Важной особенностью Visual Basic является то, что он позволяет обращаться как к объектам приложения сервера OLE, так и к его функциональным возможностям для работы с этими объектами. Преимуществом автоматизации OLE является то, что можно, работая в единой среде, использовать любые OLE-средства, доступные в других приложениях.
Когда компания Microsoft начала разрабатывать автоматизацию OLE, основная идея была проста: создать общий язык и среду программирования, позволяющую использовать средства и возможности ряда основных приложений. В результате был разработан язык Visual Basic for Applications (VBA).
Используя только VBA нельзя разработать требуемое вам приложение, независимо от его типа VBA предоставляет в распоряжение разработчика только основные управляющие структуры, математические и строковые функции, а также возможности манипулирования переменными. Реальная эффективность VBA определяется приложениями, поддерживающими его.
С появлением VBA версии 5.0 фирма Microsoft начала продавать лицензии на него тем компаниям разработчикам программного обеспечения, которые хотели добавить к своим продуктам дополнительные средства программирования. Например язык программирования, использовавшийся в пакете AutoCAD компании AutoDesk, был уникален и не мог использоваться другими приложениями. Многие другие изготовители включали в свои программные продукты языки, позволяющие разрабатывать сценарии и прочие средства автоматизации но потребность в некоем глобальном языке который мог бы помочь объединить отдельные части различных приложении была очевидна. В конце концов, фирма Microsoft разработала VBA (версии 5), который соответствовал потребностям других разработчиков. Теперь VBA идет своей дорогой, становясь универсальным языком, позволяющим создавать универсальные приложения для Windows.
Большинство потребителей покупают сегодня готовое программное обеспечение и должны после этого настраивать его. Более половины корпорации в США ис пользуют программы фирмы Microsoft. Многие из них используют VBA, чтобы настроить эти приложения в соответствии с собственными потребностями. Это достаточно устойчивая тенденция. Кроме того, имеется потребность не только в настройке приложении, но и в придании приложениям возможности связываться между собой VBA позволяет выполнять и то и другое. В результате потребность в программистах умеющих использовать VBA, в течение последующих лет увеличится.
Сегодняшние приложения стали настолько мощными и насыщенными разно образными функциями, что больше не имеет смысл разрабатывать приложения на заказ Даже приложения из пакета Office 97 выполняют большинство рутинных компьютерных операций, необходимых для работы типичной корпорации. Важность поддержки VBA можно понять познакомившись с продуктами сторонних производителей в них также предусмотрена поддержка VBA. Давайте начнем знакомство с автоматизацией OLE рассмотрев несколько примеров.
Чтобы получить доступ к возможностям, предоставляемым приложением-сервером OLE, сначала необходимо создать переменную, на которую мог бы сослаться Excel. Эта переменная называется объектной переменной (object variable), поскольку она описывает объект, а не целое число и не иные (относительно про стые) типы данных. Характерной особенностью объектных переменных является то, что они выступают в качестве компонентов членов приложения или класса (Class), который они представляют. Например, Excel предоставляет метод Evaluate с помощью которого можно вычислять любые математические выражения. К этому методу нельзя обращаться непосредственно, к нему необходимо обратиться через объектную переменную, которая представляет приложение Excel. Иными словами, нельзя использовать оператор:
Excel.Evaluate "Log(499/0 785)" 'WRONG! (Ошибка!)
Сначала необходимо создать объектную переменную например ExcelObj, а затем вызвать метод Evaluate для переменной ExcelObf
ЕхсеlObj.Evaluate "Log (499/0 785)"
Существует две функции позволяющие создавать объектные переменные. Это функция CreateObject(), позволяющая создать новый экземпляр приложения, на который можно сослаться и функция Get0bject(), с помощью которой можно связаться с экземпляром приложения, уже запущенного на компьютере. Эти функции будут рассмотрены позже.
Примечание
Чтобы предоставить VB-приложению возможность обращаться к серверам автоматизации OLE, необходимо добавить соответствующую ссылку к проекту с помощью диалогового окна Reference, вызываемого по команде References (Ссылки) меню Project (Проект). Чтобы приложение могло воспринимать ссылки на объекты Excel, необходимо в проект добавить элемент "Microsoft Excel 8.0 Object Library", на объекты Word элемент "Microsoft Word 8.0 Object Library", и на объекты Outlook 98 элемент "Microsoft Outlook 98 Object Model"
Создание нового экземпляра
Первый метод установления связи с приложением-сервером OLE состоит в том, чтобы организовать новый экземпляр приложения, воспользовавшись функцией Create0bject():
Set AppObject = CreateObject(Class, ServerName)
Аргумент Class это имя класса приложения-сервера, зарегистрированного в реестре (Registry). Имя класса Word - это строка "Word.Application", а имя класса Excel - "Excel.Application".
Второй параметр (необязательный) является именем сетевого сервера, на котором будет создан объект. Если приложение-сервер постоянно находится на другой машине, следует также указать имя машины, на которой будет создано приложение-сервер с именем Class. Если приложение-сервер было установлено на машине с именем "Toolkit", то для создания нового "экземпляра приложения Excel следует воспользоваться следующим оператором:
Set EXLApp = Create0bject ("Excel.Application", "Toolkit")
Установление связи с уже существующим экземпляром приложения
Если приложение, с которым следует установить связь, уже запущено, нет потребности создавать его новый экземпляр. Можно "войти в контакт" с уже запущенным экземпляром приложения и открыть новый документ. Чтобы установить связь с уже выполняющимся экземпляром приложения-сервера, следует воспользоваться функцией Get0bject():
Set AppObject = GetObject(pathname, class)
Оба параметра являются необязательными, но хотя бы один из них должен быть определен. Параметр pathname это полный путь и имя файла документа, который будет открыт с помощью приложения-сервера. Второй параметр, class, является именем класса приложения, зарегистрированного в системном реестре (Registry).
Если указывается документ, который необходимо открыть данным приложением, то не следует указывать имя класса (Class) приложения. Например, разработчику не надо дополнительно указывать, что рабочий лист будет обрабатываться приложением Excel: Системе известно, что файлы с расширением XLS обрабатываются Excel, например:
Set EXLApp = Get0b]ect ("С:\sample files\Sales98.xls")
Вызов этой функции приведет к запуску Excel (если до этого не был запущен ни один экземпляр). А чтобы установить связь с уже запущенным экземпляром Excel, следует следующим оператором вызвать функцию Get0bject():
Set EXLApp = Get0bject(, "Excel.Application")
Во многих ситуациях нет разницы, будет ли запущен новый экземпляр приложения-сервера, или будет установлена связь с уже запущенным экземпляром. Например, чтобы вызывать метод Evaluate нет необходимости запускать новый экземпляр Excel. Если он уже запущен, следует связаться с ним и выполнить с его помощью вычисление математического выражения. После того как это действие будет выполнено, работающий экземпляр Excel вернется в то же состояние, что и прежде. Поэтому, предпочтительнее (с точки зрения эффективности) пытаться устанавливать связь с существующим экземпляром приложения-сервера. И только в том случае, если нет ни одного запущенного экземпляра сервера, следует его запустить В следующем фрагменте программы применяется именно этот способ. Сначала делается попытка установления связи с уже запущенным экземпляром Word. Если Word не работает, то генерируется сообщение об ошибке. Оператор On Error Resume Next предписывает Visual Basic подавлять сообщение об ошибках и продолжать выполнение программы с оператора, следующего за вызвавшим ошибку. Если происходит ошибка, значит, при вызове функции Get0bject() произошел сбой и следует вызвать функцию CreateObject(), чтобы запустить новый экземпляр Word.
Программа 14.8. Установление связи или запуск 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 quit"
'(Word не был запущен. Программа прекращает работу)"
End
End If
End If
Объявление объектных переменных
Объектная переменная, которая описывает приложение-сервер OLE, может быть объявлена либо как переменная типа Object (Объект), либо как переменная специального типа (например, Excel.Application или Word.Application). Если переменная EXLApp объявлена как переменная типа Object (Объект), то каждый раз перед вызовом соответствующих свойств или методов Visual Basic должен сначала удостовериться, что вызываемые элементы существуют. Поскольку Object (Объект) обобщенный тип переменной, который может включать все типы объектов. Visual Basic не знает, какой именно объект описывает объектная переменная во время разработки, и это не позволяет обнаружить синтаксические ошибки во время ввода программы. Например, если было неправильно набрано имя компонента-члена, Visual Basic не сможет обнаружить эту ошибку во время разработки приложения. Так, например, Excel поддерживает метод Evaluate, который позволяет вычислять
математические выражения. Если объявить переменную EXLApp как Object (Объект), а затем попытаться обратиться к ней, чтобы получить доступ к методу Calculate, Visual Basic не сможет определить наличие ошибки.
Если же объявить переменную EXLApp, как Excel Application, Visual Basic не только не будет захватывать никакие ссылки на несуществующие элементы, но также выведет список компонентов-членов в списке, как только будет поставлена точка после имени переменной EXLApp. Иными словами если объявлять переменные, правильно указывая их тип, то синтаксические ошибки будут определены еще на этапе ввода программы. При этом приложение не будет работать неправильно только лишь из за того, что в имени члена допущена орфографическая ошибка. Даже если опция Member AutoList выключена эти ошибки будут определены во время трансляции.
Другое, гораздо более серьезное, последствие правильного объявления типа объекта эффективность. Когда Visual Basic обнаруживает выражение, подобное EXLApp Property, он должен сначала удостовериться что указанное свойство существует, затем связаться с приложением сервером, предоставившим объект EXLApp, и активизировать его компонент Property. Компилятор вставит дополнительные операторы, которые организуют связь с приложением, предоставившим объектную переменную, чтобы удостовериться, что предоставляется запрошенный элемент. Неприятной особенностью является то, что эти операторы будут выполняться каждый раз, когда приложение запрашивает компонент объекта EXLApp. Чтобы избежать этой ненужной задержки, следует просто объявить объектную переменную EXLApp, указав соответствующий тип.
Объявление объектных переменных с указанием типа называется ранним связи ванием (early hounding), поскольку Visual Basic может связывать их с объектами, которые они представляют во время проектирования. Объявление объектных переменных без указания типа (просто переменные типа Object) приводит к позднему связыванию (late-bounding) Visual Basic не может связать их со специфическими объектами во время проектирования, что может привести к появлению любых ошибок уже во время выполнения.
Чтобы воспользоваться преимуществом раннего связывания объектных пере менных следует объявить их, указав соответствующий тип. Однако и применение позднего связывания имеет свои достоинства. Иногда тип объекта, описываемого переменной, заранее неизвестен и выход из такой ситуации заключается в объявлении переменной как Object. Например, требуется организовать программное переключение между объектами Form и Printer. Удобный способ организации вывода на любое из устройств (монитор или принтер) заключается в объявлении переменной OutputObject и последующей установки требуемого значения с помощью одного из операторов
Set OutputObject = Printer
Set OutputObject = Screen
Если вызвать метод Print переменной Output Object, то он будет применен к объекту, который был в последний раз присвоен к объектной переменной OutputObject. В ситуациях такого рода переменная OutputObject не может быть ранне связанной.
Доступ к объектам Excel с помощью объектных переменных
Переменная EXLObject является объектной переменной, которая предоставляет доступ к объектам Excel. Например, для обращения к текущей рабочей книге следует использовать выражение:
EXLObject.ActiveWorkbook
Чтобы обратиться к активному рабочему листу в активной книге, следует воспользоваться выражением:
EXLObject.ActiveWorkbook.ActiveSheet
Объекты, к которым обычно требуется получить доступ на рабочем листе это ячейки, которые могут быть представлены семейством ячеек Cells. Чтобы обратиться к первой ячейке второй строки и присвоить ей значение 99, следует воспользоваться следующим выражением:
EXLObject.ActiveWorkbook.ActiveSheet.Cells(2, 1).Value = 99
Свойства и методы, предоставляемые Excel для организации доступа к ячейкам и изменения их содержимого, рассматриваются далее в этой же главе. Следует учесть, что доступ к ним организуется через переменную, возвращаемую функцией Create0b)ect(). Функция Create0bject() так же, как и функция Get0bject(), возвращает ссылку на OLE-сервер. Эта переменная является шлюзом (gateway) к объектной модели (object model), предоставляемой приложением-сервером. Объектная модель представляет иерархию объектов, соответствующих объектам приложение-сервера (например, ячейки и макросы Excel или предложения и словари Word).
В оставшихся параграфах этой главы будут рассматриваться самые основные объекты Word 97, Excel 97 и Outlook 98 (его бета-версия, появившаяся перед выпуском Visual Basic 6). К моменту выхода этой книги, вероятно, станут доступны версии Word и Excel для Windows 98. Впрочем, приводимые примеры должны работать без изменений. Если у читателя возникнут проблемы, то обновленные версии файлов можно найти на сайте издательства Sybex.
Рассмотрение всех объектов, предоставляемых указанными приложениями, вероятно, потребовало бы трех отдельных книг. Поэтому знакомство с ними ограничивается только основными объектами, предоставляемыми приложениями; приводятся примеры, с которыми можно поэкспериментировать. Ознакомившись с этими объектами и используя справку Object Browser, которая содержит список объектов, предоставляемых каждым приложением, разработчик сможет разрабатывать приложения, которые используют услуги приложения-сервера OLE.
Microsoft Word предоставляет многочисленные объекты, которые можно использовать для программирования любых операций, которые могут быть выполнены с помощью команд меню. Например, можно открыть документ, подсчитать количество слов и символов, заменить в нем некоторые слова, и снова сохранить его на диске и все это без вмешательства пользователя. Все необходимые действия могут быть выполнены в фоновом режиме, без вывода окна Word на рабочий стол.
Объект верхнего уровня в Word это объект Application, который представляет собой текущий экземпляр приложения. Можно воспользоваться объектом Application, чтобы обратиться к некоторым общим свойствам окна Word, включая свойство Visible (с помощью которого приложение можно сделать невидимым) и к активным документам (чтобы переключиться на обработке одного из открытых документов).
Ниже в иерархии под объектом Application располагается семейство Documents, которое содержит объект Document для каждого открытого документа. Используя объектную переменную типа Document, можно обращаться к любому открытому документу (или открывать и создавать новые документы). Наиболее важный объект, который предоставляет каждый документ - это объект Range, представляющий собой непрерывную часть текста. Эта часть может быть словом, частью слова, символами или целым документом. Используя методы объекта Range, можно вставлять новый текст, форматировать, существующий текст (или удалять его), и так далее.
Чтобы адресовать специфические элементы текста, можно воспользоваться следующими семействами:
• семейством Paragraphs (Абзацы), состоящим из объектов типа Paragraph, которые представляют собой абзацы текста;
• семейством Words (Слова), состоящим из объектов типа Word, которые представляют собой слова;
• семейством Characters (Символы), состоящим из объектов типа Character, которые представляют собой отдельные символы.
Например, можно получить доступ ко всем абзацам документа с помощью семейства Paragraphs (Абзацы) объекта Document. Если применить тот же самый метод к текущему выделению (предоставленному объектом Selection), можно получить доступ ко всем абзацам в выделенном тексте. В следующем параграфе будут исследованы элементы базовых объектов, предоставляемых Word, чтобы продемонстрировать, как можно использовать их непосредственно в программе Visual Basic.
Первым в иерархии объектов приложения 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
Чтобы напечатать документ, следует вызвать метод 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, позволяющего программно контролировать процесс печати документа.
Базовым объектом для доступа к тексту в документах 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
Одна из наиболее полезных функции 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-приложения совсем несложно. Познакомившись с объектами этих приложений, можно установить с ними связь, управляя некоторыми свойствами и вызывая методы этих объектов.
Объекты, которые Excel предоставляет в распоряжение других приложений, имеют различные названия, но они формируют структурную иерархию для доступа к данным, хранящимся в виде таблиц. Точно так же, как и в Word, где базовой информационной единицей является сегмент текста (а не символы или слова), базовой информационной единицей в Excel является также объект типа Range. Объект такого типа может представлять собой и ячейку, и весь рабочий лист таблицы (или блок ячеек).
Объект Application представляет экземпляр Excel и поддерживает большинство основных свойств и методов объекта Application Word. Кроме того, он поддерживает еще несколько своих собственных методов. Два важных метода объекта Application Excel это метод Calculate, с помощью которого можно автоматически выполнить вычисления во всех открытых рабочих листах, и метод Evaluate, позволяющий вычислять математические выражения и возвращать их результат. Следующий оператор возвращает числовое значение, которое является результатом вычисления математического выражения, переданного методу Evaluate в качестве параметра:
Application.Evaluate "cos(3/1.091)* log(3.499)"
В выражениях можно также использовать переменные, значения которых хранятся в ячейках. Обращаются к ячейкам по их адресам. Следующий оператор возвращает логарифм числового значения, хранящегося в ячейке А1:
Application.Evaluate "log(" & Application.Range("А1") & ")"
Объект Range может представлять собой одну или несколько ячеек в зависимости от указанного диапазона адресов. В данном примере выполнялось обращение к одной ячейке (А1). В последующих двух параграфах будет рассмотрен метод доступа к блокам ячеек рабочего листа Excel.
Каждая рабочая книга в 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, занимающий левый верхний угол активного рабочего листа, следует воспользоваться выражением:
Worksheet.Range ("Al:J10")
Для обращения к одиночной ячейке объекта Range можно воспользоваться методом Cells:
Worksheet.Cells(row, col)
Параметры row и col координаты ячейки, заданные в числовом виде. Кроме того, существуют методы Rows и Columns, возвращающие целиком строку или столбец в соответствии с указанным номером. Следующие выражения возвращают третью строку и четвертый столбец как объекты типа Range:
Worksheet.Rows(3)
и
Worksheet.Columns("D")
Несмотря на то, что объект Range не является семейством, можно обратиться к отдельным ячейкам в объекте Range с помощью метода Cells. Для обращения требуется в методе Cells указать только один параметр, который является индексом ячейки в блоке. Индекс 1 соответствует левой верхней ячейке блока, индекс 2 соответствует второй ячейке первой строки и так продолжается до последней ячейки в первой строке. Следующий индекс соответствует первой ячейке второй строки, и таким образом нумерация продолжается до последней строки. При обращении к свойству Text содержимое ячейки всегда возвращается в виде строки, а при обращении к свойству Value содержимое ячейки возвращается в виде строки (если она содержит текст) или в виде числа (если ячейка содержит число).
Другой способ работы с ячейками состоит в выделении ячеек и обращении к свойствам и методам объекта Selection. Чтобы создавать объект Selection (который представляет собой выделенные ячейки), следует воспользоваться методом Select объекта Range:
Range ("A2 : D2"). Select
Этот оператор позволяет создать новый объект Selection, к которому можно обратиться по имени. Поскольку на рабочем листе может быть только один выделенный блок ячеек, метод не требует параметров. Чтобы изменить вид выделения, можно воспользоваться свойством Font (Шрифт):
Selection.Font.Bold = True
Selection.Font.Size = 13
Обратите внимание, что выделение всегда имеет вид прямоугольника. Выбрать на рабочем листе несмежные ячейки нельзя. Однако можно определить многоблочную область, содержащую несколько выделенных блоков. Следующие операторы выполняют объединение двух различных блоков с помощью метода Union и присваивают их содержимое новому объекту Range:
Set Titles = Worksheet.Range("Al :A10")
Set Totals = Worksheet.Range ("A100:A110")
Set CommonFontRange = Union(Titles, Totals)
Метод Union возвращает объект Range, который можно использовать для управления всеми ячейками сразу в блоках Titles и Totals. Например, можно применить общее форматирование ко всем ячейкам блока Range.
В следующем параграфе будет рассмотрено создание новой электронной таблицы из приложения Visual Basic, вставка формулы и печать итогового документа.
VB6 в действии: проект ExcelVBA
В приложении ExcelVBA предусмотрена кнопка Make New Sheet, с помощью которой демонстрируется обращение к рабочему листу, заполнение его данными и их форматирование (рис. 14.17). Программа начинается с установки объектной переменной AppExcel, позволяющей сослаться на приложение Excel.
Новая электронная таблица заполняется данными и форматируется подпрограммой MakeSheet(), текст которой приведен ниже. Для обращения к отдельным ячейкам и для записи в них значений используется семейство Cells. Для форматирования блока ячеек создается объект Range, содержащий ячейки, которые нужно отформатировать, выделяется блок ячеек, после чего работа с ячейками выполняется через объект Selection.
Рис. 14.17. В проекте ExcelVBA демонстрируется обращение к Excel непосредственно из VB-приложения
Программа 14.15. Подготовка новой электронной таблицы
Sub MakeSheet ()
Dim wSheet As Worksheet
Dim wBook As Workbook
Set wBook = AppExcel.Workbooks.Add
Set wSheet = AppExcel.Sheets (1)
wSheet.Cells (2, 1).Value = "1st Quarter"
wSheet.Cells (2, 2).Value = "2nd Quarter"
wSheet.Cells (2, 3).Value = "3rd Quarter"
wSheet.Cells (2, 4).Value = "-4th Quarter"
wSheet.Cells (2, 5).Value = "Year Total"
wSheet.Cells (3, 1).Value = 123.45
wSheet.Cells (3, 2).Value = 435.56
wSheet.Cells (3, 3).Value = 376.25
wSheet.Cells (3, 4).Value = 425.75
' Форматирование заголовков столбцов
Range ("A2:E2").Select
With Selection.Font
.Name = "Verdana"
. FontStyle = "Bold"
.Size = 12
End With
Range ("A2:E2") .Select
Selection.Columns.AutoFit
Selection.ColumnWidth = Selection.ColumnWidth * 1.25
Range ("A2:E2") .Select
With Selection
. Horizontal-Alignment - xlCenter
End With
' Форматирование чисел
Range ("A3 E3") Select
With Selection.Font
.Name "Verdana"
.FontStyle "Regular"
.Size 11
End With
wSheet Cells (3, 5) Value - "=Sum(A3.D3)"
MsgBox "The year total is " & wSheet Cells (3, 5) Value
'(Итог за прошедший год .)
End Sub
Во время заполнения и форматирования рабочего листа Excel работает в фоновом режиме. Пользователь не видит работу Excel, но может зафиксировать факт работы вращается диск, указатель мыши периодически принимает форму песочных часов и т. п. (рис. 14.18).
Рис. 14.18. Эта электронная таблица была создана приложением ExcelVBA с помощью автоматизации OLE
После того как таблица заполнена данными, программа выполняет чтение данных и отображает значения в виде двух строк в окне элемента управления TextBox формы Demo ExcelVBA. Для чтения данных используется другой метод. Следующий фрагмент программы позволяет в электронной таблице выделить блок ячеек, а затем за один прием перенести его в VB-приложение. Выбранные ячейки читаются в массив CData, причем, массиву присваивается имя объекта Selection:
AppExcel Range ("A2:ЕЗ").Select
Set CData AppExcel.Selection
С помощью этих двух операторов выполняется чтение значений ячеек в массив. Массив создается только на время работы. Поэтому нет потребности объявлять его отдельно. Затем можно непосредственно воспользоваться программой Visual Basic, чтобы просмотреть элементы массива и создать два столбца текста (см. рис. 14.17). Ниже приводится фрагмент программы, в котором выполняется чтение значений, содержащихся в ячейках таблицы.
Программа 14.16. Импортирование данных из Excel
AppExcel.Range ("A2:E3").Select
Set CData = AppExcel.Selection
For icol = 1 To 5
For irow = 1 To 2
Text1.Text = Text1.Text & Chr(9) & CData(irow, icol)
Next
Textl.Text = Textl.Text & vbCrLf
Next
В одном из предыдущих параграфов ("Проверка орфографии документов") рассматривался способ заимствования функций проверки орфографии " из 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, позволяющего реализовывать вычисление математических выражений.
Другой метод вычисления математических выражении с помощью Excel заключается в записи перед выражением знака равенства ("=") и присваивании выражения какой-либо ячейке. Excel выполнит вычисления и присвоит результат ячейке. После этого можно прочитать значение, хранящееся в этой ячейке, - это будет число, а не выражение, переданное ей.
wSheet.Cells(1, 1).Value = "=" & expression
wSheet.Calculate
result = wSheet.Cells (1, 1).Value
MsgBox "The value of the expression" & expression & _
vbCrLf & " is " & result
'(Значение выражения...)
Примечание
Использование Excel для вычисления простых выражений может показаться самоубийственным, но если считать, что Visual Basic не предоставляет для этого соответствующих инструментальных средств, то можно использовать Excel. Это вполне оправдано, особенно, если требуется вычислить значения сложных выражений или обработать большие наборы статистических данных. В гл. 20 "Объекты, используемые в сценариях" будет рассматриваться использование (для этих же целей) элемента управления Script. Но предоставляемый им набор функций не такой обширный, как в Excel.
Встраивание средств работы с электронной почтой (e-mail) непосредственно в офисные приложения в настоящее время становится весьма популярным. Чтобы приложение могло обрабатывать документы электронной почты, можно воспользоваться элементом управления MAPI или запрограммировать соответствующие объекты Outlook. В этом параграфе будет рассматриваться способ встраивания средств обработки сообщений электронной почты в VB-приложения, основанный на использовании языка Outlook VBA. Поскольку приложение Outlook достаточно простое и позволяет обрабатывать разнообразную информацию (а не только почтовые сообщения), кроме того, является весьма удобным в повседневной работе средством, оно используется во многих организациях для автоматизации широкого круга задач, например, задач планирования и рассылки сообщений. Поэтому имеет смысл изучить основы работы с объектами в нем. В то время как и Excel, и Word могут программироваться с помощью VBA, Outlook может программироваться только с помощью Visual BasicScnpt. Но для организации взаимодействия с Outlook можно воспользоваться и VBA.
Чтобы установить связь с Outlook и начать программировать предоставленные им объекты, сначала следует создать объектную переменную OLApp.
Dim OLApp As Outlook.Application
Set OLApp = Create0bject ("Outlook.Application")
В отличие от Word и Excel, Outlook 98 предоставляет доступ (с целью обработки содержащейся в них информации) не к единичным объектам, подобным документу Word или рабочему листу Excel Outlook 98 работает с несколькими объектами, включая почтовые сообщения, контакты и задачи. Наиболее вероятный кандидат на использование в качестве информационного модуля в Outlook - это папка. В зависимости от операции, которую требуется выполнять с помощью Outlook, сначала необходимо выбрать соответствующую папку в панели ярлыков. Например, чтобы просмотреть входящие сообщения электронной почты, следует выбрать папку InBox, а чтобы добавить контакт, следует сначала выбрать папку Contacts. Нельзя обнаружить информацию о контактах в папке InBox. Аналогично, нельзя обнаружить информацию об отложенных сообщениях в папке Calendar. Поскольку каждая операция в Outlook начинается с выбора соответствующей папки, то папки для данного приложения являются объектами верхнего уровня.
Чтобы обратиться к таким объектам, как папки, следует создать место для хранения MAPI сообщений. Память MAPI-сообщении это источник данных, который предоставляет все типы информации, хранимой в Outlook. Приложение Outlook является, на самом деле, интерфейсной частью базы данных, которая содержит разнотипную информацию. Чтобы обратиться к этой информации, необходимо сначала создать объектную переменную mNameSpace.
Set mNameSpace = OLApp GetNamespace("MAPI")
Приведем фрагмент программы, позволяющий организовать доступ к информации, сохраненной Outlook.
Dim OLApp As Outlook.Application
Dim mNameSpace As NameSpace
Set OLApp = Create0bject ("Outlook.Application")
Set mNameSpace = OLApp.GetNamespace("MAPI")
Используя переменную mNameSpace, можно обращаться к различным папкам Outlook. Для доступа к папке используется метод GetDefaultFolder, в который в качестве параметра передается имя папки. Метод возвращает объектную переменную, которая обеспечивает свойства и методы для доступа к объектам, хранящимся в папке.
К папкам, обслуживаемым Outlook, можно обращаться с помощью следующих констант (их имена очевидны):
olFolderContacts olFolderDeletedltems olFolderDrafts olFolderInBox olfolder Journal olFolderNotes olFolderOutBox olFolderSentMail olFolderTask
Чтобы получить информацию об объектах, хранящихся в папке Contacts (Контакты), можно воспользоваться следующим выражением:
Set AllContacts = _
mNameSpace.GetDefaultFolder(olFolderContacts).Items
После выполнения этого оператора свойство Items возвратит семейство объектов, хранящихся в папке.
Каждая папка содержит разнотипную информацию. Папка Contacts (Контакты) состоит из объектов Contactltem, папки InBox и OutBox содержат объекты MailIterm, папка Calendar (Календарь) содержит семейство объектов Appointmentltem. Каждый из этих объектов обладает большим количеством свойств, являющихся, в свою очередь, атрибутами самого объекта. Например, объект Contactltem обладает свойствами, установка значений которых влияет только на параметры контакта.
Чтобы просмотреть свойства объекта Contactltem, откройте Object Browser, выберите Outlook в окне Class (Класс), а в списке Classes (Классы) щелкните на элементе Contactltem (рис. 14.19). Члены выбранного класса появятся на правой панели. Чаще всего в приложениях используются следующие свойства: LastName, FirstName, Email1 Address, Title, и свойства, начинающиеся с HomeAddress и BusmessAddress. Это поля, которые можно заполнить в диалоговом окне Contact, добавляя или редактируя контакт в Outlook. Если требуются дополнительные поля, можно создать свои собственные. К этим свойствам также можно обращаться по именам полей, но такой способ здесь не рассматривается. Для получения более подробной информации следует обратиться к справочной системе Outlook.
Рис. 14.19. Свойства объекта Contactltem
Общим для всех объектов является свойство EntrylD (идентификатор объекта), являющееся значением типа Long. Значения EntrylD аналогичны значениям ID, которые присваиваются различным записям в базе данных (они идентифицируют запись и предназначены только для этого). Разумеется, нелепо требовать, чтобы пользователь выбирал контакт или сообщение по его EntrylD (более подходящими для этого представляются списки имен или компаний), но их можно использовать для создания закладок соответствующих записей. Если пользователь из Outlook заполняет узлы, перечисленные в окне элемента управления Tree View, сообщениями или контактами, он может воспользоваться полями EntrylD в качестве ключей для соответствующих узлов. Используя такой способ, пользователь может выбирать объекты, основываясь на более содержательной информации, например, имени абонента, названии компании или темы сообщения. Затем, используя значение ID, можно немедленно разыскать требуемый объект в соответствующей папке. В последующих" параграфах будут приведены примеры использования свойства EntrylD.
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