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

2 семестр / vba_2002

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

Последовательность событий может быть сложнее, чем кажется. Перечисленные выше события происходят на уровне объекта Application. При добавлении нового листа возникают и дополнительные события {на уровне объектов Workbook и Worksheet).

Следует помнить, что события возникают в определенной последовательности. Знание порядка этой последовательности может оказаться очень важным при создании процедур обработки событий. Далее в этой главе будет рассматриваться порядок событий, возникающих при определенных действиях (за дополнительной информацией обратитесь к разделу "Отслеживание событий уровня объекта Application") .

Размещение процедур обработкисобытий

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

В окне редактора VBE все проекты перечислены в окне Projects. Компоненты проектов расположены в списке, показанном на рис. 19.1.

Все приведённые ниже компоненты имеют собственный модуль кода:

объект Лист (например, Лист1, Лист2 и т.д.);

объект Диаграмма (т.е. листы диаграмм);

объект 3TaKHwra(ThisWorkbook);

модули VBA общего назначения: процедуру обработки события никогда нельзя размещать в модуле общего назначения (необъектном модуле);

модули классов.

Даже если процедуры обработки событий располагаются в мо-

 

дулях объектов, они могут вызывать процедуры в модулях общего

 

назначения для выполнения определенных задач. Например, сле-

 

дующая процедура обработки события, расположенная в модуле

 

объекта ЭтаКнига, вызывает процедуру WorkbookSetup, кото-

риСш jgjt Компоненты ка-

рая может храниться в модуле кода VBA общего назначения.

 

ждаго проекта VBA пере-

Private sub Workbook_open ()

числены в окне Projects

Call WorkbookSetup

 

 

End Sub

 

 

Отключение событий

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

Application.EnableEvencs = False

Для разрешения возникновения событий воспользуйтесь оператором Appli cat ion.EnableEven с s = True

Итак, зачем же отключать события? Основная причина заключается в необходимости предотвратить бесконечный цикл возникающих событий.

Часть V. Совершенные методы программирования

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

Например, ячейка Al на рабочем листе всегда должна содержать значение, которое меньше или равно 12. Можно написать процедуру, которая будет выполняться при каждом изменении данных в ячейке, что позволит проверять действительность содержимого этой ячейки. В данном случае контролируется событие Change объекта Worksheet, для чего используется процедура, которая называется Worksheet_Change. Процедура проверяет введенные пользователем данные, и если значение больше 12, то отображается окно сообщения, а содержимое ячейки очищается. Проблема заключается в том, что очистка содержимого ячейки с помощью кода VBA провоцирует возникновение еще одного события Change, что приводит к повторному вызову процедуры обработки события. Так как подобный результат нежелателен, перед очисткой содержимого ячейки необходимо отключить механизм возникновения событий. После выполнения операции включите механизм поддержки событий, чтобы иметь возможность контролировать следующую попытку пользователя ввести правильное значение в ячейку.

Еще одним способом предотвращения бесконечного цикла возникающих событий является декларирование статической булевой переменной ( S t a t i c Boolean) в начале процедуры обработки события. Воспользуйтесь следующим выражением:

S t a t i c AbortProc As Boolean

Программирование событий в старых версиях Excel

Программы Excel до версии 97 также поддерживают события, но методы программирования процедур обработки отличаются от описанных в этой главе,

Например, если вы соэдали процедуру Auto_open, которая хранится в модуле VBA общего назначения, то эта процедура будет запускаться при каждом открытии рабочей книги. Начиная с Excel 97, процедура Auto_Open дополняется обработчиком события Workbook_open, который хранится в модуле кода для обьекта Этакнига. Такой обработчик выполняется перед вызовом процедуры Auto_open.

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

Sheets ("Лист1") .OnEntry = "ValidciteEntry"

Этот оператор сообщает Excel, что следует запускать процедуру ValidateEntry каждый раз, когда данные вводятся в ячейку. В Excel 97 и более поздних версиях достаточно создать процедуру, которая называется Worksheet_change и сохранить ее в модуле кода для объекта Лист1.

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

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

If

AbortProc

Then

 

AbortProc

= False

 

Exit Sub

 

End

if

 

500

Глава 19. Концепция событий Excel

