59899

Visual Basic 6. Руководство разработчика

Книга

Информатика, кибернетика и программирование

Основные элементы управления ctiveX. Усовершенствованные элементы Visul Bsic. Усовершенствованные элементы управления ctiveX. Дополнительные элементы управления ctiveX. Специальные темы. Конструирование элементов управления ctiveX Часть V Программирование баз данных на Visul Bsic.

Русский

2014-06-05

7.18 MB

137 чел.

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. Активные серверные страницы

Приложение. О прилагаемом компакт-диске

Предметный указатель

Содержание

Часть IV 

Расширение возможностей Visual Basic

Глава 13. API-функции Windows

Глава 14. Автоматизация OLE и VBA

Глава 15. Конструирование компонентов ActiveX

Глава 16. Конструирование элементов управления

Глава 13

API-функции Windows

• Доступ к 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" ("Использование элементов мультимедиа для расширения приложений") на компакт-диске.

Обращение к API-функциям из Visual Basic

Единственное отличие функций Visual Basic от API-функций заключается в том, что последние необходимо объявлять перед использованием. По сути, требуется сообщить Visual Basic имя и местоположение DLL-библиотеки, в которой находится требуемая API-функция, и указать типы и количество ее параметров. После этого ее можно использовать так же, как и функцию Visual Basic.

Объявление API-функций

Для объявления API-функций используется оператор Declare. Одним из способов является ввод имени функции с указанием ее параметров.

Declare Function mciSendString Lib "winmm.dll" _

Alias "mciSendStringA" (ByVal IpstrCommand As String_

ByVal IpstrReturnString As String, ByVal uReturnLenght_ As Long, ByVal hwndCallback As Long) As Long

Примечание

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

API-функция mciSendString() является частью библиотеки Winmm, расположенной в файле Winmm.dll в подпапке System папки Windows Суффикс А — это наследство, доставшееся от старых версий API, в которых сосуществовали 16- и 32-х разрядные функции. В Windows 95/98 необходимо использовать 32-разрядные функции.

Почти для всех API-функций необходимо передавать параметры по значению. Только те параметры, которые изменяются самой функцией, необходимо передавать по ссылке. По умолчанию, Visual Basic передает аргументы по ссылке, поэтому для передачи аргументов по значению необходимо использовать ключевое слово ByVal.

Использование приложения API Viewer

Предполагается, что пользователю нет необходимости запоминать параметры каждой функции и даже их имена - он может обратиться к справочной системе. Получить доступ к ней можно непосредственно из IDE-среды — окно API Viewer приведено на рис. 13.1.

Используя это приложение, можно вставить в VB-программу любую функцию. Для этого необходимо выполнить следующие действия.

1. Выберите команду API-Viewer в меню Add-Ins. Если в меню Add-Ins (Надстройки) нет пункта API Viewer, необходимо открыть диалоговое окно Add-Ins Manager (Диспетчер надстроек) и выполнить правый щелчок на элементе Visual Basic 6 API Viewer, чтобы добавить данный пункт в меню Add-Ins.

Рис 13.1. Окно приложения API Viewer

2. В диалоговом окне API Viewer в меню File (Файл) выберите команду Load Text File (Загрузить текстовый файл) или Load Database File (Загрузить файл базы данных) Загрузка файла базы данных выполняется быстрее, но лишь в том случае если при этом не происходит преобразование текстового файла в файл базы данных

3. В окне списка Available Items (Доступные объекты) выберите требуемую функцию и щелкните на кнопке Add (Добавить). API-Viewer отобразит выбранную функцию (функции) в окне списка Selected Items (Выделенные объекты)

4. Выберите функции, которые необходимо вставить в прикладную программу, а затем щелкните на кнопке Сору (Копировать) для копирования объявления функций в Clipboard (Буфер обмена)

5. Откройте окно Code (Исходный код) вашего приложения и вставьте объявления функций

Совет

