Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2 семестр / vba_2002

.pdf
Скачиваний:
82
Добавлен:
09.04.2015
Размер:
9.9 Mб
Скачать

Простой пример

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

1.Создает временное диалоговое окно UserForm в активной рабочей книге. Для этого используется метод Add коллекции VBComponents.

2.Добавляет элемент управления CommandButton в диалоговое окно UserForm. Для

этого применяется объект D e s i g n e r .

3.Добавляет процедуру обработки события в модуль кода диалогового окна UserForm. Данная процедура (CommandButtonl _ Click) используется для отображения окна сообщения и закрытия диалогового окна.

4.Отображает диалоговое окно UserForm.

5.Удаляет диалоговое окно UserForm.

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

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

Ниже приведен полный листинг процедуры MakeForm.

Листинг 28.6. Динамическое создание диалогового окнаUserForm

3ub MakeForm{)

Dim TempForm As Object 'VBComponent Dim NewButton As Msforms.CommandButton Dim Line As Integer

Dim TheForm

Application.VBE.MainWindow.Visible = False

1Создание диалогового окна UserForm

Set TempForm = ThisWorkbook.VBProject. _ VBComponents.Add(3) 'vbext_ct_MSForm

With TempForm

.Properties("Caption") = "Временная форма"

.Properties("Width") =2 00

.Properties("Height") = 100 End With

1Добавление элемента управления CommandButton Set NewButton = TempForm.Designer.Controls _

.Add("forms.CommandButton.1") With NewButton

.Caption = "Щелкни!"

.Left = 60

.Top = 4 0 End With

Часть VII. Другие темы

Добавление процедуры обработки события для CommandButton

With TempForm.CodeModule

 

Line = .CountOfLines

 

.InsertLines Line + 1,

"Sub CoiranandButtonl_Click()"

.InsertLines Line + 2,

"MsgBox ""Привет!"""

.InsertLines Line + 3,

"Unload Me"

.InsertLines Line + 4,

"End Sub"

End With

 

1Отображение диалогового окна UserForm VBA.UserForms.Add(TempForm.Name).Show

1Удаление диалогового окна UserForm ThisWorkbook.VBProject.VBComponents.Remove TempForm

End Sub

Эта процедура создает диалоговое окно, показанное на рис. 28.8.

Рис. 28.8. Такое диалоговое окно UserForm, а также связанный