Если происходит повторный вызов процедуры обработки события, то значение T r u e переменной A b o r t P r o c сообщает приложению о необходимости завершения этого вызова. Кроме того, значение переменной A b o r t P r o c устанавливается в значение F a l s e .

В качестве практического примера макроса проверки правильности введенных данных можно рассмотреть процедуру, приведенную в разделе "Проверка правильности введенных данных" далее в этой главе.

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

Ввод кода процедуры обработки события

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

Worksheet_SelееtionChange Workbook_Open Chart_Activate

Class_Initialize

Можно объявить процедуру обработки события вручную, но целесообразнее возложить эту задачу на редактор VBE.

На рис. 19.2 показан модуль кода объекта ЭтаКнига. Для того чтобы добавить объявление процедуры, выберите объект Workbook из списка объектов слева. Затем выберите событие из списка процедур справа. После этого будет создана "оболочка" процедуры, которая состоит из строки декларации и оператора End Sub.

Рис. 19.2. Лучшим способом создания процедуры обработки событияявляетсяиспользованиевстроенныхсредствVBE

Haiiptrivfер, если выбрать из списка объектов — Workbook, а из списка процедур — Open, то редактор VBE вставит приведенную ниже (пустую) процедуру;

P r i v a t e Sub VJorkbook_Open {)

End Sub

Создаваемый код должен помещаться между этими двумя строками.

Часть V. Совершенные методы программирования

501

Процедуры обработки событий, которые используют аргументы

Некоторые процедуры обработки событий используют набор аргументов. Например, может возникнуть необходимость в создании процедуры для обработки события S h e e t A c t i v a t e рабочей книги. Если воспользоваться методикой, описанной в предыдущем разделе, то редактор VBE создаст представленную далее процедуру:

Private Sub Workbook_SheetActivate(ByVal Sh As Object)

End Sub

Эта процедура использует один аргумент (Sh), который представляет активизированный лист. В данном случае переменная Sh имеет тип O b j e c t , а не просто тип Worksheet. Это связано с тем, что активизированный лист может оказаться листом диаграммы.

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

Private Sub Workbook_SheetActivate(ByVal Sh As Object) MsgBox TypeName(Sh) & vbCrLf & Sh.Name

End Sub

Некоторые процедуры обработки событий используют аргумент C a n c e l с типом данных Boolean. Например, объявление процедуры обработки события B e f o r e P r i n t рабочей книги будет выглядеть следующим образом:

Private Sub Workbook_BeforePrint(Cancel As Boolean)

Значение аргумента C a n c e l , которое передается в процедуру, равно F a l s e . Но код может установить это значение равным True, что приведет к отмене печати. Следующий пример демонстрирует такую операцию.

Private Sub Workbook_BeforePrint(Cancel As Boolean) Msg = "Вы загрузили необходимую бумагу?"

Ans = MsgBox{Msg, vbYesNo, "В процессе печати...") If Ans = vbNo Then Cancel = True

End Sub

Процедура W o r k b o o k _ B e f o r e P r i n t выполняется перед тем, как печатается рабочая книга. Эта процедура отображает окно сообщения, которое показано на рис. 19.3. Если пользователь щелкнет на кнопке Нет, то аргумент C a n c e l будет иметь значение True, и ничего напечатано не будет.

Событие BeforePrint возникает и перед предварительным просмотром рабочей книги.

Рис.19.3.Можноотменитьоперацию печати, изменив значение аргумента Cancel

502

Глава 19. КонцепциясобытийExcel

К сожалению, Excel не обрабатывает событие Bef orePrint на уровне листа. Таким образом, код не может определить, какая часть рабочей книги будет распечатана.

События объекта Workbook

События объекта Workbook происходят в пределах определенной рабочей книги. В табл. 19.1 перечислены события рабочей книги, а также приведено краткое описание каждого из них. Процедуры обработки событий объекта Workbook хранятся в модуле кода объекта ThisWorkbook (ЭтаКнига).

Таблица 19.1. СобытияобъектаWorkbook

Событие

Действие, которое приводит к возникновению этого события

Activate

Актиаизация рабочей книги

Addinlnstall

Установка рабочей книги в качестве надстройки

AddinUninstall

Удаление рабочей книги, используемой в качестве надстройки

BeforeClose

Начало закрытия рабочей книги

BeforePrint