Пакет Win32 Software Development Kit содержит полное описание каждой функции, включая все структуры и сообщения. Microsoft Developer Network (MSDN) предоставляет все необходимое для разработки Windows-приложений. Для получения подробной информации о MSDN посетите сайт

http.//www.microsoft.com/msdn.

Большинство API-функций требует большого числа параметров, причем некоторые из них имеют сложный тип. Типы параметров API функции пере числены ниже.

Параметры 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), так как они указывают на область памяти, в которой хранится значение переменной.

Объявление 32-разрядных функций и структур

В некоторых API-функциях в качестве параметров используются структуры. В приложении MousePos (папка MousePos данной главы на компакт-диске) приводится пример объявления и использования простой структуры. В этом приложении для получения информации о положении мыши в момент выполнения щелчка используется функция GetCursorPosQ. Эта функция должна возвратить вызвавшей ее программе два значения: координаты Х и Y мыши. Эти значения хранятся в структуре POINTAPI, которая состоит из двух элементов - Х и Y. Доступ к ним можно получить из программы с помощью выражений PointAPl.X и PointAPl.Y.

Чтобы создать проект MousePos, выполните следующие действия:

1. Откройте окно API Viewer, выбрав команду API Viewer в меню Add-Ins.

2. В открывшемся окне в меню File (Файл) выберите команду Load Text File (Загрузить текстовый файл).

3. Выберите файл Win32api.txt и выполните двойной щелчок на элементе GetCursorPos в списке Available Items (Доступные объекты).

4. В окне списка Selected Items (Выделенные объекты) появится следующее объявление:

Declare Function GetCursorPos Lib "user32" _

Alias "GetCursorPos" (IpPoint As POINTAPI) As Long

Параметр, необходимый для вызова функции - это структура данных, называемая POINTAPI. Она хранит координаты точки экрана. Чтобы найти определение структуры данных POINTAPI с помощью API Viewer выполните следующие действия:

5. В раскрывающемся списке API Type (API-типы) выберите Types (Типы). Список Available Items (Доступные объекты) будет содержать названия всех структур данных, используемых API-функциями.

6. Найдите структуру данных POINTAPI и выполните двойной щелчок на ее названии. В окне списка Selected Items (Выделенные объекты) появится ее определение.

Type POINTAPI

х As Long

у As Long

End Type

7. Щелкните на кнопке Сору, чтобы скопировать это определение в буфер обмена (вместе с объявлением функции GetCursorPos()).

Совет

Объявления функций можно помещать в любом месте, но обычно их помещают в Module (Модуль): тогда другие процедуры смогут получить к ним доступ.

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

Для работы с различными элементами управления можно использовать метод 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

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()

Функция 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(). С помощью этой функции можно выполнять масштабирование (сжимать или растягивать) растровых изображений в процессе копирования. Функция 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.

Глава 14 Автоматизация OLE и VBA

• Расширение возможностей 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?

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

С появлением 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 делает доступными объекты различных типов (или классов). 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 Container

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

Элемент управления OLE Container — это доступ к различным объектам операционной системы, которые Visual Basic не в состоянии использовать самостоятельно (например, документы Word, звуковые файлы, растровые изображения или электронные таблицы Excel). Элемент управления OLE Container может содержать любой из объектов, перечисленных в диалоговом окне Insert Object (Вставка объекта), и сделать вашу программу на Visual Basic приложением-контейнером. Преимуществом использования OLE Container является то, что он скрывает сложности, связанные с применение OLE. Встраивать объекты в OLE Container можно как при разработке приложения, так и при выполнении.

Встраивание и связывание объектов во время разработки

В этом параграфе рассмотрено создание простого элемента управления 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

Существует еще один способ внедрения объектов в элемент управления 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-приложению.

Общие свойства элемента управления OLE Container

В этом параграфе рассмотрены свойства и методы, которые используются при работе с документами, встраиваемыми или связываемыми во время выполнения программы. Эти свойства можно установить в среде Visual Basic при разработке приложения методами, описанными ранее.