снш( код, созданы динамически

спомощью кода VBA

Рабочая книга, которая содержит процедуру MakeForm, не требует создания ссылки на VBA Extensibility Library, так как переменная TempForm объявляется как имеющая универсальный тип object (а не объект VBComponent). Более того процедуранеиспользуетвстроенныеконстанты.

Обратите внимание на то, что первая инструкция процедуры скрывает окно VBE, уста навливая его свойство V i s i b l e в значение F a l s e . Это позволяет избежать мерцания экран; при генерациикода и диалогового окна.

Сложный пример

Данный пример имеет как образовательную, так и практическую ценность. Он состоит из функции G e t O p t i o n , которая отображает диалоговое окно UserForm. В этом диалоговом окне находится несколько элементов управления O p t i o n B u t t o n , подписи которых указываются в виде аргументов функции. Функция возвращает значение, которое соответствует элементу управления O p t i o n B u t t o n , выбранному пользователем. Полный исходный код функции приводится в листинге 28.7.

Листинг 28.7. Динамическая генерация диалогового окна с несколькими переключателями

Function GetOption(OpArray, Default, Title)

Dim TempForm As Object 'VBComponent

Dim NewOptionButton As Msforms.OptionButton

Dim NewCommandButtonl As Msforms.CommandButton

Dim NewCommandButton2 As Msforms.CommandButton

Dim i As Integer, TopPos As Integer

Dim MaxWidth As Long

Dim Code As String

'Скрытие окна VBE для избежания мерцания

Глава 28. Управление компонентами Visual Basic

Application.VBE.MainWindow.Visible = False

' Создание диалогового окна UserForm Set TempForm = _

ThisWorkbook.VBProject.VBComponents.Add{3) TempForm.Properties{"Width"} = 300

1Добавление элементов управления OptionButton TopPos = 4

MaxWidth = 0

For i = LBound(OpArray) To UBound(OpArray)

Set NewOptionButton = TempForm.Designer.Controls. _ Add("forms.OptionButton.1")

With NewOptionButton

.Width = 300

.Caption = OpArray(i)

.Height = 15 -Left = 8

.Top = TopPos

.Tag = i

.AutoSize = True

If Default =.i Then .Value = True

If .Width > MaxWidth Then MaxWidth = .Width End With

TopPos = TopPos + 15 Next i

'Добавление кнопки Отмена

Set NewCommandButton1 = TempForm.Designer.Controls. _ Add("forms.CommandButton.1")

With NewComnandButtonl

.Caption = "Отмена"

.Height о 18

.Width = 44

.Left = MaxWidth + 12

.Top = 6 End With

'Добавление кнопки OK

Set NewComraandButton2 = TempForm.Designer.Controls. _ Add("forms.CommandButton.1")

With NewCommandButton2

.Caption - "OK"

.Height = 18

.Width = 4 4

.Left = MaxWidth + 12

.Top = 28 End With

1Добавление процедур обработки событий для CommandButton

Code = ""

Code = Code & "Sub CommandButtonl_Click{)" & vbCrLf Code = Code & " GETOPTION_RET_VAL=False" & vbCrLf Code - Code & " Unload Me" & vbCrLf

Code = Code & "End Sub" & vbCrLf

Code m Code & "Sub CommandButton2_Click()" & vbCrLf Code = Code & " Dim ctl" & vbCrLf

Code = Code & • GETOPTION_RET_VAL = False" & vbCrLf

ЧастьVll.Другиетемы

691

Code = Code & " For Each ctl In Me.Controls" & vbCrLf

Code = Code & " If TypeNaitie(ctl) = ""OptionButton"" Then" & vbCrLf Code = Code & " If ctl Then GETOPTION_RET_VAL = ctl.Tag" & vbCrLf Code = Code & " End If" & vbCrLf

Code = Code & " Next ctl" & vbCrLf Code = Code & " Unload Me" £= vbCrLf Code = Code & "End Sub"

With TempForm.CodeModule

.InsertLines .CountOfLines + 1, Code

End With

'Изменение параметров диалогового окна With TempForm

.Properties{"Caption") = Title

.Properties ("Width") = NewConunandButtonl.Left + _

NewCommandButtonl.Width + 10

If .Properties{"Width") < 160 Then

.Properties("Width") = 160

NewCommandButtonl.Left = 106

NewCommandButton2.Left = 106

End If

.Properties("Height") = TopPos +24

End With

'Отображение диалогового окна VBA.UserForms.Add(TempForm.Name).Show

'Удаление диалогового окна

ThisWorlcbook.VBProject .VBComponents .Remove VBComponent: =TempForrn

'Передача выбранного параметра в вызывающую процедуру GetOption • GETOPTION_RET_VAL

End Function

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

Использование функции GetOption

Функция GetOption принимает три аргумента.

OpArray — строковый массив, содержащий названия элементов, которые будут отображены в диалоговом окне с помощью элементов управления OptionButton.

Default — целое число, которое указывает на элемент управления OptionButton, выбранный по умолчанию в момент отображения диалогового окна UserForm. Если этот параметримеетзначение0, то невыбран ни один изэлементовуправленияOptionButton.

Title — текст, который будет отображаться в строке заголовка созданного диалогового окнаUserForm.

Принцип действия функции GetOption

Функция GetOption выполняет следующие операции.

1.Скрывает окно VBE, что позволяет избежать мерцания экрана в момент генерации диалогового окна UserForm и добавления кода процедур обработки событий.

692

Глава 28. Управление компонентами Visual Basic

2.Создает диалоговое окно UserForm и назначает его переменной TempForm.

3. Затем в диалоговое окно добавляются элементы управления O p t i o n B u t t o n . Для этого используется массив, который передан в функцию с помощью аргумента ОрАггау. Свойство Tag элемента управления используется для сохранения индексного номера. Значение свойства Tag выбранного элемента управления возвращается функцией в качестве результата.

4.После этого функция добавляет два элемента управления CommandButton: кнопку ОК и кнопку Отмена.

5.Для каждого из элементов управления CommandButton создается процедура обработки события.

6.Проводятся завершающие действия по настройке диалогового окна UserForm: функция изменяет расположение кнопок CommandButton и размер диалогового окна UserForm.

7.Диалоговое окно UserForm отображается на экране. Когда пользователь щелкает на

кнопке ОК, выполняется процедура CommandButtonl _ Click . Она определяет, какой из элементов управления O p t i o n B u t t o n выделен, и присваивает соответствующее значение переменной GETOPTIQN_RET_VAL (эта переменная объявлена с областью действия P u b l i c ) .

8.Диалоговое окно UserForm закрывается и удаляется.

9.Функция возвращает значение переменной GETOPTI0N_RET_VAL в качестве результата.

Заметным преимуществом динамического создания диалогового окна UserForm является размещение функции в единственном модуле и отсутствие необходимости в создании ссылки на VBA Extensibility Library. Таким образом, полученный модуль можно просто экспортировать {модуль называется modOptionsForm). Затем вы вправе импортировать модуль в рабочую книгу и получить доступ к функции Getoption.

Следующая процедура демонстрирует использование функции G e t o p t i o n . В

этом слу-

ше диалоговое окно U s e r F o r m предоставляет пять вариантов выбора (которые содержат-

:я в массиве Ops).

 

Sub TestGetOption()

 

Dim Ops{1 To 5)

 

Dim UserOption

 

On Error Resume Next

 

Dim x

 

 

Set x = ActiveWorkbook.VBProject

 

If Err <> 0 Then

 

MsgBox "Настройки безопасности не позволяют выполнить _

 

 

макрос.", vbCritical

 

On Error GoTo 0

 

Exit Sub

 

End If

 

 

Ops(1)

= "Север"

 

Ops(2) = "Юг"

 

Ops(3)

= "Запад"

 

Ops(4)

= "Восток"

 

Ops(5)

- "Все регионы"

 

UserOption = GetOption(Ops, 5, "Выберите регион")

 

MsgBox

Ops(UserOption)

 

End Sub

 

 

ЧастьVII.Другиетемы

693

Переменная UserOption хранит индексный номер выбранного переключателя. Если пользователь щелкнет на кнопке Отмена, то переменная UserOption устанавливается в значение False.

На рис. 28.9 показано диалоговое окно UserForm, которое создается такой функцией.

Рис 28.9. Это диалоговое окно UserFonr. создано функцией GetOption

Диалоговое окно UserForm меняет собственный размер для того, чтобы подстроиться под заданное количество элементов управления, добавленных в диалоговое окно. Теоретически, функция Useroption может принимать массив любого размера. Однако необходимо ограничить количество элементов массива, так как размер диалогового окна UserForm не может превысить размер экрана.

Задачи, выполняемые функцией GetOption

Ниже приведены процедуры обработки события для элементов управления CommandButton. Этот код генерируется с помощью функции GetOption и размещается в модуле кода созданного диалогового окна UserForm.

Sub CommandButtonl_Click() GETOPTION_RET_VAL = False

Unload Me End Sub

Sub CommandButton2_ClickU

Dim ctl

GETOPTION_RET_VAL = False

For Each ctl In Me.Controls

If TypeName{ctl} = "OptionBu11on" Then

If ctl Then GETOPTION_RET._VAL = ctl. Tag

End If

Next ctl

Unload Me

End Sub

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

ThisWorkhook.VBProject.VBComponenfcs.Remove _ VBComponent j=TempForm

Резюме

Вэтой главе изложена вводная информация о работе в интегрированной среде разработки VBA. В ней приведены примеры использования кода VBA для добавления и удаления модулей, добавления кода VBA, а также отображения диалоговых окон UserForm.

Вследующей главе рассматривается еще одна сложная тема — модули классов.

Глава 28. Управление компонентами Visual Basic

Принципы управления модулями классов

Для

большинства профаммистов на VBA концепция мо-

 

дуля класса является неизведанной тайной. Модули

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

Что такое модуль класса

Модуль класса (class module) — это специальный тип мо1уля VBA, который можно добавить в проект. Проще говоря, •юдуль класса позволяет разработчику создать новый класс >бъектов. На этом этапе вы уже должны знать, что программирование Excel сводится к управлению объектами. Модуль oiacca позволяет создать новые объекты, а также соответстзуюшие свойства, методы и события.

Примеры из предыдущих глав этой книги демонстрируют использование модулей классов (см. главы 15, 18, 19 и 23).

У вас может возникнуть вопрос. "Нужно ли создавать новые объекты?". Ответ краток: нет. Однако как только вы поймете преимущества модулей классов, то можете рискнуть и попробовать. В большинстве случаев модуль класса служит достойной заменой функциям и процедурам, но можно найти для него и более серьезное применение. Иногда модуль класса является единственным способом получения необходимого результата.

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

Обработка событий, связанных со встроенными диаграммами. (Соответствующий пример представлен в главе 18).

Контроль над событиями уровня приложения. В число таких событий входит активизация рабочей книги. (Соответствующие примеры находятся в главах 19 н 23)

Перенастройка функций Windows API для упрощения их использования в исходном коде.

Например, можно создать класс, который упрощает определение или изменение состояния клавиш <NumLock> и <CapsLock>. Также можно создать класс, который упрощает доступ к системному реестру.

Выполнение одной процедуры несколькими объектами диалогового окна UserForm.

Обычно объект имеет собственную процедуру обработки события. Пример в главе J5 демонстрирует использование модуля класса, предназначенного для предоставления нескольким элементам управления CommandButton одной процедуры обработки события Click .

Создание компонентов, рассчитанных на повторное использование; их можно и.м- портировать в другие проекты. Как только будет создан модуль класса общего назначения, его можно импортировать в другие проекты для сокращения объема работ по разработке приложений.

Пример: создание класса NumLock

В данном разделе приводится пошаговая инструкция создания полезного, хотя и достаточно простого, модуля класса. Этот модуль класса создает класс NumLock, который имеет одно свойство: Value . Определение или установка значения клавиши <NumLock> требует использования нескольких функции Windows API. Такой модуль класса предназначен для упрощения операции управления клавишей <NumLock>. Вызовы функций API, а также необходимый код расположены в модуле класса (а не в обычном модуле кода VBA). В чем преимущества такого подхода? Работать с подобным кодом намного проще, а модуль класса можно использовать в других проектах.

Создав класс в коде VBA. определите текущее состояние клавиши <NumLock> с помо щью инструкции, отображающей значение свойства Value:

MsgBox NumLock.Value

Также в коде можно изменить состояние клавиши <NumLock>. Например, следующш оператор включает клавишу <NumLock>:

NumLock.Value = True

Важно понимать, что модуль класса содержит код, который определяет объект, включая его свойства и методы. В результате предоставляется возможность создания экземпляров этого класса в модуле кода VBA общего назначения, а также использования его свойств и методов. Для того чтобы лучше понять процесс создания модуля класса, воспользуйтесь инструкциями следующего раздела. Начнем с создания новой рабочей книги.

Вставка модуля класса

Запустите редактор VBE и

выберите Inserts Class Module (Вставкам Модуль класса).

Это приведет к добавлению пустого модуля класса, который называется C l a s s l . Если окно

Properties не отображено на экране, нажмите клавишу <F4>. После ото-

бражения окна Properties измените имя модуля класса на NumLock

(рис. 29.J).

 

Рис.29./.Пустоймодулькласса,которыйназываетсяNumLock

696

Глава 29. Принципы управления модулями классов

Добавление кода VBA

Далее необходимо создать код, обеспечивающий работоспособность свойства Value. Чтобы определить или изменить состояние клавиши <NumLock>, модуль класса должен включать объявления функций Windows API, которые используются для установки или получения состояния клавиши <NumLock>. Ниже приведен необходимый код.

Privat e Type KeyboardBytes

kbBytefO To 255) As Byte End Type