Начало процесса печати или предварительного просмотра рабочей

 

книги или любого из ее элементов

BeforeSave

Начало сохранения рабочей книги

Deactivate

Деактивизация рабочей книги

NewSheet

Создание нового листа в рабочей книге

Open

Открытие рабочей книги

PivotTableCloseConnection* Соединение с внешним источником данных сводной таблицы

 

закрыто

 

PivotTableOpenConnection* Соединение с внешним источником данных сводной таблицы

 

открыто

 

SheetActivate

Активизация любого листа

 

SheetBeforeDoubleClick

Двойной щелчок на любом из листов. Это событие происходит до

 

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

SheetBeforeEightClick

Щелчок правой кнопкой мыши на любом листе. Это событие про-

 

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

 

кой мыши

 

SheetCalculate

Расчет (или перерасчет) значений в любом листе

 

SheetChange

Изменение любого листа пользователем или внешней ссылкой

SheetDeactivate

Деактивизация любого листа

 

SheetFollowHyperlink

Щелчок на гиперссылке в листе

 

SheetPivotTableUpdate

Пополнение сводной таблицы новыми данными

 

SheetSelectionChange

Изменение выделения на любом листе

 

WindowActivate

Активизация окна любой рабочей книги

 

WindowDeactivate

Деактивация окна любой рабочей книги

,

WindowResize

Изменение размера окна любой рабочей книги

 

" Это событие происходит только в Excel 2002 и не поддерживается в предыдущих версиях.

ЧастьV.Совершенныеметодыпрограммирования

503

Если необходимо следить за событиями, возникающими для всех рабочих книг, то следует работать на уровне объекта Application (см. раздел "События объекта Application" далее в этой главе). Ниже приведены примеры использования событий объекта workbook. Все примеры процедур, представленные ниже,, должны располагаются в модуле кода объекта ЭтаКнига. Если разместить их в модуле кода другого типа, то они не будут работать.

Событие Open

Одним из наиболее часто используемых является событие Open объекта рабочей книги. Это событие возникает при открытии рабочей книги (или надстройки). При этом выполняется процедура Workbook_Open. Процедура Workbook_Open может выполнять любые действия, но чаще всего она используется для решения следующих задач:

отображении приветственных сообщений;

открытия других рабочих книг;

настройки пользовательских меню или панелей инструментов;

активизации определенного листа или ячейки;

проверки определенных условий (например, рабочая книга может требовать наличия определенной надстройки);

установки определенных автоматических средств (например, можно определять комбинации клавиш — см. раздел "Событие ОпКеу" далее в этой главе);

настройки свойства S c r o l l A r e a рабочего листа (которое не хранится в рабочей книге);

настройки защиты User I n t e r faceOnly для рабочего листа, что позволяет управлять

защищенными листами в коде. Этот параметр является аргументом метода P r o t e c t и не хранится в пределах рабочей книги

Если пользователь будет удерживать клавишу <Shift> в момент открытия рабочей книги, то процедура Workbook_ppen не сможет быть запущена.

Ниже приводится простой пример процедуры Workbook_Open. Эта процедура использует функцию Weekday для определения дня недели. Если текущий день недели пятница, то отображается окно сообщения, которое напоминает пользователю о необходимости проведения еженедельного резервного копирования файлов. Если текущий день недели не пятница, то ничего не происходит.

P r i v a t e Sub Workbook_Open{)

If Weekday(Now) = vbFriday Then

Msg = "Сегодня пятница. Ты уже создал" Msg = Msg & "новую резервную копию?" MsgBox Msg, vblnformation

End If End Sub

Событие Activate

Следующая процедура выполняется при каждой активизации рабочей книги, Эта проце-

дура разворачивает активное окно:

 

504

Глава 19. Концепция событий Excel

Private Sub Workbook_Activate()

ActiveWindow.WindowState = xlMaximized

End Sub

Событие SheetActivate

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

Private Sub Workbook_SheetActivate(ByVal Sh As Object) If TypeName(Sh) = "Worksheet" Then _

Range("Al").Select

End Sub

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

P r i v a t e Sub Workbook_SheetActivate{ByVal Sh As Object)

On Error Resume Next Range("Al").Select

End Sub

Событие NewSheet