Class

Это свойство определяет тип объекта, хранящегося в элементе OLE Container. Если запустить приложение OLERTime, то, выбирая объекты различных типов, зарегистрированных в системе, и щелкая затем на кнопке Object Info, можно посмотреть значения свойства Class.

DispIayType

Это свойство указывает, отображается объект с содержимым (значение свойства 0) или только значок OLE-сервера (1).

 vbOLEDisplayContent (0) — отобразить объект с содержимым;

 vbOLEDisplayIcon (1) — отобразить объект в виде значка.

OLETypeAllowed

Значение этого свойства обуславливает тип создаваемого объекта:

• 0 — связанный;

•  1 — встроенный;

• 2 — любой.

Тип объекта определяется в диалоговом окне Insert Object. Соответствующие константы приведены ниже:

 vbOLELinked (0) - объект можно связать;

 vbOLEEmbedded (1) — объект можно встроить;

 vbOLEEither (2) — объект можно связать или встроить.

OLEDropAllowed

Если значение этого свойства - True, то во время выполнения приложения можно поместить объект в элемент управления OLE Container, перетаскивая его

мышью. К аналогичным результатам приводит копирование объекта в буфер обмена и последующий вызов приложением метода Paste Special для элемента OLE Container.

SizeMode

Значение этого свойства определяет, как будет отображаться объект — в виде значка или реального документа в окне элемента управления OLE Container. Свойство может принимать следующие значения.

 vbOLESizeClip (0). Это значение установлено по умолчанию. Размеры изображения объекта равны размерам исходного документа. Если размеры объекта больше, чем размеры окна элемента управления OLE Container, то часть изображения отсекается.

 vbOLESizeStretch (1). Размер изображения объекта изменяется так, чтобы заполнить все окно элемента управления OLE Container. При этом первоначальные пропорции объекта могут измениться.

 vbOLESizeAutosize (2). Размеры окна элемента управления OLE Container изменяются таким образом, чтобы отобразить весь объект

 vbOLESizeZoom (3). Размеры объекта изменяются так, чтобы объект занял как можно большую часть окна элемента управления OLE Container, а изображение при этом не исказилось.

SourceDoc

При связывании объекта значение этого свойства определяет файл-источник. Когда вы внедряете объект, это свойство определяет, какой файл будет использован в качестве шаблона.

Sourceltem

Этим свойством обладают только связанные объекты. Его значение определяет связываемые данные, находящиеся внутри файла. Например, если выполняется связывание с блоком ячеек рабочего листа Excel, то значение свойства Sourceltem - это диапазон ячеек, которые будут связаны.

OLEType

При выполнении программы это свойство доступно только для чтения. Оно возвращает статус объекта: 0 — для связанных объектов, 1 — для встроенных объектов, и 2 —объект не был вставлен. Соответствующие константы приведены ниже.

 vbOLELinked (0). Объект связывается с элементом управления OLE.

 vbOLEEmbedded (1). Объект встраивается в элемент управления OLE.

 vbOLENone (2). Элемент управления OLE Container не содержит объектов.

AutoActivate

Значение этого свойства определяет, будет содержимое элемента управления OLE Container активизировано двойным щелчком или перемещением фокуса в его окно Свойство AutoActivate может принимать следующие значения.

 vbOLEActivaleManual (0). Объект не активизируется автоматически. Для его активизации необходимо использовать метод DoVerb.

 vbOLEActivateGetFocus (1). Объект активизируется для редактирования при каждом попадании фокуса в окно элемента управления OLE Container.

 vbOLEActivateDoubleclick (2). Значение по умолчанию. Объект в окне элемента управления OLE Container активизируется при выполнении на нем двойного щелчка.

 vbOLEActivateAuto (3). Объект активизируется, когда элемент управления получает фокус либо на объекте выполняется двойной щелчок.

Общие методы элемента управления OLE Container