Dim kbArray As KeyboardBytes

Private Declare Function GetKeyState _

Lib "user32" (ByVal nVirtKey As Long) As Long

Private Declare Function GetKeyboardState _

Lib "user32" (kbArray As KeyboardBytes) Аз Long

Private Declare Function SetKeyboardState _

Lib "изегЗг" (kbArray As KeyboardBytes) As Long

Const VK_NUMLOCK = &H90

После этого создайте процедуру, которая будет получать текущее состояние клавиши <NumLock>. Она определяет свойств Value создаваемого объекта. В качестве имени свойства можно использовать любое название, V a l u e — неплохой вариант. Для того чтобы получить текущее состояние клавиши, вставьте в модуль следующую процедуру P r o p e r t y Get:

Property Get Value{) As Boolean

Value = GetKeyState(VK_NUMLOCK) And 1 = 1 Snd Property

Подробно код процедуры Property рассматривается далее в этой главе. Для получениянеобходимойинформацииобратитеськразделу"Программирование свойств".

Процедура, использующая функцию Windows API GetKeyState, определяет текущее состояние клавиши <NuinLock>. Эта процедура вызывается каждый раз, когда код VBA запрашивает значение свойства Value. Например, оператор VBA, который приведен ниже, приводит к выполнению процедуры P r o p e r t y Get:

MsgBox NumLock.Value

Теперь необходимо создать процедуру, которая будет устанавливать состояние клавиши <NumLock>. Клавиша может иметь одно из двух состояний: включена или выключена. Такая задача выполняется с помощью следующей процедуры P r o p e r t y Let:

Property Let Value(boolVal As Boolean) GetKeyboardState kbArray kbArray.kbByte(VK_NUMLQCK) = Abs(boolVal} SetKeyboardState kbArray

End Property

Процедура Propert y Let принимает один аргумент, который может иметь либо значение True, либо False . Оператор VBA, который приводится ниже, устанавливает значение Value объекта NumLock в значение TrueДля этого вызывается процедура Property Let:

NumLock.Value = True

ЧастьVII.Другиетемы

697

Использование класса NumLock

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

Dim NumLock As New NumLockClass

Обратите внимание на то, что тип объекта указан как NumLockClass (т.е. используется название модуля класса). Сама переменная может иметь любое название, но NumLock является наиболее приемлемым.

Представленная далее процедура устанавливает свойство Value объекта NumLock в значение True. Это приводит к включению клавиши <NumLock>.

Sub NumLockOn{)

Dim NumLock As New NumLockClass NumLock.Value = True

End Sub

Приведенная ниже процедура отображает окно сообщения, которое указывает на текущее состояние клавиши <NumLock> (True — если клавиша включена, и F a l s e в противном случае).

Sub GetNumLockState{)

Dim NumLock As New NumLockClass MsgBox NumLock.Value

End Sub

Наконец, последняя процедура переключает состояние клавиши <NumLock>.

Sub ToggleNumLock{)

Dim NumLock As New NumLockClass NumLock.Value = Not NumLock.Value

End Sub

Завершенный модуль класса этого примера находится на Web-узле издательст ва,. Рабочая книга также содержит модуль класса для определения и установи состояния клавиши <CapsLock>.

Еще о модулях классов

Пример в предыдущем разделе продемонстрировал методы создания нового объекта, обладающего свойством Value. Но объект может иметь любое количество свойств. Кроме того, объект поддерживает методы и события.

Именование класса объектов

Имя, которое: используется для модуля класса, является одновременно и именем определяемого класса. По умолчанию модули классов получают такие имена, как C l a s s l , C l a s s 2 и т.д. Модулю класса требуется более точное имя.

Программированиесвойств

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

698

Глава 29. Принципы управления модулями классов

Соседние файлы в папке 2 семестр