Рассматриваемая процедура выполняется каждый раз, когда к рабочей книге добавляется лист. Лист передается в процедуру в качестве аргумента. Так как новый лист может выступать как рабочим листом, так и листом диаграммы, то эта процедура в обязательном порядке определяет тип листа. Если вставляется рабочий лист, то код создает запись о дате и времени добавления листа в ячейку А1.

Private Sub Workbook_NewSheet(ByVal Sh As Object) If TypeName(Sh) = "Worksheet" Then _

Range("Al") = "Лист добавлен " & Now () End Sub

Событие BeforeSave

Событие B e f o r e S a v e возникает перед фактическим сохранением рабочей книги. Как известно, использование команды Файл^Сохранить приводит к появлению диалогового окна Сохранение документа. Это происходит в том случае, если рабочая книга еще ни разу

не сохранялась и не открывалась в режиме "только чтения".

 

При

выполнении процедуры

Workbook_Bef o r e S a v e ей передается

аргумент

(SaveAsUI), который позволяет предвосхитить появление диалогового окна Сохранение

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

 

Private Sub Workbook_BeforeSave __

 

{ByVal SaveAsUI As Boolean,

Cancel As Boolean)

 

If SaveAsUI Then

 

 

 

MsgBox "Щелкните на кнопке OK для сохранения."

 

End

If

 

 

End Sub

 

 

 

Часть V. Совершенные методы программирования

505

Когда пользователь сохраняет рабочую книгу, выполнится процедура Workbook_ BeforeSave . Если операция сохранения приводит к появлению диалогового окна Сохранение документа, то переменной SaveAsUl присваивается значение True . Процедура проверяет переменную SaveAsUl, в результате отображается сообщение лишь в том случае, если на экране появляется окно сохранения документа. При установлении процедурой аргумента C a n c e l в значение True файл сохранен не будет.

Событие Deactivate

Предлагаемый пример демонстрирует использование события D e a c t i v a t e . Эта процедура выполняется каждый раз при деактивизашш рабочей книги. Она не позволяет пользователю деактивизиронать рабочую книгу. При возникновении события D e a c t i v a t e код производит повторную активизацию рабочей книги и выводит на экран соответствующее сообщение.

Private Sub Workbook_Deactivate() Me.Windows(1).Activate

MsgBox "Мне жаль, ко вы не покинете эту книгу!" End Sub

Использовать такие процедуры не рекомендуется. Если процедура пытается "взвалить" на себя задачи Excel, то ее действия могут привести пользователя в замешательство. Мы настоятельно рекомендуем обучать пользователей правильной работе с приложением.

Приводимый пример иллюстрирует важность обработки событий в необходимой последовательности. Запустив эту процедуру, вы убедитесь, что она работает правильно только в тех случаях, когда пользователь активизирует другую рабочую книгу. Событие D e a c t i v a t e для рабочей книги возникает и в ряде других случаев:

при закрытии рабочей книги;

при открытии новой рабочей книги;

при сворачивании окна рабочей книги..

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

Событие BeforePrint

Событие B e f o r e P r i n t происходит, когда пользователь отправляет документ на печать или отображает его (или фрагмент рабочей книги) в режиме предварительного просмотра. Данное событие происходит перед началом фактической печати или предварительного просмотра рабочей книги. Процедура обработки этого события принимает аргумент C a n c e l , чтобы в коде можно было отменить печать пли выполнить предварительный просмотр в результате установки этого аргумента и значение True . К сожалению, не существует способа определить, чем было спровоцировано событие B e £ o r e P r i n t : отправкой задания печати или запросом предварительного просмотра.

В Excel до версии 2002 нельзя было в верхнем или нижнем колонтитуле страницы напечатать полный путь к файлу, в котором хранилась рабочая книга. Excel 2002 решает эту проблему. Теперь на вкладке Колонтитулы (доступ к ней открыт в диалоговом окне Параметры страницы) можно определить все необходимые данные колонтитулов.

506 Глава 19. Концепция событий Excel

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

Private Sub Workbook_BeforePrint(Cancel As Boolean) For Each sht In ThisWorkbaok.Sheets

sht.PageSetup.LeftFooter = „ "&8" & ThisWorkbook.FullName

Next sht End Sub