Чтобы управлять встроенными или связанными объектами, в элементе управления OLE Container, в дополнение к уже упомянутым, предусмотрены следующие методы.

CreateEmbed

С помощью этого метода создается встроенный объект. Синтаксис метода имеет вид:

CreateEmbed sourcedoc, class

Параметр sourcedoc имя файла документа, используемого в качестве шаблона для встроенного объекта. Чтобы создать новый встроенный документ, в качестве параметра sourcedoc указывается строка нулевой длины ("").

Параметр class — необязательный параметр, определяющий имя класса встроенного объекта. Этот параметр требуется только в том случае, если параметр sourcedoc опущен. Чтобы найти зарегистрированные классы, выберите свойство Class (Класс) в окне Properties (Свойства) элемента управления OLE Container и щелкните на кнопке с многоточием.

CreateLink

Этот метод позволяет создать связанный объект из содержимого файла. Синтаксис метода CreateLink:

CreateLink sourcedoc, sourceitem

Параметр sourcedoc это файл, из которого будет создан объект, а параметр sourceitem — данные внутри файла, которые должны быть в связанном объекте. Например, чтобы связать содержимое элемента управления OLE Container с блоком ячеек рабочего листа Excel, следует задать файл с помощью параметра sourcedoc, a диапазон связанных ячеек - с помощью параметра sourceitem. Параметр sourceitem может указывать на одиночную ячейку (например, R10C12) или на блок ячеек (например, R1C1:R10C20). Можно также задать именованный блок.

После того как связанный документ создан, значение свойства Sourceitem устанавливается в строку нулевой длины, а его первоначальное значение присоединяется к свойству SourceDoc. Например:

"c:\data\revenus\revl997.xls|RCl:R20C25 "

Самый простой способ определения синтаксиса этих двух команд - это выбрать связываемый объект, а затем при проектировании вставить его с помощью команды Paste Special в элемент управления OLE Container. После того как объект будет связан, просмотрите значение свойства SourceDoc и используйте его в собственной программе.

DoVerb verb

Метод DoVerb выполняет команды (являющиеся глаголами, например, Edit, Play и т. п.). Объекту известно, как выполнять заданное действие. Синтаксис метода:

DoVerb verb

Значения необязательного параметра verb перечислены в табл. 14.3.

Таблица 14.3. Значения параметра verb

Константа

Значение

Описание

VbOLEPrimary

0

Действие для объекта, заданное по умолчанию

vbOLEShow

-1

Открывает объект для редактирования.

Активизирует приложение, создавшее документ, в окне OLE Container

VbOLEOpen

-2

Открывает объект для редактирования

Активизирует приложение, создавшее документ, в отдельном окне

vbOLEHide

-3

Для встроенных объектов позволяет скрыть приложение, создавшее объект

vbOLEUIActivate

-4

Активизирует объект для оперативного редактирования и позволяет отобразить любые инструментальные средства пользовательского интерфейса. Если объект не поддерживает оперативное редактирование, то появляется сообщение об ошибке

VbOLEInPlaceActivate

-5

Когда пользователь перемещает фокус в окно элемента управления OLE Container, то с помощью этой операции можно создать окно для объекта и подготовить объект, который нужно отредактировать

vbOLEDiscardUndoState

-6

Когда объект активизирован для редактирования, этот метод позволяет отбросить все изменения, которые приложение, создавшее объект, может отменить

InsertObjDIg

Этот метод позволяет отобразить диалоговое окно Insert Object (Вставка объекта). Установки пользователя, выполненные в этом окне, передаются приложению с помощью значений свойств элемента управления OLE Container.

PasteSpecialDIg

Этот метод позволяет отобразить диалоговое окно Paste Special (Специальная вставка). Установки пользователя, выполненные в этом окне, передаются приложению с помощью значений свойств элемента управления OLE Container.

Object Browser позволяет выяснить, какие встроенные константы используются в различных методах и свойствах элемента управления OLE Container.

1. Выберите команду Object Browser (Просмотр объекта) в меню View (Вид).

2. Выберите библиотеку объектов Visual Basic, а в нем объект Constant, чтобы отобразить названия констант в списке Method/Properties (Метод/Свойства).

Если немного поэкспериментировать с методами OLE и элементом управления OLE Container, то можно сделать вывод: в пограничных ситуациях OLE далека от совершенства. У пользователя нет возможности полностью контролировать внешний вид встроенного или связанного объекта, а иногда и панель приложения-сервера остается невидимой. Несмотря на то, что работа над OLE идет уже несколько лет, нельзя считать ее завершенной.

Существует не так уж много созданных в Visual Basic приложений, которые выполняют связывание и встраивание документов, предоставленных приложениями-серверами. Однако другой аспект OLE — OLE-автоматизация — вполне совершенна и является наиболее мощным средством основных Windows-приложений, например, Microsoft Office. Автоматизация OLE рассматривается во второй части главы, а сейчас мы кратко рассмотрим операции перетащить-и-опустить, применяемые в OLE.

Использование операций перетащить-и-опустить в OLE

В гл. 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

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

Чтобы получить доступ к возможностям, предоставляемым приложением-сервером 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.

Взаимодействие с Word

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.

Семейство Documents u объект Document

Первым в иерархии объектов приложения Word является объект Document, представляющий любой документ, который можно открыть в Word, или иной документ, который можно отобразить в окне Word. Все открытые документы принадлежат семейству Documents (Документы), которое состоит из объектов Document. Подобно всем другим семействам, это семейство поддерживает свойство Count (Число открытых документов), метод Add (Добавить), с помощью которого можно добавить новый документ, и метод Remove (Удалить), который позволяет закрыть существующий документ. Чтобы обратиться к уже открытому документу, можно воспользоваться методом Item (Элемент) из семейства Documents (Документы), определив индекс документа следующим образом:

Application.Documents.Item(1)

Аналогичным образом можно определить имя документа:

Application.Documents.Item ("MasteringVB.doc")

Поскольку Item — это заданное по умолчанию свойство, то можно полностью опустить его имя:

Application.Documents(I)

Чтобы открыть существующий документ, можно воспользоваться методом Open (Открыть) семейства Documents (Документы):

Documents.Open(fileName)

Параметр fileName это путь и имя файла документа.

Для создания нового документа, следует воспользоваться методом Add семейства Documents (Документы), который принимает два необязательных параметра:

Documents.Add(template, newTemplate)

Параметр template определяет имя файла шаблона, который нужно использовать в качестве основы для нового документа. Параметр newTemplate является значением типа Boolean. Если он имеет значение True, Word создаст новый файл шаблона.

Большинство выполняемых операций воздействуют на активный документ (документ в активном окне Word), который представляется объектом ActiveDocument, являющийся свойством объекта Application. Чтобы обращаться к выделенному тексту в активном документе, следует воспользоваться следующим выражением:

Application ActiveDocument.Selection

Можно сделать активным любой документ, вызвав метод Activate (Активизировать) объекта Document. Чтобы сделать документ My Notes doc активным, можно воспользоваться следующим оператором:

Documents ("MyNotes doc"). Activate

После выполнения этого оператора документ MyNotes doc становится активным, и программа может обращаться к нему по имени Application ActiveDocument

Печать и сохранение документов

Чтобы напечатать документ, следует вызвать метод 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

Объекты, которые 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.

Семейство Worksheets и объект Worksheet

Каждая рабочая книга в Excel может содержать один или несколько рабочих листов. Коллекция Worksheets, подобная коллекции Documents в Word, содержит объект Worksheet для каждого рабочего листа в текущей рабочей книге. Чтобы добавить новый рабочий лист, следует воспользоваться методом Add:

Application.Worksheets.Add(before, after, count, type)

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

xlWorksheet. Значение, установленное по умолчанию.