Эта процедура просматривает все листы рабочей книги и присваивает свойству LeftFooter объекта PageSetup значение свойства FileName объекта рабочей книги (которое содержит путь и имя файла, где хранится рабочая книга). Кроме того, размер шрифта устанавливается в значение 8 пунктов.

Приводимый пример демонстрирует неоднородность объектной модели Excel. Для того чтобы изменить размер шрифта нижнего и верхнего колонтитулов, необходимо применить специальный код форматирования. В примере, показанном выше, используется строка "&8" для назначения шрифта размером 8 пунктов. В идеале в объектах колонтитулов должен использоваться объект Font. Чтобы определить доступность других способов форматирования, необходимо обратиться к справочному руководству (или записать макрос в момент доступа к диалоговому окну Параметры страницы, а затем проанализировать полученный код).

При тестировании процедуры обработки события BeforePrint вы сможете сэкономить время {и бумагу), выполнив предварительный просмотр документа вместо отправки его на печать.

Событие BeforeClose

Событие B e f o r e C l o s e происходит перед закрытием рабочей книги. Это событие часто используется совместно с процедурой Workbook_Open. Например, можно использовать процедуру Workbook_open для создания дополнительной опции меню, специфичной для конкретной рабочей книги, а процедуру W o r k b o o k _ B e f o r e C l o s e — для удаления этого дополнительного элемента из меню. Таким образом вы обеспечите доступность опции меню только в открытой рабочей книге.

Как известно, при попытке закрыть несохраненную рабочую книгу Excel выдает сообщение с запросом на сохранение рабочей книги перед ее закрытием (рис. 19.4).

Рис. 19.4- Если отображается это сообщение, значит, процедура Workhook_Be£oreClose уже завершиласвоюработу

Обратим ваше внимание на потенциальную проблему, которая заключается в следующем: к моменту отображения этого сообщения событие BeforeClose уже возникло, что указывает на завершение работы процедуры workbook_BeforeCios(j.

Часть V. Совершенные методы программирования

507

Рассмотрим иной сценарий развития событий: в момент открытия определенной рабочей книги отображается пользовательское меню. В данном случае рабочая книга использует процедуру Workbook_Open для создания меню при открытии рабочей книги, а процедура Workbook_Bef o r e C l o s e — для удаления этого меню при закрытии рабочей книги. Процедуры обработки событий приведены ниже. Обе процедуры вызывают другие процедуры, которые нами не рассматриваются.

Private Sub Workbook_Open()

Call CreateMenu

End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)

Call DeleteMenu

End Sub

Как отмечалось выше, сообщение Excel Сохранить и з м е н е н и я . . . отображается после того, как процедура Workbook_Bef o r e C l o s e завершит свою работу. Поэтому, если пользователь щелкнет на кнопке Отмена, то работай книга останется открытой, но дополнительный элемент меню будет уже удален!

Одним из решений подобной проблемы является создание кода запроса на сохранение в процедуре Workbook _ BeforeClose . Ниже приведен пример, выполняющий подобную задачу.

Private Sub Workbook_BeforeClose(Cancel As Boolean) Dim Msg As String

If Me.Saved Then Call DeleteMenu Exit Sub

Else

Msg = "Сохранить изменения в документе?" Msg = Msg & Me.Name & "?"

Ans = MsgBox{Msg, vbQuestion + vbVesNoCancel) Select Case Ans

Case vbYes Me.Save

Call DeleteMenu Case vbNo

Me.Saved = True

Call DeleteMenu Case vbCancel

Cancel = True End Select

End If End Sub

Данная процедура проверяет значение свойства Saved объекта Workbook, с целью определить наличие в рабочей книге несохраненных данных. Если они существуют, то выполняется процедура DeleteMenu, и рабочая книга закрывается. Однако в рабочей книге могут оставаться несохраненные данные, тогда процедура отображает окно сообщения, которое дублирует исходное окно сообщения Excel. Если пользователь щелкнет на кнопке Да, то рабочая книга будет сохранена, элемент меню удален, а рабочая книга — закрыта. Если пользователь щелкнет на кнопке Нет, то код установит свойство Saved объекта Workbook в значение True {но не будет сохранять файл) и удалит опцию меню. Если пользователь щелкнет на кнопке Отмена, то событие Bef o r e C l o a e будет отменено и процедура завершится без удаления элемента меню.

508

Глава 19. Концепция событий Excel

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