xIExcel4MacroSheet. Рабочий лист, содержащий макросы Excel 4.

xlExcel4lntlMacroSheet. Рабочий лист, содержащий международные макросы Excel 4. Чтобы обратиться к рабочему листу, следует воспользоваться методом Item коллекции Worksheets, передавая в качестве параметра индекс или имя рабочего листа. Если второй рабочий лист называется SalesData.xIs, то следующие выражения эквивалентны:

Application.Worksheets.Item(2)

и

Application.Worksheets.Item ("Sales Data.xls")

Поскольку Item — это установленное по умолчанию свойство коллекции, имя его можно полностью опустить:

Application.Worksheets (2)

Объекты, предоставляющие доступ к ячейкам

Excel - это приложение, которое предназначено для обработки информации хранящейся в ячейках. Но основным объектом, используемым для организации доступа к содержимому рабочего листа, является объект Range, являющийся свойством объекта Worksheet. Имеются несколько способов идентификации объекта Range, но ниже приведено каноническое его описание:

Worksheet.Range(celll:се112)

Где cell1 и сеll2 —адреса двух ячеек, которые определяют прямоугольную область на рабочем листе. Это адреса левой верхней и правой нижней ячеек блока. В этом параграфе будет использована стандартная нотация Excel, в которой число определяет строку, а буква - столбец, например, СЗ или А103. Чтобы выбрать блок ячеек размером 10 х 10, занимающий левый верхний угол активного рабочего листа, следует воспользоваться выражением:

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

Использование Excel для вычисления математических выражений

В одном из предыдущих параграфов ("Проверка орфографии документов") рассматривался способ заимствования функций проверки орфографии " из Word. Теперь нечто подобное будет проделано с Excel. Excel — превосходное средство для выполнения математических операций. В то же время Visual Basic не содержит функций и методов, позволяющих выполнять вычисления математических выражений (заданных в виде строки — прим. ред.). Если Excel установлен на хост-компьютере, можно обратиться к нему непосредственно из приложения Visual Basic и использовать его для вычисления сложного математического выражения.

Самый простой способ вычисления математического выражения заключается в вызове метода Evaluate объекта Excel.Application. Пусть имеется инициализированная объектная переменная ExcelApp, тогда можно, например, вычислить математическое выражение:

1/cos(0.335) * cos(12.45)

Для этого следует вызвать метод Evaluate объекта ExcelApp и передать ему это выражение в виде параметра (строки):

у = ExcelApp.Evaluate "1/cos(0.335) * cos(12.45)"

Именно это происходит при выполнении щелчка на кнопке Calculate Expression (Вычислить выражение) в форме ExcelVBA. Ниже приводится текст программы обработчика команды Calculate Expression.

Программа 14.17. Команда Calculate Expression

Private Sub bttnCalculate_Click()

Dim wSheet As Worksheet

Dim wBook As Workbook

Dim expression

StartExcel

expression = InputBox ("Enter math expression to evaluate _

i.e., 1/cos(3.45) * log (19.004)")

'(Введите вычисляемое выражение, например...)

On Error GoTo CalcError

If Trim(expression) <> "" Then

MsgBox AppExcel.Evaluate(expression)

End If

GoTo Terminate

Exit Sub

CalcError:

MsgBox "Excel returned the following error" & vbCrLf & _

Err.Description

' (Excel возвратил сообщение об ошибке...)

Terminate:

AppExcel.Quit

Set AppExcel = Nothing

End Sub

Программа предлагает пользователю ввести любое математическое выражение. Организовать вычисление произвольных математических выражений, используя программные средства Visual Basic затруднительно. В гл. 20 "Объекты, используемые в сценариях" будет рассматриваться использование элемента управления Script, позволяющего реализовывать вычисление математических выражений.

Другой метод вычисления математических выражении с помощью 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.

Взаимодействие с Outlook 98

Встраивание средств работы с электронной почтой (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 выполняется поиск информации о контактах объекта в папке