Перехватить событие от excel

8 / 8 / 3

Регистрация: 12.07.2014

Сообщений: 19

1

12.07.2014, 21:45. Показов 2021. Ответов 2


Студворк — интернет-сервис помощи студентам

Нужно перехватить завершение работы Excel, т.е. если пользователь нажмёт «крестик» в правом верхнем углу или кнопку «Выход из Excel» вместо завершения работы запускалась определённая процедура. И уже она спросит пользователя уверен ли он, в зависимости от открытого листа корректно сохранит данные и только потом выполнит Application.Quit



0



ikki

призрак

3261 / 889 / 119

Регистрация: 11.05.2012

Сообщений: 1,702

Записей в блоге: 2

13.07.2014, 00:25

2

ну, если нужно — значит перехватывайте.
для файла — обработка события workbook_beforeclose (в модуле книги)
для приложения (хотя, по-моему, вам это не особо нужно) — тоже в модуле книги:

Visual Basic
1
2
3
4
5
6
7
8
9
10
Private WithEvents app As Application
 
Private Sub app_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)
  MsgBox "попытка закрыть приложение"
  Cancel = True ' отменяем закрытие
End Sub
 
Private Sub Workbook_Open()
  Set app = Application
End Sub



5



Ts

8 / 8 / 3

Регистрация: 12.07.2014

Сообщений: 19

14.07.2014, 15:48

 [ТС]

3

Большое спасибо!
Правда Ваш пример у меня не сработал, то ли руки у меня кривые, то ли извилины прямые
Но начал разбираться с Workbook_BeforeClose и у меня получилось так:
В модуле «ЭтаКнига»

Visual Basic
1
2
3
Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Cancel = End_Work
End Sub

А в модуле определил функцию End_Work

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Function End_Work()
'   Имя листа на котором завершается работа
    Name_List = ActiveSheet.Name
    
    Response = MsgBox("Вы действительно хотите завершить работу с программой?", _
        vbYesNo + vbDefaultButton2, "Моя программа")
    If Response = vbYes Then
'   Нажата кнопка ДА
'          Различные действия в зависимости на каком листе завершается работа 
           Select Case Name_List
                Case "Лист1"
                    Cells(2, 6).Select
                Case "Лист2"
                    Cells(2, 3).Select
                Case "Лист3"
                    Cells(2, 2).Select
            End Select
 
'           Отображение ранее скрытой Ленты Excel
            Application.ExecuteExcel4Macro "SHOW.TOOLBAR(""Ribbon"", True)"         
            
'           Сохранение книги
            ActiveWorkbook.Save
 
            End_Work = False
        Else
'   Нажата кнопка НЕТ
            End_Work = True
    End If
End Function

Так всё работает как планировалось. Ещё раз БОЛЬШОЕ СПАСИБО!



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

14.07.2014, 15:48

Помогаю со студенческими работами здесь

Перехват события
Добрый день, возник вопрос. Есть форма требуется по нажатию крестика(стандартного закрыть окно),…

Перехват события
Есть функция которая при нажатии на submit вызывает alert
Как сделать чтобы вызов алерта…

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

Перехват события в Fullscreen
Здравствуйте знатоки.

Сделал проигрыватель видео который можно переходить в полноэкранный режим…

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

3

Содержание

  1. Как отследить событие(например выделение ячеек) в любой книге?
  2. Метод WorksheetFunction.Intercept (Excel)
  3. Синтаксис
  4. Параметры
  5. Возвращаемое значение
  6. Замечания
  7. Поддержка и обратная связь
  8. Обработка событий
  9. События Excel VBA — Введение
  10. Различные типы событий Excel VBA
  11. Где поставить код, связанный с событием
  12. Понимание последовательности событий
  13. Понимание роли аргументов в событиях VBA
  14. События на уровне рабочей книги (поясняются примерами)
  15. События уровня рабочего листа (объясненные с примерами)
  16. Событие Excel VBA OnTime
  17. Событие Excel VBA OnKey
  18. Отключение событий в VBA
  19. Влияние событий Undo Stack

Как отследить событие(например выделение ячеек) в любой книге?

Иногда при разработке надстройки просто необходимо отследить какое-либо событие в книге. Но модуль ЭтаКнига и модули листов надстройки позволяют отследить лишь те события, которые происходят в той книге, в которой этот код прописан. А как же другие книги? Как, например, отследить событие открытия любой книги в Excel и сделать какое-то действие в зависимости от имени открытой книги? Или как отследить выделение ячейки в любой книге? Изменение значений ячеек?

На самом деле все до смешного просто:
В модуле ЭтаКнига главной книги(надстройка либо PERSONAL.XLS) необходимо создать переменную, которая будет ссылкой на все приложение Excel

Private WithEvents App As Application

На событие открытия главной книги (той, в которой пишется код и в которой объявили переменную App — опять же это надстройка либо PERSONAL.XLS) присваиваем этой переменной App значение запущенного приложения Excel:

Private Sub Workbook_Open() Set App = Application End Sub

Т.е. мы теперь имеем как бы свою локальную управляемую ссылку на Excel. Это позволит нам получить доступ к событиям приложения Excel из VBA и отследить их. И среди прочих событий есть такие, которые относятся ко всем открытым книгам. Т.е. то же выделение ячеек мы сможем обработать только внутри своей надстройки, но срабатывать оно будет при выделении ячеек в любой открытой книге.
Теперь создаем непосредственно событие — аналогично выбору других событий в книге в левом окне выбора объектов выбираем App. В правом появятся все доступные события для нашего объекта App:

в этом окне перечислены все события, которые могут быть «перехвачены» в любой открытой книге, а не только той, в которой этот код записан. Сразу после выбора какого-либо события из списка автоматически будет создана пустая процедура, в которую надо будет лишь добавить необходимый код.
Рассмотрим некоторые из этих событий.

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

Private Sub App_WorkbookOpen(ByVal Wb As Workbook) MsgBox «Вы открыли книгу:» & Wb.Name End Sub

Теперь при открытии любой книги будет появляться сообщение с именем именно открытой книги.
Wb — это переменная событийной процедуры. Для каждой процедуры они могут отличаться или вовсе отсутствовать. Но если они есть — значит можно их использовать. Например, в этой процедуре( App_WorkbookOpen ) Wb это открываемая книга, т.е. объект типа Workbook. И к ней можно обращаться как к любой книге: перебрать листы, изменить какие-то свойства и т.п. Например, в коде выше я просто вывожу в информационное окно с именем открываемой книги.

Сам по себе код не заработает. Т.к. назначение значения переменной App происходит только при открытии самой книги(надстройки или PERSONAL), то после создания кодов надо будет сохранить эту книгу и открыть заново

А с помощью этого кода можно отследить создание новой книги :

Private Sub App_NewWorkbook(ByVal Wb As Workbook) MsgBox «Вы создали новую книгу» End Sub

Отслеживаем выделение ячеек во всех открытых книгах :

Private Sub App_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range) MsgBox «Вы выделили ячейку с адресом: » & Target.Address End Sub

Target — это объект Range(ячейка или диапазон ячеек), которые были выделены в книге.
Sh — это объект Worksheet, ячейки которого были выделены.
Таким образом у нас есть две переменные, которые мы можем использовать. Например, можно производить определенные действия только на листах с конкретным именем:

Private Sub App_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range) If Sh.Name = «Отчет» Then MsgBox «Вы выделили ячейку с адресом: » & Target.Address End If End Sub

А процедура ниже поможет отследить изменение значений ячеек во всех открытых книгах и отменить нежелательные изменения:

Private Sub App_SheetChange(ByVal Sh As Object, ByVal Target As Range) Dim bUndo As Boolean If Sh.Name <> «Для изменений» Then If Sh.Name = «Описание» Then ‘для этого листа можно изменять только ячейки диапазона «A16:B20» If Intersect(Target, Sh.Range(«A16:B20»)) Is Nothing Then MsgBox «На этом листе изменять можно только ячейки в диапазоне ‘A16:B20’!», vbCritical, «www.excel-vba.ru» bUndo = True End If Else ‘для всех других листов, кроме листа «Для изменений» — изменять значения ячеек вообще нельзя MsgBox «Ячейки на этом листе нельзя изменять!», vbCritical, «www.excel-vba.ru» bUndo = True End If If bUndo Then With Application .EnableEvents = False .Undo .EnableEvents = True End With End If End If End Sub

В приложенном к статье файле будет чуть более понятно что делает эта процедура.

Естественно, в таких процедурах можно назначить выполнение и других(нужных) действий. Например, вызов макроса ( Call ИмяМакроса ). Макрос в таком случае должен быть размещен в стандартном модуле и иметь статус Public (или вовсе без статуса). Сам модуль должен тоже находится в той же книге.

Tips_Macro_How_Catch_Events.xls (60,5 KiB, 4 639 скачиваний)

Статья помогла? Поделись ссылкой с друзьями!

Источник

Метод WorksheetFunction.Intercept (Excel)

Вычисляет точку, в которой линия будет пересекаться с осью Y с использованием существующих значений X и Y. Точка перехвата основана на наиболее подходящей линии регрессии, отрисоченной через известные значения x и известные значения y.

Используйте функцию Intercept , если требуется определить значение зависимой переменной, если независимая переменная равна 0 (нулю). Например, функцию Intercept можно использовать для прогнозирования электрического сопротивления металла при 0°C при получении точек данных при комнатной температуре и выше.

Синтаксис

expression. Перехват (Arg1, Arg2)

Выражение Переменная, представляющая объект WorksheetFunction .

Параметры

Имя Обязательный или необязательный Тип данных Описание
Arg1 Обязательный Variant Known_y — зависимый набор наблюдений или данных.
Arg2 Обязательный Variant Known_x — независимый набор наблюдений или данных.

Возвращаемое значение

Double

Замечания

Аргументы должны быть числами или именами, массивами или ссылками, содержащими числа.

Если массив или ссылочный аргумент содержит текст, логические значения или пустые ячейки, эти значения игнорируются; однако включаются ячейки с нулевым значением.

Если known_y и known_x содержат разное количество точек данных или не содержат точек данных, функция Intercept возвращает значение ошибки #N/A.

Уравнение для перехвата линии регрессии, a, имеет следующий вид:

где наклон , b, вычисляется следующим образом:

и где x и y — это выборка, означаемая AVERAGE(known_x) и AVERAGE(known_y).

Базовый алгоритм, используемый в функциях Перехват и Наклон , отличается от базового алгоритма, используемого в функции LinEst . Разница между этими алгоритмами может привести к разным результатам, если данные не определены и коллинеарны. Например, если точки данных аргумента known_y имеют значение 0, а точки данных аргумента known_x — 1:

Перехват и наклон возвращают #DIV/0! Ошибка. Алгоритм перехвата и наклона предназначен для поиска одного и только одного ответа, и в этом случае может быть несколько ответов.

LinEst возвращает значение 0. Алгоритм LinEst предназначен для возврата разумных результатов для коллинеарных данных, и в этом случае можно найти по крайней мере один ответ.

Поддержка и обратная связь

Есть вопросы или отзывы, касающиеся Office VBA или этой статьи? Руководство по другим способам получения поддержки и отправки отзывов см. в статье Поддержка Office VBA и обратная связь.

Источник

Обработка событий

Когда вы создаете или записываете макрос в Excel, вам нужно запустить макрос, чтобы выполнить шаги в коде.

Несколько способов запуска макроса включают использование диалогового окна макроса, назначение макроса кнопке, использование ярлыка и т.д.

Помимо этих запускаемых пользователем макросов, вы также можете использовать события VBA для запуска макроса.

События Excel VBA — Введение

Позвольте мне сначала объяснить, что такое событие в VBA.

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

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

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

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

Например, если вы вставляете новый лист и хотите, чтобы он имел префикс года, вы можете написать для него код.

Теперь, когда кто-нибудь вставляет новый лист, этот код будет автоматически выполняться и добавлять префикс года к имени листа.

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

Точно так же вы можете создавать коды VBA для многих таких событий (рассмотрим позже в этой статье).

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

Двойной щелчок — это событие, а отображение окна сообщения — это то, что я указал в коде, когда происходит событие двойного щелчка.

Хотя приведенный выше пример является бесполезным событием, я надеюсь, что он поможет вам понять, как это происходит.

Различные типы событий Excel VBA

В Excel есть разные объекты — например, сам Excel (к которому мы часто обращаемся как приложение), рабочие книги, рабочие таблицы, диаграммы и т.д.

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

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

Ниже приведены различные типы событий, которые существуют в Excel:

  1. События уровня рабочего листа. Это типы событий, которые запускаются на основе действий, выполненных в рабочем листе. Примеры этих событий включают изменение ячейки на рабочем листе, изменение выделения, двойной щелчок по ячейке, щелчок правой кнопкой мыши по ячейке и т.д.
  2. События на уровне рабочей книги. Эти события будут инициироваться на основе действий на уровне рабочей книги. Примеры таких событий включают добавление новой рабочей таблицы, сохранение рабочей книги, открытие рабочей книги, печать части или всей рабочей книги и т.д.
  3. События уровня приложения: это события, которые происходят в приложении Excel. Примером этого может быть закрытие любой из открытых рабочих книг или открытие новой рабочей книги.
  4. События уровня пользовательской формы: эти события будут инициироваться на основе действий в пользовательской форме. Примеры этого включают инициализацию пользовательской формы или нажатие кнопки в пользовательской форме.
  5. События диаграммы: это события, относящиеся к листу диаграммы. Лист диаграммы отличается от рабочего листа. Примеры таких событий могут включать изменение серии диаграммы или изменение размера диаграммы.
  6. События OnTime и OnKey. Это два события, которые не соответствуют ни одной из перечисленных выше категорий. Поэтому я перечислил их отдельно. Событие «OnTime» позволяет вам выполнить код в определенное время или по истечении определенного времени. Событие «OnKey» позволяет выполнить код, когда используется определенное нажатие клавиши (или комбинация нажатий клавиш).

Где поставить код, связанный с событием

В приведенном выше разделе я рассмотрел различные типы событий.

В зависимости от типа события вам необходимо поместить код в соответствующий объект.

Например, если это событие, связанное с рабочим листом, оно должно идти в окне кода объекта рабочего листа. Если она связана с книгой, она должна идти в окне кода для объекта книги.

В VBA разные объекты — такие как Worksheets, Workbooks, Chart Sheets, UserForms и т.д. Имеют собственные окна кода. Вам необходимо поместить код события в окно кода соответствующего объекта. Например, если это событие уровня рабочей книги, вам нужно иметь код события в окне кода рабочей книги.

Следующие разделы охватывают места, где вы можете поместить код события:

В окне кода Worksheet

Когда вы откроете VB Editor (используя сочетание клавиш ALT + F11), вы заметите объект рабочих таблиц в Project Explorer. Для каждого листа в книге вы увидите один объект.

Если дважды щелкнуть объект листа, в который вы хотите поместить код, откроется окно кода для этого листа.

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

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

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

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

Примечание. Как только вы выберете «Worksheet» в раскрывающемся списке, вы увидите две строки кода в окне кода. После того, как вы выбрали событие, для которого вы хотите код, вы можете удалить строки, которые появились по умолчанию.

Обратите внимание, что каждый лист имеет собственное окно кода. Когда вы вводите код для Лист1, он будет работать только в том случае, если событие происходит в Лист1.

В окне кода ThisWorkBook

Точно так же как рабочие листы, если у вас есть код события уровня книги, вы можете поместить его в окно кода ThisWorkbook.

Когда вы дважды щелкните на ThisWorkbook, он откроет окно кода для него.

Вам нужно выбрать Workbook из выпадающего списка в верхнем левом углу окна кода.

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

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

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

В окне кода Userform

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

Хотя объекты Sheet и ThisWorkbook уже доступны при открытии редактора VB, пользовательская форма — это то, что вам нужно создать в первую очередь.

Чтобы создать пользовательскую форму, щелкните правой кнопкой мыши любой из объектов, перейдите на вкладку «Вставка» и выберите «UserForm».

Это вставит объект UserForm в книгу.

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

Теперь, так же как рабочие листы или ThisWorkbook, вы можете выбрать событие, и оно вставит первую и последнюю строку для этого события. И тогда вы можете добавить код в середине этого.

В окне кода Chart

В Excel вы также можете вставлять листы диаграмм (которые отличаются от листов). Лист диаграмм должен содержать только диаграммы.

Вставив лист диаграммы, вы сможете увидеть объект листа диаграммы в редакторе VB.

Вы можете добавить код события в окно кода листа диаграммы, как мы это делали на листе.

Дважды щелкните объект листа Chart в Project Explorer. Это откроет окно кода для листа диаграммы.

Теперь вам нужно выбрать Chart из выпадающего списка в верхнем левом углу окна кода.

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

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

Class Module должны быть вставлены так же, как пользовательские формы.

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

Я расскажу о модуле класса в качестве отдельного учебного пособия в ближайшие недели.

Обратите внимание, что кроме событий OnTime и OnKey, ни одно из перечисленных выше событий не может быть сохранено в обычном модуле VBA.

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

Когда вы запускаете событие, оно не происходит изолированно. Это также может привести к последовательности нескольких триггеров.

Например, когда вы вставляете новый лист, происходит следующее:

  1. Добавлен новый рабочий лист
  2. Предыдущая рабочая таблица деактивируется
  3. Новый лист активируется

Хотя в большинстве случаев вам не нужно беспокоиться о последовательности, если вы создаете сложные коды, основанные на событиях, лучше знать последовательность, чтобы избежать неожиданных результатов.

Понимание роли аргументов в событиях VBA

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

В событиях VBA было бы два типа кодов:

  • Без каких-либо аргументов
  • С аргументами

И в этом разделе я хочу быстро осветить роль аргументов.

Ниже приведен код без аргументов (круглые скобки пусты):

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

Теперь давайте посмотрим на код, который имеет аргумент.

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

Присвоив новый лист, который добавляется к книге, объектной переменной Sh, VBA позволил нам использовать его в коде. Поэтому, чтобы обратиться к новому названию листа, я могу использовать Sh.Name.

Концепция аргументов будет полезна при ознакомлении с примерами событий VBA в следующих разделах.

События на уровне рабочей книги (поясняются примерами)

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

Событие Что запускает событие
Activate Когда книга активирована
AfterSave Когда книга установлена как надстройка
BeforeSave Когда рабочая книга сохранена
BeforeClose Когда рабочая книга закрыта
BeforePrint Когда печатается книга
Deactivate Когда книга деактивирована
NewSheet Когда добавляется новый лист
Open Когда рабочая книга открыта
SheetActivate Когда любой лист в книге
активирован
SheetBeforeDelete При удалении любого листа
SheetBeforeDoubleClick При двойном щелчке по любому листу
SheetBeforeRightClick При щелчке правой кнопкой
мыши по любому листу
SheetCalculate Когда любой лист
рассчитывается или
пересчитывается
SheetDeactivate Когда рабочая книга
деактивирован
SheetPivotTableUpdate При обновлении книги
SheetSelectionChange При изменении рабочей книги
WindowActivate Когда книга активирована
WindowDeactivate Когда книга деактивирована

Обратите внимание, что это не полный список.

Помните, что код для события Workbook хранится в окне кода объектов ThisWorkbook.

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

Событие Workbook Open

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

Вы можете использовать приведенный ниже код, чтобы сделать это:

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

При работе с этим кодом (или с кодами событий рабочей книги в целом) необходимо знать несколько вещей:

  • Если в книге есть макрос, и вы хотите сохранить его, вам нужно сохранить его в формате .XLSM. В противном случае код макроса будет потерян.
  • В приведенном выше примере код события будет выполняться только при включенных макросах. Может появиться желтая полоса, запрашивающая разрешение на включение макросов. Пока это не включено, код события не выполняется.
  • Код события Workbook помещается в окно кода объекта ThisWorkbook.

Вы можете дополнительно уточнить этот код и показать сообщение только пятницы.

Код ниже сделает это:

Обратите внимание, что в функции «Weekday» воскресенье присваивается значение 1, понедельник — 2 и т. Д.

Поэтому на пятницу я использовал 6.

Событие Open Workbook может быть полезно во многих ситуациях, таких как:

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

Событие Workbook NewSheet

Событие NewSheet запускается при вставке нового листа в рабочую книгу.

Допустим, вы хотите ввести значение даты и времени в ячейку A1 вновь вставленного листа. Вы можете использовать приведенный ниже код, чтобы сделать это:

Приведенный выше код использует «On Error Resume Next» для обработки случаев, когда кто-то вставляет лист диаграммы, а не лист. Поскольку на листе диаграммы нет ячейки A1, будет отображаться ошибка, если «On Error Resume Next» не используется.

Другой пример может быть, когда вы хотите применить некоторые базовые настройки или форматирование к новому листу, как только он будет добавлен. Например, если вы хотите добавить новый лист и хотите, чтобы он автоматически получал серийный номер (до 100), то вы можете использовать код ниже.

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

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

Событие Workbook BeforeSave

Событие «BeforeSave» запускается при сохранении книги. Обратите внимание, что событие инициируется сначала, а затем рабочая книга сохраняется.

При сохранении книги Excel возможны два сценария:

  1. Вы сохраняете его в первый раз, и он покажет диалоговое окно Сохранить как.
  2. Вы уже сохранили его ранее, и он просто сохранит и перезапишет изменения в уже сохраненной версии.

Теперь давайте рассмотрим несколько примеров, где вы можете использовать событие BeforeSave.

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

В приведенном выше коде, если файл никогда не был сохранен, SaveAsUI имеет значение True и вызывает диалоговое окно Save As. Приведенный выше код будет отображать сообщение до появления диалогового окна «Save As».

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

Приведенный ниже код вставляет отметку даты и времени в ячейку A1 листа She1 при каждом сохранении файла.

Обратите внимание, что этот код выполняется, как только пользователь сохраняет рабочую книгу. Если книга сохраняется в первый раз, в ней отобразится диалоговое окно «Save As». Но код уже выполняется к тому времени, когда вы видите диалоговое окно Save As. На этом этапе, если вы решите отменить и не сохранить книгу, дата и время уже будут введены в ячейку.

Событие Workbook BeforeClose

Событие «BeforeClose» происходит непосредственно перед закрытием книги.

Приведенный ниже код защищает все рабочие листы до их закрытия.

Помните, что код события срабатывает, как только вы закрываете книгу.

Об этом событии важно знать, что не имеет значения, закрыта ли рабочая книга или нет.

В случае, если рабочая книга не была сохранена, и вы увидите приглашение с вопросом о том, сохранять рабочую книгу или нет, и вы нажмете Отмена, она не сохранит вашу рабочую книгу. Однако код события уже был бы выполнен к тому времени.

Событие Workbook BeforePrint

Когда вы даете команду печати (или команду предварительного просмотра), запускается событие «BeforePrint».

Приведенный ниже код будет пересчитывать все рабочие листы до их печати.

Когда пользователь печатает книгу, событие вызывается независимо от того, печатает ли он всю книгу или только ее часть.

Другой пример, приведенный ниже, — это код, который добавляет дату и время в нижний колонтитул при печати рабочей книги.

События уровня рабочего листа (объясненные с примерами)

События рабочего листа происходят на основе триггеров в рабочем листе.

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

Событие Что запускает событие
Activate Когда лист активирован
BeforeDelete Перед удалением листа
BeforeDoubleClick Перед двойным щелчком на
листе
BeforeRightClick Перед щелчком правой кнопкой мыши по рабочему листу
Calculate До того, как рабочий лист будет рассчитан или пересчитан
Change При изменении ячеек на листе
Deactivate Когда лист деактивирован
PivotTableUpdate При обновлении сводной
таблицы на листе
SelectionChange Когда выбор на рабочем листе
изменяется

Обратите внимание, что это не полный список. Вы можете найти полный список здесь.

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

Теперь давайте посмотрим на некоторые полезные события на листе и посмотрим, как их можно использовать в вашей повседневной работе.

Событие Worksheet Activate

Это событие вызывается при активации рабочего листа.

Приведенный ниже код снимает защиту листа, как только он активирован.

Вы также можете использовать это событие, чтобы убедиться, что конкретная ячейка или диапазон ячеек (или именованный диапазон) выбран, как только вы активируете рабочую таблицу. Приведенный ниже код выберет ячейку D1, как только вы активируете лист.

Событие Worksheet Change

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

Есть некоторые изменения, которые вызывают событие, а некоторые нет. Вот список некоторых изменений, которые не вызовут событие:

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

Следующие изменения могут вызвать событие (даже если вы думаете, что не должно):

  • Копирование и вставка форматирования вызовут событие.
  • Очистка форматирования вызовет событие.
  • Запуск проверки орфографии вызовет событие.

Ниже код будет отображать окно сообщения с адресом ячейки, которая была изменена.

Хотя это бесполезный макрос, он показывает, как использовать аргумент Target, чтобы узнать, какие ячейки были изменены.

Теперь давайте посмотрим пару более полезных примеров.

Предположим, у вас есть диапазон ячеек (скажем, A1: D10), и вы хотите показать подсказку и спросить пользователя, действительно ли он хочет изменить ячейку в этом диапазоне, вы можете использовать приведенный ниже код.

Отображается подсказка с двумя кнопками — «Да» и «Нет». Если пользователь выбирает «Да», изменение выполняется, в противном случае оно отменяется.

В приведенном выше коде мы проверяем, находится ли целевая ячейка в первых 4 столбцах и первых 10 строках. Если это так, появится окно сообщения. Кроме того, если пользователь выбрал «Нет» в окне сообщения, изменение отменяется (с помощью команды Application.Undo).

Обратите внимание, что я использовал Application.EnableEvents = False перед строкой Application.Undo. И затем я изменил его, используя Application.EnableEvent = True в следующей строке.

Это необходимо, поскольку, когда происходит отмена, это также вызывает событие изменения. Если я не установлю для параметра EnableEvent значение False, он продолжит вызывать событие изменения.

Вы также можете отслеживать изменения в именованном диапазоне, используя событие изменения. Например, если у вас есть именованный диапазон с именем «DataRange», и вы хотите показать подсказку на случай, если пользователь внесет изменение в этот именованный диапазон, вы можете использовать код ниже:

Приведенный выше код проверяет, имеет ли ячейка / диапазон, в котором вы внесли изменения, какие-либо ячейки, общие для диапазона данных. Если это так, он показывает окно сообщения.

Событие SelectionChange Workbook

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

Приведенный ниже код будет пересчитывать лист, как только вы измените выбор.

Другой пример этого события — когда вы хотите выделить активную строку и столбец выбранной ячейки.

Что-то, как показано ниже:

Следующий код может сделать это:

Код сначала удаляет цвет фона из всех ячеек, а затем применяет цвет, упомянутый в коде, к активной строке и столбцу.

И это проблема с этим кодом. Что он удаляет цвет со всех клеток.

Если вы хотите выделить активную строку / столбец, не изменяя цвета в других ячейках, используйте технику, показанную в этом руководстве.

Событие Workbook DoubleClick

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

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

Позвольте мне показать вам, как это круто.

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

Это может быть полезно, когда вы просматриваете список ячеек и хотите выделить несколько выбранных. Хотя вы можете использовать клавишу F4, чтобы повторить последний шаг, он сможет применить только один вид форматирования. С этим событием двойного щелчка вы можете применить все три с помощью двойного щелчка.

Обратите внимание, что в приведенном выше коде я сделал значение Cancel = True.

Это сделано для того, чтобы действие двойного щелчка по умолчанию было отключено — то есть войти в режим редактирования. Если Cancel = True, Excel не переведет вас в режим редактирования, если дважды щелкнуть ячейку.

Вот еще один пример.

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

Как показано ниже:

Вот код, который сделает это:

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

Событие Excel VBA OnTime

События, которые мы видели до сих пор в этой статье, были связаны с одним из объектов Excel, будь то рабочая книга, рабочий лист, лист диаграммы или пользовательские формы и т.д.

Событие OnTime отличается от других событий, поскольку оно может быть сохранено в обычном модуле VBA (тогда как другие должны были быть помещены в окно кода объектов, таких как ThisWorkbook или Worksheets или UserForms).

В обычном модуле VBA он используется как метод объекта приложения.

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

Или, если я хочу показать сообщение / напоминание в определенное время дня, я могу использовать событие OnTime.

Ниже приведен код, который будет показывать сообщение в 2 часа дня каждый день.

Помните, что вам нужно поместить этот код в обычный модуль VBA,

Кроме того, хотя событие OnTime будет запускаться в указанное время, макрос необходимо запускать вручную в любое время. После запуска макроса он будет ждать до 14:00, а затем вызовет макрос «ShowMessage».

Макрос ShowMessage будет отображать сообщение.

Событие OnTime принимает четыре аргумента:

Application.OnTime (Самое раннее время, Процедура, Последнее время, Расписание)

  • EarliestTime: время, когда вы хотите запустить процедуру.
  • Procedure: имя процедуры, которая должна быть запущена.
  • LatestTime (Необязательно): Если другой код выполняется и указанный код не может быть запущен в указанное время, вы можете указать LatestTime, которого он должен ждать. Например, это может быть EarliestTime + 45 (что означает, что он будет ждать 45 секунд, пока другая процедура завершится). Если даже через 45 секунд процедура не может быть запущена, она прекращается. Если вы не укажете это, Excel подождет, пока код может быть запущен, а затем запустит его.
  • Schedule (необязательно): если установлено значение «ИСТИНА», оно планирует новую процедуру времени. Если ЛОЖЬ, то это отменяет ранее установленную процедуру. По умолчанию это ИСТИНА

В приведенном выше примере мы использовали только первые два аргумента.

Давайте посмотрим на другой пример.

Приведенный ниже код будет обновлять лист каждые 5 минут.

Приведенный выше код обновляет лист каждые 5 минут.

Он использует функцию «Now», чтобы определить текущее время, а затем добавляет 5 минут к текущему времени.

Событие OnTime будет продолжаться до тех пор, пока вы его не остановите. Если вы закроете книгу, а приложение Excel все еще будет запущено (другие книги открыты), книга, в которой запущено событие OnTime, снова откроется.

Это лучше сделать, если специально остановить событие OnTime.

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

Вышеупомянутый код события «BeforeClose» находится в окне кода ThisWorkbook.

Событие Excel VBA OnKey

Когда вы работаете с Excel, он продолжает отслеживать нажатия клавиш, которые вы используете. Это позволяет нам использовать нажатия клавиш в качестве триггера для события.

С помощью события OnKey вы можете указать нажатие клавиши (или комбинацию нажатий клавиш) и код, который должен выполняться при использовании этого нажатия клавиши. При нажатии этих клавиш выполняется код для него.

Точно так же, как событие OnTime, у вас должен быть способ отменить событие OnKey. Кроме того, когда вы устанавливаете событие OnKey для определенного нажатия клавиши, оно становится доступным во всех открытых книгах.

Прежде чем я покажу вам пример использования события OnKey, позвольте мне сначала поделиться кодами клавиш, которые вам доступны в VBA.

Ключ Код
Backspace or
Break
Caps Lock
Delete or
Down Arrow
End
Enter
Enter (on the nueric keypad)
Escape or
Home
Ins
Left Arrow
NumLock
PageDown
PageUp
RightArrow
Scroll Lock
Tab
Up Arrow
F1 through F15 through

Когда вам нужно использовать любое событие onkey, вам нужно использовать код для него.

В приведенной выше таблице приведены коды для однократных нажатий.

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

Shift: + (знак плюс)
Контроль: ^ (Карет)
Alt:% (в процентах)
Например, для Alt F4 вам нужно использовать код: «% » — где% для клавиши ALT, а для клавиши F4.

Теперь давайте посмотрим на примере (помните, код для событий OnKey находится в обычном модуле VBA).

Когда вы нажимаете клавишу PageUp или PageDown, она переходит на 29 строк выше / ниже активной ячейки (по крайней мере, это то, что она делает на моем ноутбуке).

Если вы хотите, чтобы он перескакивал только на 5 строк одновременно, вы можете использовать следующий код:

Когда вы запускаете первую часть кода, он запускает события OnKey. Как только это будет выполнено, использование PageUp и клавиши PageDown заставит курсор перескакивать только на 5 строк за раз.

Обратите внимание, что мы использовали «On Error Resume Next», чтобы убедиться, что ошибки игнорируются. Эти ошибки могут возникать, когда вы нажимаете клавишу PageUp, даже если вы находитесь в верхней части листа. Поскольку больше нет строк для перехода, код покажет ошибку. Но так как мы использовали «On Error Resume Next», он будет проигнорирован.

Чтобы убедиться, что эти события OnKey доступны, вам нужно запустить первую часть кода. Если вы хотите, чтобы это было доступно, как только вы откроете рабочую книгу, вы можете поместить ее в окно кода ThisWorkbook.

Приведенный ниже код вернет ключи к их нормальной работе.

Если вы не укажете второй аргумент в методе OnKey, он вернет нажатие клавиши к своей обычной функциональности.

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

В приведенном ниже коде Excel ничего не будет делать, когда мы используем ключи PageUp или PageDown.

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

Иногда вам может потребоваться отключить события, чтобы ваш код работал правильно.

Например, предположим, что у меня есть диапазон (A1: D10), и я хочу показать сообщение всякий раз, когда ячейка изменяется в этом диапазоне. Поэтому я показываю окно сообщения и спрашиваю пользователя, уверены ли они, что хотят внести изменения. Если ответ «Да», изменение внесено, и если ответ «Нет», VBA отменит его.

Вы можете использовать следующий код:

Проблема с этим кодом заключается в том, что когда пользователь выбирает «Нет» в окне сообщения, действие отменяется (как я использовал Application.Undo).

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

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

Чтобы избежать таких случаев, вам нужно отключить события, чтобы событие изменения (или любое другое событие) не срабатывало.

Следующий код будет хорошо работать в этом случае:

В приведенном выше коде, прямо над строкой Application.Undo, мы использовали — Application.EnableEvents = False.

Если для параметра EnableEvents установлено значение False, это не приведет к возникновению какого-либо события (в текущей или любой открытой рабочей книге).

После того, как мы завершили операцию отмены, мы можем переключить свойство EnableEvents на True.

Имейте в виду, что отключение событий влияет на все книги, которые в данный момент открыты (или открыты, когда для параметра EnableEvents установлено значение False). Например, как часть кода, если вы откроете новую книгу, событие Workbook Open не будет работать.

Влияние событий Undo Stack

Позвольте мне сначала рассказать вам, что такое Undo Stack.

Когда вы работаете в Excel, он продолжает следить за вашими действиями. Когда вы делаете ошибку, вы всегда можете использовать Control + Z, чтобы вернуться к предыдущему шагу (то есть отменить ваше текущее действие).

Если вы дважды нажмете Control + Z, это вернет вас назад на два шага. Эти шаги, которые вы выполнили, сохраняются как часть Undo Stack.

Любое событие, которое изменяет рабочий лист, уничтожает этот стек отмены. Это означает, что если я выполнил 5 действий до запуска события, я не смогу использовать Control + Z, чтобы вернуться к этим предыдущим шагам. Запуск события уничтожил этот стек для меня.

В приведенном ниже коде я использую VBA для ввода метки времени в ячейку A1 при каждом изменении в листе.

Поскольку я делаю изменения в листе, это уничтожит Undo Stack.

Также обратите внимание, что это не ограничивается только событиями.

Если у вас есть код, который хранится в обычном модуле VBA, и вы вносите изменения в рабочую таблицу, это также уничтожит Undo Stack в Excel.

Например, приведенный ниже код просто вводит текст «Hello» в ячейку A1, но даже выполнение этого приведет к разрушению
Undo Stack.

Источник

На чтение 31 мин. Просмотров 19.5k.

Когда вы создаете или записываете макрос в Excel, вам нужно запустить макрос, чтобы выполнить шаги в коде.

Несколько способов запуска макроса включают использование диалогового окна макроса, назначение макроса кнопке, использование ярлыка и т.д.

Помимо этих запускаемых пользователем макросов, вы также можете использовать события VBA для запуска макроса.

Содержание

  1. События Excel VBA — Введение
  2. Различные типы событий Excel VBA
  3. Где поставить код, связанный с событием
  4. Понимание последовательности событий
  5. Понимание роли аргументов в событиях VBA
  6. События на уровне рабочей книги (поясняются примерами)
  7. События уровня рабочего листа (объясненные с примерами)
  8. Событие Excel VBA OnTime
  9. Событие Excel VBA OnKey
  10. Отключение событий в VBA
  11. Влияние событий Undo Stack

Позвольте мне сначала объяснить, что такое событие в VBA.

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

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

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

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

Например, если вы вставляете новый лист и хотите, чтобы он имел префикс года, вы можете написать для него код.

Теперь, когда кто-нибудь вставляет новый лист, этот код будет автоматически выполняться и добавлять префикс года к имени листа.

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

Точно так же вы можете создавать коды VBA для многих таких событий (рассмотрим позже в этой статье).

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

Двойной щелчок — это событие, а отображение окна сообщения — это то, что я указал в коде, когда происходит событие двойного щелчка.

Excel VBA Events Demo Double Click

Хотя приведенный выше пример является бесполезным событием, я надеюсь, что он поможет вам понять, как это происходит.

Различные типы событий Excel VBA

В Excel есть разные объекты — например, сам Excel (к которому мы часто обращаемся как приложение), рабочие книги, рабочие таблицы, диаграммы и т.д.

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

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

Ниже приведены различные типы событий, которые существуют в Excel:

  1. События уровня рабочего листа. Это типы событий, которые запускаются на основе действий, выполненных в рабочем листе. Примеры этих событий включают изменение ячейки на рабочем листе, изменение выделения, двойной щелчок по ячейке, щелчок правой кнопкой мыши по ячейке и т.д.
  2. События на уровне рабочей книги. Эти события будут инициироваться на основе действий на уровне рабочей книги. Примеры таких событий включают добавление новой рабочей таблицы, сохранение рабочей книги, открытие рабочей книги, печать части или всей рабочей книги и т.д.
  3. События уровня приложения: это события, которые происходят в приложении Excel. Примером этого может быть закрытие любой из открытых рабочих книг или открытие новой рабочей книги.
  4. События уровня пользовательской формы: эти события будут инициироваться на основе действий в пользовательской форме. Примеры этого включают инициализацию пользовательской формы или нажатие кнопки в пользовательской форме.
  5. События диаграммы: это события, относящиеся к листу диаграммы. Лист диаграммы отличается от рабочего листа. Примеры таких событий могут включать изменение серии диаграммы или изменение размера диаграммы.
  6. События OnTime и OnKey. Это два события, которые не соответствуют ни одной из перечисленных выше категорий. Поэтому я перечислил их отдельно. Событие «OnTime» позволяет вам выполнить код в определенное время или по истечении определенного времени. Событие «OnKey» позволяет выполнить код, когда используется определенное нажатие клавиши (или комбинация нажатий клавиш).

Где поставить код, связанный с событием

В приведенном выше разделе я рассмотрел различные типы событий.

В зависимости от типа события вам необходимо поместить код в соответствующий объект.

Например, если это событие, связанное с рабочим листом, оно должно идти в окне кода объекта рабочего листа. Если она связана с книгой, она должна идти в окне кода для объекта книги.

В VBA разные объекты — такие как Worksheets, Workbooks, Chart Sheets, UserForms и т.д. Имеют собственные окна кода. Вам необходимо поместить код события в окно кода соответствующего объекта. Например, если это событие уровня рабочей книги, вам нужно иметь код события в окне кода рабочей книги.

Следующие разделы охватывают места, где вы можете поместить код события:

В окне кода Worksheet

Когда вы откроете VB Editor (используя сочетание клавиш ALT + F11), вы заметите объект рабочих таблиц в Project Explorer. Для каждого листа в книге вы увидите один объект.

Excel VBA Events - Worksheets Objects

Если дважды щелкнуть объект листа, в который вы хотите поместить код, откроется окно кода для этого листа.

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

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

Excel VBA Events - Selecting Worksheet Object from the drop down

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

List of Worksheet Events in VBA

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

Your Code Goes Here is the Worksheet Events

Примечание. Как только вы выберете «Worksheet» в раскрывающемся списке, вы увидите две строки кода в окне кода. После того, как вы выбрали событие, для которого вы хотите код, вы можете удалить строки, которые появились по умолчанию.

Обратите внимание, что каждый лист имеет собственное окно кода. Когда вы вводите код для Лист1, он будет работать только в том случае, если событие происходит в Лист1.

В окне кода ThisWorkBook

Точно так же как рабочие листы, если у вас есть код события уровня книги, вы можете поместить его в окно кода ThisWorkbook.

Excel VBA Events - Workbook Objects

Когда вы дважды щелкните на ThisWorkbook, он откроет окно кода для него.

Вам нужно выбрать Workbook из выпадающего списка в верхнем левом углу окна кода.

Select Workbook Object from the drop down

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

List of Workbook Events in VBA

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

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

В окне кода Userform

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

Хотя объекты Sheet и ThisWorkbook уже доступны при открытии редактора VB, пользовательская форма — это то, что вам нужно создать в первую очередь.

Чтобы создать пользовательскую форму, щелкните правой кнопкой мыши любой из объектов, перейдите на вкладку «Вставка» и выберите «UserForm».

Inserting a Userform in Excel

Это вставит объект UserForm в книгу.

Userform inserted in Excel in the VB Editor

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

Теперь, так же как рабочие листы или ThisWorkbook, вы можете выбрать событие, и оно вставит первую и последнюю строку для этого события. И тогда вы можете добавить код в середине этого.

В окне кода Chart

В Excel вы также можете вставлять листы диаграмм (которые отличаются от листов). Лист диаграмм должен содержать только диаграммы.

Вставив лист диаграммы, вы сможете увидеть объект листа диаграммы в редакторе VB.

Вы можете добавить код события в окно кода листа диаграммы, как мы это делали на листе.

Дважды щелкните объект листа Chart в Project Explorer. Это откроет окно кода для листа диаграммы.

Обработка событий

Теперь вам нужно выбрать Chart из выпадающего списка в верхнем левом углу окна кода.

Excel VBA Events - Select Chart from the drop down

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

List of Chart Sheet Events in VBA

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

В Class Module

Class Module должны быть вставлены так же, как пользовательские формы.

Inserting a Class Module in Excel

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

Я расскажу о модуле класса в качестве отдельного учебного пособия в ближайшие недели.

Обратите внимание, что кроме событий OnTime и OnKey, ни одно из перечисленных выше событий не может быть сохранено в обычном модуле VBA.

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

Когда вы запускаете событие, оно не происходит изолированно. Это также может привести к последовательности нескольких триггеров.

Например, когда вы вставляете новый лист, происходит следующее:

  1. Добавлен новый рабочий лист
  2. Предыдущая рабочая таблица деактивируется
  3. Новый лист активируется

Хотя в большинстве случаев вам не нужно беспокоиться о последовательности, если вы создаете сложные коды, основанные на событиях, лучше знать последовательность, чтобы избежать неожиданных результатов.

Понимание роли аргументов в событиях VBA

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

В событиях VBA было бы два типа кодов:

  • Без каких-либо аргументов
  • С аргументами

И в этом разделе я хочу быстро осветить роль аргументов.

Ниже приведен код без аргументов (круглые скобки пусты):

Private Sub Workbook_Open()
MsgBox "Не забудьте заполнить расписание"
End Sub

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

Теперь давайте посмотрим на код, который имеет аргумент.

Private Sub Workbook_NewSheet(ByVal Sh As Object)
Sh.Range("A1") = Sh.Name
End Sub

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

Присвоив новый лист, который добавляется к книге, объектной переменной Sh, VBA позволил нам использовать его в коде. Поэтому, чтобы обратиться к новому названию листа, я могу использовать Sh.Name.

Концепция аргументов будет полезна при ознакомлении с примерами событий VBA в следующих разделах.

События на уровне рабочей книги (поясняются примерами)

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

Событие Что запускает событие
Activate Когда книга активирована
AfterSave Когда книга установлена как надстройка
BeforeSave Когда рабочая книга сохранена
BeforeClose Когда рабочая книга закрыта
BeforePrint Когда печатается книга
Deactivate Когда книга деактивирована
NewSheet Когда добавляется новый лист
Open Когда рабочая книга открыта
SheetActivate Когда любой лист в книге
активирован
SheetBeforeDelete При удалении любого листа
SheetBeforeDoubleClick При двойном щелчке по любому листу
SheetBeforeRightClick При щелчке правой кнопкой
мыши по любому листу
SheetCalculate Когда любой лист
рассчитывается или
пересчитывается
SheetDeactivate Когда рабочая книга
деактивирован
SheetPivotTableUpdate При обновлении книги
SheetSelectionChange При изменении рабочей книги
WindowActivate Когда книга активирована
WindowDeactivate Когда книга деактивирована

Обратите внимание, что это не полный список.

Помните, что код для события Workbook хранится в окне кода объектов ThisWorkbook.

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

Событие Workbook Open

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

Вы можете использовать приведенный ниже код, чтобы сделать это:

Private Sub Workbook_Open()
MsgBox "Не забудьте заполнить расписание"
End Sub

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

Workbook Event code example - show reminder

При работе с этим кодом (или с кодами событий рабочей книги в целом) необходимо знать несколько вещей:

  • Если в книге есть макрос, и вы хотите сохранить его, вам нужно сохранить его в формате .XLSM. В противном случае код макроса будет потерян.
  • В приведенном выше примере код события будет выполняться только при включенных макросах. Может появиться желтая полоса, запрашивающая разрешение на включение макросов. Пока это не включено, код события не выполняется.
  • Код события Workbook помещается в окно кода объекта ThisWorkbook.

Вы можете дополнительно уточнить этот код и показать сообщение только пятницы.

Код ниже сделает это:

Private Sub Workbook_Open()
wkday = Weekday(Date)
If wkday = 6 Then MsgBox "Не забудьте заполнить расписание"
End Sub

Обратите внимание, что в функции «Weekday» воскресенье присваивается значение 1, понедельник — 2 и т. Д.

Поэтому на пятницу я использовал 6.

Событие Open Workbook может быть полезно во многих ситуациях, таких как:

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

Событие Workbook NewSheet

Событие NewSheet запускается при вставке нового листа в рабочую книгу.

Допустим, вы хотите ввести значение даты и времени в ячейку A1 вновь вставленного листа. Вы можете использовать приведенный ниже код, чтобы сделать это:

Private Sub Workbook_NewSheet(ByVal Sh As Object)
On Error Resume Next
Sh.Range("A1") = Format(Now, "dd-mmm-yyyy hh:mm:ss")
End Sub

Приведенный выше код использует «On Error Resume Next» для обработки случаев, когда кто-то вставляет лист диаграммы, а не лист. Поскольку на листе диаграммы нет ячейки A1, будет отображаться ошибка, если «On Error Resume Next» не используется.

Другой пример может быть, когда вы хотите применить некоторые базовые настройки или форматирование к новому листу, как только он будет добавлен. Например, если вы хотите добавить новый лист и хотите, чтобы он автоматически получал серийный номер (до 100), то вы можете использовать код ниже.

Private Sub Workbook_NewSheet(ByVal Sh As Object)
On Error Resume Next
With Sh.Range("A1")
.Value = "S. No."
.Interior.Color = vbBlue
.Font.Color = vbWhite
End With
For i = 1 To 100
Sh.Range("A1").Offset(i, 0).Value = i
Next i
Sh.Range("A1", Range("A1").End(xlDown)).Borders.LineStyle = xlContinuous
End Sub

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

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

Событие Workbook BeforeSave

Событие «BeforeSave» запускается при сохранении книги. Обратите внимание, что событие инициируется сначала, а затем рабочая книга сохраняется.

При сохранении книги Excel возможны два сценария:

  1. Вы сохраняете его в первый раз, и он покажет диалоговое окно Сохранить как.
  2. Вы уже сохранили его ранее, и он просто сохранит и перезапишет изменения в уже сохраненной версии.

Теперь давайте рассмотрим несколько примеров, где вы можете использовать событие BeforeSave.

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

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If SaveAsUI Then MsgBox "Сохраните этот файл на диске K"
End Sub

В приведенном выше коде, если файл никогда не был сохранен, SaveAsUI имеет значение True и вызывает диалоговое окно Save As. Приведенный выше код будет отображать сообщение до появления диалогового окна «Save As».

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

Приведенный ниже код вставляет отметку даты и времени в ячейку A1 листа She1 при каждом сохранении файла.

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Worksheets("Лист1").Range("A1") = Format(Now, "dd-mmm-yyyy hh:mm:ss")
End Sub

Обратите внимание, что этот код выполняется, как только пользователь сохраняет рабочую книгу. Если книга сохраняется в первый раз, в ней отобразится диалоговое окно «Save As». Но код уже выполняется к тому времени, когда вы видите диалоговое окно Save As. На этом этапе, если вы решите отменить и не сохранить книгу, дата и время уже будут введены в ячейку.

Событие Workbook BeforeClose

Событие «BeforeClose» происходит непосредственно перед закрытием книги.

Приведенный ниже код защищает все рабочие листы до их закрытия.

Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim sh As Worksheet
For Each sh In ThisWorkbook.Worksheets
sh.Protect
Next sh
End Sub

Помните, что код события срабатывает, как только вы закрываете книгу.

Об этом событии важно знать, что не имеет значения, закрыта ли рабочая книга или нет.

В случае, если рабочая книга не была сохранена, и вы увидите приглашение с вопросом о том, сохранять рабочую книгу или нет, и вы нажмете Отмена, она не сохранит вашу рабочую книгу. Однако код события уже был бы выполнен к тому времени.

Событие Workbook BeforePrint

Когда вы даете команду печати (или команду предварительного просмотра), запускается событие «BeforePrint».

Приведенный ниже код будет пересчитывать все рабочие листы до их печати.

Private Sub Workbook_BeforePrint(Cancel As Boolean)
 For Each ws in Worksheets
 ws.Calculate
 Next ws
 End Sub

Когда пользователь печатает книгу, событие вызывается независимо от того, печатает ли он всю книгу или только ее часть.

Другой пример, приведенный ниже, — это код, который добавляет дату и время в нижний колонтитул при печати рабочей книги.

Private Sub Workbook_BeforePrint(Cancel As Boolean)
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.PageSetup.LeftFooter = "Напечатано - " & Format(Now, "dd-mmm-yyyy hh:mm")
Next ws
End Sub

События уровня рабочего листа (объясненные с примерами)

События рабочего листа происходят на основе триггеров в рабочем листе.

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

Событие Что запускает событие
Activate Когда лист активирован
BeforeDelete Перед удалением листа
BeforeDoubleClick Перед двойным щелчком на
листе
BeforeRightClick Перед щелчком правой кнопкой мыши по рабочему листу
Calculate До того, как рабочий лист будет рассчитан или пересчитан
Change При изменении ячеек на листе
Deactivate Когда лист деактивирован
PivotTableUpdate При обновлении сводной
таблицы на листе
SelectionChange Когда выбор на рабочем листе
изменяется

Обратите внимание, что это не полный список. Вы можете найти полный список здесь.

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

Теперь давайте посмотрим на некоторые полезные события на листе и посмотрим, как их можно использовать в вашей повседневной работе.

Событие Worksheet Activate

Это событие вызывается при активации рабочего листа.

Приведенный ниже код снимает защиту листа, как только он активирован.

Private Sub Worksheet_Activate()
ActiveSheet.Unprotect
End Sub

Вы также можете использовать это событие, чтобы убедиться, что конкретная ячейка или диапазон ячеек (или именованный диапазон) выбран, как только вы активируете рабочую таблицу. Приведенный ниже код выберет ячейку D1, как только вы активируете лист.

Private Sub Worksheet_Activate()
ActiveSheet.Range("D1").Select
End Sub

Событие Worksheet Change

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

Ну .. не всегда.

Есть некоторые изменения, которые вызывают событие, а некоторые нет. Вот список некоторых изменений, которые не вызовут событие:

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

Следующие изменения могут вызвать событие (даже если вы думаете, что не должно):

  • Копирование и вставка форматирования вызовут событие.
  • Очистка форматирования вызовет событие.
  • Запуск проверки орфографии вызовет событие.

Ниже код будет отображать окно сообщения с адресом ячейки, которая была изменена.

Private Sub Worksheet_Change(ByVal Target As Range)
MsgBox "Вы только что изменились " & Target.Address
End Sub

Хотя это бесполезный макрос, он показывает, как использовать аргумент Target, чтобы узнать, какие ячейки были изменены.

Теперь давайте посмотрим пару более полезных примеров.

Предположим, у вас есть диапазон ячеек (скажем, A1: D10), и вы хотите показать подсказку и спросить пользователя, действительно ли он хочет изменить ячейку в этом диапазоне, вы можете использовать приведенный ниже код.

Отображается подсказка с двумя кнопками — «Да» и «Нет». Если пользователь выбирает «Да», изменение выполняется, в противном случае оно отменяется.

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row <= 10 And Target.Column <= 4 Then
Ans = MsgBox("Вы вносите изменения в ячейки в A1: D10. Вы уверены, что хотите это?", vbYesNo)
End If
If Ans = vbNo Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
End If
End Sub

В приведенном выше коде мы проверяем, находится ли целевая ячейка в первых 4 столбцах и первых 10 строках. Если это так, появится окно сообщения. Кроме того, если пользователь выбрал «Нет» в окне сообщения, изменение отменяется (с помощью команды Application.Undo).

Обратите внимание, что я использовал Application.EnableEvents = False перед строкой Application.Undo. И затем я изменил его, используя Application.EnableEvent = True в следующей строке.

Это необходимо, поскольку, когда происходит отмена, это также вызывает событие изменения. Если я не установлю для параметра EnableEvent значение False, он продолжит вызывать событие изменения.

Вы также можете отслеживать изменения в именованном диапазоне, используя событие изменения. Например, если у вас есть именованный диапазон с именем «DataRange», и вы хотите показать подсказку на случай, если пользователь внесет изменение в этот именованный диапазон, вы можете использовать код ниже:

Private Sub Worksheet_Change(ByVal Target As Range)
Dim DRange As Range
Set DRange = Range("DataRange")
If Not Intersect(Target, DRange) Is Nothing Then
MsgBox "Вы только что внесли изменения в диапазон данных"
End If
End Sub

Приведенный выше код проверяет, имеет ли ячейка / диапазон, в котором вы внесли изменения, какие-либо ячейки, общие для диапазона данных. Если это так, он показывает окно сообщения.

Событие SelectionChange Workbook

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

Приведенный ниже код будет пересчитывать лист, как только вы измените выбор.

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.Calculate
End Sub

Другой пример этого события — когда вы хотите выделить активную строку и столбец выбранной ячейки.

Что-то, как показано ниже:

Excel VBA Events - Selection change event

Следующий код может сделать это:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Cells.Interior.ColorIndex = xlNone
With ActiveCell
.EntireRow.Interior.Color = RGB(248, 203, 173)
.EntireColumn.Interior.Color = RGB(180, 198, 231)
End With
End Sub

Код сначала удаляет цвет фона из всех ячеек, а затем применяет цвет, упомянутый в коде, к активной строке и столбцу.

И это проблема с этим кодом. Что он удаляет цвет со всех клеток.

Если вы хотите выделить активную строку / столбец, не изменяя цвета в других ячейках, используйте технику, показанную в этом руководстве.

Событие Workbook DoubleClick

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

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

Позвольте мне показать вам, как это круто.

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

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Cancel = True
With Target
.Interior.Color = vbBlue
.Font.Color = vbWhite
.Font.Bold = True
End With
End Sub

Это может быть полезно, когда вы просматриваете список ячеек и хотите выделить несколько выбранных. Хотя вы можете использовать клавишу F4, чтобы повторить последний шаг, он сможет применить только один вид форматирования. С этим событием двойного щелчка вы можете применить все три с помощью двойного щелчка.

Обратите внимание, что в приведенном выше коде я сделал значение Cancel = True.

Это сделано для того, чтобы действие двойного щелчка по умолчанию было отключено — то есть войти в режим редактирования. Если Cancel = True, Excel не переведет вас в режим редактирования, если дважды щелкнуть ячейку.

Вот еще один пример.

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

Как показано ниже:

Excel VBA Event - Double Click Event

Вот код, который сделает это:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Cancel = True
CurrFormat = Target.Font.Strikethrough
If CurrFormat Then
Target.Font.Strikethrough = False
Else
Target.Font.Strikethrough = True
End If
End Sub

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

Событие Excel VBA OnTime

События, которые мы видели до сих пор в этой статье, были связаны с одним из объектов Excel, будь то рабочая книга, рабочий лист, лист диаграммы или пользовательские формы и т.д.

Событие OnTime отличается от других событий, поскольку оно может быть сохранено в обычном модуле VBA (тогда как другие должны были быть помещены в окно кода объектов, таких как ThisWorkbook или Worksheets или UserForms).

В обычном модуле VBA он используется как метод объекта приложения.

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

Или, если я хочу показать сообщение / напоминание в определенное время дня, я могу использовать событие OnTime.

Ниже приведен код, который будет показывать сообщение в 2 часа дня каждый день.

Sub MessageTime()
Application.OnTime TimeValue("14:00:00"), "ShowMessage"
End Sub

Sub ShowMessage()
MsgBox "Время обеда"
End Sub

Помните, что вам нужно поместить этот код в обычный модуль VBA,

Кроме того, хотя событие OnTime будет запускаться в указанное время, макрос необходимо запускать вручную в любое время. После запуска макроса он будет ждать до 14:00, а затем вызовет макрос «ShowMessage».

Макрос ShowMessage будет отображать сообщение.

Событие OnTime принимает четыре аргумента:

Application.OnTime (Самое раннее время, Процедура, Последнее время, Расписание)

  • EarliestTime: время, когда вы хотите запустить процедуру.
  • Procedure: имя процедуры, которая должна быть запущена.
  • LatestTime (Необязательно): Если другой код выполняется и указанный код не может быть запущен в указанное время, вы можете указать LatestTime, которого он должен ждать. Например, это может быть EarliestTime + 45 (что означает, что он будет ждать 45 секунд, пока другая процедура завершится). Если даже через 45 секунд процедура не может быть запущена, она прекращается. Если вы не укажете это, Excel подождет, пока код может быть запущен, а затем запустит его.
  • Schedule (необязательно): если установлено значение «ИСТИНА», оно планирует новую процедуру времени. Если ЛОЖЬ, то это отменяет ранее установленную процедуру. По умолчанию это ИСТИНА

В приведенном выше примере мы использовали только первые два аргумента.

Давайте посмотрим на другой пример.

Приведенный ниже код будет обновлять лист каждые 5 минут.

Dim NextRefresh as Date

Sub RefreshSheet()
ThisWorkbook.Worksheets("Лист1").Calculate
NextRefresh = Now + TimeValue("00:05:00")
Application.OnTime NextRefresh, "RefreshSheet"
End Sub

Sub StopRefresh()
On Error Resume Next
Application.OnTime NextRefresh, "RefreshSheet", , False
End Sub

Приведенный выше код обновляет лист каждые 5 минут.

Он использует функцию «Now», чтобы определить текущее время, а затем добавляет 5 минут к текущему времени.

Событие OnTime будет продолжаться до тех пор, пока вы его не остановите. Если вы закроете книгу, а приложение Excel все еще будет запущено (другие книги открыты), книга, в которой запущено событие OnTime, снова откроется.

Это лучше сделать, если специально остановить событие OnTime.

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

Private Sub Workbook_BeforeClose(Cancel As Boolean)
Call StopRefresh
End Sub

Вышеупомянутый код события «BeforeClose» находится в окне кода ThisWorkbook.

Событие Excel VBA OnKey

Когда вы работаете с Excel, он продолжает отслеживать нажатия клавиш, которые вы используете. Это позволяет нам использовать нажатия клавиш в качестве триггера для события.

С помощью события OnKey вы можете указать нажатие клавиши (или комбинацию нажатий клавиш) и код, который должен выполняться при использовании этого нажатия клавиши. При нажатии этих клавиш выполняется код для него.

Точно так же, как событие OnTime, у вас должен быть способ отменить событие OnKey. Кроме того, когда вы устанавливаете событие OnKey для определенного нажатия клавиши, оно становится доступным во всех открытых книгах.

Прежде чем я покажу вам пример использования события OnKey, позвольте мне сначала поделиться кодами клавиш, которые вам доступны в VBA.

Ключ Код
Backspace {BACKSPACE} or {BS}
Break {BREAK}
Caps Lock {CAPSLOCK}
Delete {DELETE} or {DEL}
Down Arrow {DOWN}
End {END}
Enter ~
Enter (on the nueric keypad) {ENTER}
Escape {ESCAPE} or {ESC}
Home {HOME}
Ins {INSERT}
Left Arrow {LEFT}
NumLock {NUMLOCK}
PageDown {PGDN}
PageUp {PGUP}
RightArrow {RIGHT}
Scroll Lock {SCROLLOCK}
Tab {TAB}
Up Arrow {UP}
F1 through F15 {F1} through {F15}

Когда вам нужно использовать любое событие onkey, вам нужно использовать код для него.

В приведенной выше таблице приведены коды для однократных нажатий.

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

Shift: + (знак плюс)
Контроль: ^ (Карет)
Alt:% (в процентах)
Например, для Alt F4 вам нужно использовать код: «% {F4}» — где% для клавиши ALT, а {F4} для клавиши F4.

Теперь давайте посмотрим на примере (помните, код для событий OnKey находится в обычном модуле VBA).

Когда вы нажимаете клавишу PageUp или PageDown, она переходит на 29 строк выше / ниже активной ячейки (по крайней мере, это то, что она делает на моем ноутбуке).

Если вы хотите, чтобы он перескакивал только на 5 строк одновременно, вы можете использовать следующий код:

Sub PageUpDOwnKeys()
Application.OnKey "{PgUp}", "PageUpMod"
Application.OnKey "{PgDn}", "PageDownMod"
End Sub

Sub PageUpMod()
On Error Resume Next
ActiveCell.Offset(-5, 0).Activate
End Sub

Sub PageDownMod()
On Error Resume Next
ActiveCell.Offset(5, 0).Activate
End Sub

Когда вы запускаете первую часть кода, он запускает события OnKey. Как только это будет выполнено, использование PageUp и клавиши PageDown заставит курсор перескакивать только на 5 строк за раз.

Обратите внимание, что мы использовали «On Error Resume Next», чтобы убедиться, что ошибки игнорируются. Эти ошибки могут возникать, когда вы нажимаете клавишу PageUp, даже если вы находитесь в верхней части листа. Поскольку больше нет строк для перехода, код покажет ошибку. Но так как мы использовали «On Error Resume Next», он будет проигнорирован.

Чтобы убедиться, что эти события OnKey доступны, вам нужно запустить первую часть кода. Если вы хотите, чтобы это было доступно, как только вы откроете рабочую книгу, вы можете поместить ее в окно кода ThisWorkbook.

Private Sub Workbook_Open()
Application.OnKey "{PgUp}", "PageUpMod"
Application.OnKey "{PgDn}", "PageDownMod"
End Sub

Приведенный ниже код вернет ключи к их нормальной работе.

Sub Cancel_PageUpDownKeysMod()
Application.OnKey "{PgUp}"
Application.OnKey "{PgDn}"
End Sub

Если вы не укажете второй аргумент в методе OnKey, он вернет нажатие клавиши к своей обычной функциональности.

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

В приведенном ниже коде Excel ничего не будет делать, когда мы используем ключи PageUp или PageDown.

Sub Ignore_PageUpDownKeys()
Application.OnKey "{PgUp}", ""
Application.OnKey "{PgDn}", ""
End Sub

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

Иногда вам может потребоваться отключить события, чтобы ваш код работал правильно.

Например, предположим, что у меня есть диапазон (A1: D10), и я хочу показать сообщение всякий раз, когда ячейка изменяется в этом диапазоне. Поэтому я показываю окно сообщения и спрашиваю пользователя, уверены ли они, что хотят внести изменения. Если ответ «Да», изменение внесено, и если ответ «Нет», VBA отменит его.

Вы можете использовать следующий код:

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row <= 10 And Target.Column <= 4 Then
Ans = MsgBox("Вы вносите изменения в ячейки в A1: D10. Вы уверены, что хотите это?", vbYesNo)
End If
If Ans = vbNo Then
Application.Undo
End If
End Sub

Проблема с этим кодом заключается в том, что когда пользователь выбирает «Нет» в окне сообщения, действие отменяется (как я использовал Application.Undo).

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

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

Чтобы избежать таких случаев, вам нужно отключить события, чтобы событие изменения (или любое другое событие) не срабатывало.

Следующий код будет хорошо работать в этом случае:

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row <= 10 And Target.Column <= 4 Then
Ans = MsgBox("Вы вносите изменения в ячейки в A1: D10. Вы уверены, что хотите это?", vbYesNo)
End If
If Ans = vbNo Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
End If
End Sub

В приведенном выше коде, прямо над строкой Application.Undo, мы использовали — Application.EnableEvents = False.

Если для параметра EnableEvents установлено значение False, это не приведет к возникновению какого-либо события (в текущей или любой открытой рабочей книге).

После того, как мы завершили операцию отмены, мы можем переключить свойство EnableEvents на True.

Имейте в виду, что отключение событий влияет на все книги, которые в данный момент открыты (или открыты, когда для параметра EnableEvents установлено значение False). Например, как часть кода, если вы откроете новую книгу, событие Workbook Open не будет работать.

Влияние событий Undo Stack

Позвольте мне сначала рассказать вам, что такое Undo Stack.

Когда вы работаете в Excel, он продолжает следить за вашими действиями. Когда вы делаете ошибку, вы всегда можете использовать Control + Z, чтобы вернуться к предыдущему шагу (то есть отменить ваше текущее действие).

Если вы дважды нажмете Control + Z, это вернет вас назад на два шага. Эти шаги, которые вы выполнили, сохраняются как часть Undo Stack.

Любое событие, которое изменяет рабочий лист, уничтожает этот стек отмены. Это означает, что если я выполнил 5 действий до запуска события, я не смогу использовать Control + Z, чтобы вернуться к этим предыдущим шагам. Запуск события уничтожил этот стек для меня.

В приведенном ниже коде я использую VBA для ввода метки времени в ячейку A1 при каждом изменении в листе.

Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Range("A1").Value = Format(Now, "dd-mmm-yyyy hh:mm:ss")
Application.EnableEvents = True
End Sub

Поскольку я делаю изменения в листе, это уничтожит Undo Stack.

Также обратите внимание, что это не ограничивается только событиями.

Если у вас есть код, который хранится в обычном модуле VBA, и вы вносите изменения в рабочую таблицу, это также уничтожит Undo Stack в Excel.

Например, приведенный ниже код просто вводит текст «Hello» в ячейку A1, но даже выполнение этого приведет к разрушению
Undo Stack.

Sub TypeHello()
Range("A1").Value = "Привет"
End Sub

I want to catch «don’t save» button click on save dialog when user is trying to close Excel workbook, but there are unsaved changes.

My case is:
the user is opening the excel file changing something in the file and clicking to close button, the Excel application will display «do you want to save changes» dialog and I want to handle the cases when the user will choose no or cancel.
I don’t want to switch the screen and show to user my own dialog in my application, the user will not be happy for that solution.
If there is a way to handle this please let me know.

Here is my code:

_xlsApp = new Excel.Application();
_xlsApp.WorkbookBeforeClose += new Excel.AppEvents_WorkbookBeforeCloseEventHandler(xlsApp_WorkbookBeforeClose);
_xlsApp.WorkbookBeforeSave += new Excel.AppEvents_WorkbookBeforeSaveEventHandler(xlsApp_WorkbookBeforeSave);

tshepang's user avatar

tshepang

11.9k21 gold badges90 silver badges135 bronze badges

asked Mar 15, 2014 at 13:03

artos's user avatar

3

IMO you need to overwrite the default save/do not save changes event with a custom one.

In your before save event handler:

  • check if the workbook has any unsaved changes using the Workbook.Saved property
  • if yes, then show a custom there are unsaved changes — save or discard dialog and fetch the user response yes/no (example in this article)
  • you can always cancel the save event — MSDN documentation of the BeforeSave event that shows how to cancel
  • or save the changes using the Workbook.Save method

This way the decision is left to the user (as default, nothing changes from the user perspective), but you can still do whatever you want to do before or after the workbook is saved.

If the user closes the application excel will go first in the before close event. You have two options:
— check here if there are any changes and aks the user and save the answer and use the answer later in the before save event
— or skip this event — if there are any unsaved changes, excel will either way go to the before save event, where you can proceed as shown above; from MSDN If the workbook has been changed, this event occurs before the user is asked to save changes.

answered Mar 15, 2014 at 13:55

keenthinker's user avatar

keenthinkerkeenthinker

7,6152 gold badges38 silver badges45 bronze badges

8

Автор: Гасанов Ровшан Закариевич
ведущий .NET-разработчик компании PFSoft (pfsoft.com)
Microsoft Certified Application Developer
Email: rovshan_gasanoff@pfsoft.com
30 мая 2005 года

1. Вступление.

Многим разработчикам рано или поздно приходится сталкиваться с задачами, которые подразумевают использование Microsoft Excel (далее по тексту просто Excel) в своей работе. Не будем перечислять подобные задачи, думаю, читатель сам уже с этим столкнулся. Многие вопросы покажутся Вам очень знакомыми, кое-кто скажет, а зачем такие сложности? Ведь можно применить утилиту tlbimp.exe, импортировать библиотеку типов, создать RCW сборку, добавить на нее ссылку и вам станет доступно пространство имен Excel, со всеми RCW классами, которые отображают в себя «внутренности» Excel. Или еще проще, просто добавить ссылку на COM-объекты Excel в Visual Studio, и она сделает все сама. Все это хорошо, конечно. И просто. Но иногда возникают условия, когда описанное вкратце «раннее связывание» неприемлемо. И тогда на помощь приходит т.н. «позднее связывание», когда типы становятся известными не на этапе компиляции, а на этапе выполнения.

Описывать позднее связывание в этой статье нет смысла, в литературе, как и в Интернете достаточно материала по этой теме. По поводу языка, то все примеры приведены с использованием C#, но, надеюсь программисты, использующие в своей работе другие .NET языки, смогут разобраться в коде без особого труда.

2. Запуск и завершение работы Excel.

Запуск Excel и его корректное завершение — это самая первая задача, которую нужно решить программисту, если он собрался использовать Excel в своем приложении. Возможно, Excel уже запущен, и операция запуска уже не нужна, достаточно получить на него ссылку, и начать с ним работу. В получении ссылки на уже работающую копию Excel кроется один неприятный момент, связанный с ошибкой в самом приложении Excel (которую вроде бы исправлена в MSOffice 2003)[2]. Эта ситуация подробно описана в конце этой главы.

А сейчас по порядку.

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

using System.Runtime.InteropServices;
using System.Reflection;

Типы, которые необходимы для организации позднего связывания, описаны в этих пространствах имен. Один из них: класс Marshal, который предоставляет богатые возможности для организации взаимодействия между кодом с автоматически управляемой памятью (managed code), и объектами (unmanaged code).

Для получения ссылки на процесс Excel, нужно знать GUID Excel. Однако можно поступить намного проще, зная программный идентификатор Excel: «Excel.Application».

Для получения ссылки на работающий Excel, воспользуйтесь статическим методом GetActiveObject(), класса Marshal:

string sAppProgID = "Excel.Application";
object oExcel = Marshal.GetActiveObject(sAppProgID);

Если Excel уже запущен (COM-объект Excel присутствует), то вызов данного метода вернет ссылку на объект-отображение Excel в .NET, которые Вы сможете использовать для дальнейшей работы. Если Excel не запущен, то возникнет исключение.

Для запуска Excel необходимо воспользоваться классом Activator, описанным в пространстве имен System.

string sAppProgID = "Excel.Application";
// Получаем ссылку на интерфейс IDispatch
Type tExcelObj = Type.GetTypeFromProgID(sAppProgID);
// Запускаем Excel
object oExcel = Activator.CreateInstance(tExcelObj);

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


Рис 1. Объектная модель Excel

Нам для работы необходимо получить вместе с объектом Excel, ссылку на его коллекцию книг, и с ее помощью мы можем получить доступ к любой книге. У каждой книги есть коллекция страниц, ссылку на которую мы также должны получить для доступа к конкретной странице. Хочу сразу заметить, что доступ к книгам и к страницам мы можем получить как по их имени, так и по их порядковому номеру, причем, что самое важное: нумерация книг и страниц в коллекции начинается с единицы, а не с нуля (как принято нумеровать массивы в .NET). Отмечу, что хотя в Visual Basic for Excel есть директива Option Base, на порядок нумерации в коллекциях в наше случае он не влияет.

Для того, чтобы корректно завершить работу с приложением Excel, для всех объектов, которые мы получаем поздним связыванием, нам необходимо применить метод ReleaseComObject класса Marshal

// Уничтожение объекта Excel.
Marshal.ReleaseComObject(oExcel);
// Вызываем сборщик мусора для немедленной очистки памяти
GC.GetTotalMemory(true);

Отмечу сразу, что если вызов GC.Collect() не помогает, то попробуйте очистку памяти этим способом. Если проигнорировать эту операцию, то в памяти останутся объекты Excel, которые будут существовать даже после того, как Вы завершите свое приложение и Excel. Если после этого запустить приложение NET и попытаться получить ссылку на работающий Excel, то мы без проблем ее получим. Но если мы заходим сделать Excel видимым (Установив ему свойство Visible в true), то при наличии MSExcel версии ранней, чем 2003, основное окно Excel прорисовывалось не полностью. На экране присутствовали только панели инструментов и окантовка основного окна. В MS Excel 2003 вроде бы такого не наблюдается.

Но, тем не менее, если Ваша программа получает ссылки на какие-либо объекты Excel, Вы обязательно должны вызвать для них ReleaseComObject() класса Marshal.

А перед завершением работы с Excel обязательно произведите очистку памяти:

GC.GetTotalMemory(true);

3. Управление книгами и страницами.

Позднее связывание подразумевает, что нам неизвестен тип объекта, с которым мы хотим работать, а это значит, что мы не можем применять непосредственно обращаться к его методам и полям, используя оператор <.>. Поэтому для вызова метода, нам необходимо знать его название и список формальных параметров, которые он принимает. Для вызова метода в классе Type предусмотрен метод InvokeMember(). Поэтому нам достаточно получить ссылку на экземпляр класса Type, описывающий тип объекта, с которым мы устанавливаем позднее связывание, и вызвать метод InvokeMember()/ Я не буду останавливаться подробно на этом методе, он достаточно хорошо описан в технической документации. Отмечу только самое необходимое, с которым мы будем непосредственно работать.

Метод InvokeMember() перегружен, и имеет три модификации.

public object InvokeMember(string name,
                           BindingFlags flags,
                           Binder binder,
                           object target,
                           object[] args);

public object InvokeMember(string name,
                           BindingFlags flags,
                           Binder binder,
                           object target,
                           object[] args,
                           CultureInfo info);

public abstract object InvokeMember(string name,
                                    BindingFlags flags,
                                    Binder binder,
                                    object target,
                                    object[] args,
                                    ParameterModifier[] modifiers,
                                    CultureInfo info,
                                    string[] namedParameters);

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

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

  • BindingFlags.InvokeMethod — Найти метод, определить его точку входа, и выполнить передав ему массив фактических параметров.
  • BindingFlags.GetProperty — Установить свойство
  • BindingFlags.SetProperty — Получить значение свойства.

Третий параметр — binder — мы устанавливаем в null — он нам не нужен.

Через четвертый параметр — target — мы передаем ссылку на объект, к методу которого мы хотим обратиться.

Пятый параметр — args — это массив с параметрами, который принимает на вход вызываемый поздним связыванием метод, или массив, который содержит один элемент — значение свойство, которое мы устанавливаем.

Метод InvokeMember() возвращает результат выполнения метода или значение свойства.

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

object oWorkbooks = oExcel.GetType().InvokeMember("Workbooks",
                 BindingFlags.GetProperty, null, oExcel, null);

Объект oWorkbooks и есть managed-ссылка на коллекцию книг.

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

// Доступ к книге по ее порядковому номеру
 
// Создаем массив параметров
object[] args = new object[1];
// Мы ходим получить доступ к первой книге Excel
args[0] = 1;
// Получаем ссылку на первую книгу в коллекции Excel
object oWorkbook = oWorkbooks.GetType().InvokeMember("Item",
             BindingFlags.GetProperty, null, oWorkbooks, args);
 
// Доступ к книге по ее названию (обратите внимание, что расширение в 
//названии не указывается)
object[] args = new object[1];
// Указываем название книги, к которой мы хотим получить доступ
args[0] = "Книга1";
// Получаем ссылку на первую книгу в коллекции Excel
object oWorkbook = oWorkbooks.GetType().InvokeMember("Item",
             BindingFlags.GetProperty, null, oWorkbooks, args);

Если книг с указанным названием не существует, то данный код выбрасывает исключение.

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

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

//Создаем новую книгу
object oWorkbook = oWorkbooks.GetType().InvokeMember("Add",
          BindingFlags.InvokeMethod, null, oWorkbooks, null);

Для создания книги на основе шаблона, достаточно передать полное имя файла, содержащее этот шаблон:

// Заносим в массив параметров имя файла
object[] args = new object[1];
args[0] = "D:MyAppTemplatesinvoice.xls";
//Создаем новую книгу
object oWorkbook = oWorkbooks.GetType().InvokeMember("Add",
          BindingFlags.InvokeMethod, null, oWorkbooks, args);

Для открытия файла с книгой, воспользуемся методом Open объекта oWorkbooks:

// Открытие файла d:book1.xls
// Заносим в массив параметров имя файла
object[] args = new object[1];
args[0] = "D:book1.xls";
// Пробуем открыть книгу
object oWorkbook = oWorkbooks.GetType().InvokeMember("Open",
            BindingFlags.InvokeMethod, null, oWorkbooks, args);

Закрытие книги возможно с помощью метода Close объекта oWorkbook. При этом он принимает несколько необязательных параметров. Рассмотрим два варианта (Обратите внимание, что мы вызываем метод Close книги, а не коллекции книг, и target-объектом у нас выступает oWorkbook, а не oWorkbooks):

// Вариант 1. Закрываем книгу с принятием всех изменений
object[] args = new object[1];
// с принятием всех изменений
args[0] = true;
// Пробуем закрыть книгу
oWorkbook.GetType().InvokeMember("Close",
    BindingFlags.InvokeMethod, null, oWorkbook, args);
 
// Вариант 2. Закрываем книгу с принятием всех изменений
object[] args = new object[2];
args[0] = true;
// И под определенным названием
args[1] = @"D:book2.xls";
// Пробуем закрыть  книгу
oWorkbook.GetType().InvokeMember("Close",
   BindingFlags.InvokeMethod, null, oWorkbook, args);

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

Для того, чтобы просто сохранить изменения в книге, достаточно вызвать для нее метод Save или SaveAs, передав последнему в качестве параметра имя файла, под которым нужно сохранить книгу.

// Просто сохраняем книгу
oWorkbook.GetType().InvokeMember("Save",
   BindingFlags.InvokeMethod, null, oWorkbook, null);
 
// Задаем параметры метода SaveAs - имя файла
object[] args = new object[2];
args[0] = @"d:d1.xls";
// Сохраняем книгу в файле d:d1.xls
oWorkbook.GetType().InvokeMember("SaveAs",
   BindingFlags.InvokeMethod, null, oWorkbook, args);

// Просто сохраняем рабочую книгу. По умолчанию новая книга без 
// изменений будет сохранена в папку  текущей учетной 
// записи Windows
oWorkbook.GetType().InvokeMember("Save",
   BindingFlags.InvokeMethod, null, oWorkbook, null);

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

object oWorksheets = oWorkbook.GetType().InvokeMember("Worksheets", 
       BindingFlags.GetProperty, null, oWorkbook, null);

Объект oWorksheets — это managed-ссылка на коллекцию страниц текущей книги. Зная ссылку на эту коллекцию мы можем получить доступ к конкретной странице по ее имени или порядковому номеру (Аналогично коллекции рабочих книг):

//Задаем порядковый номер страницы - 1
object[] args = new object[1];
args[0] = 1;
// Получаем ссылку на эту страницу
object oWorksheet = oWorksheets.GetType().InvokeMember("Item",
     BindingFlags.GetProperty, null, oWorksheets, args);
 
//Задаем имя страницы
object[] args = new object[1];
args[0] = "Лист1";
//Получаем ссылку на страницу с именем Лист1
oWorksheet = oWorksheets.GetType().InvokeMember("Item",
BindingFlags.GetProperty, null, oWorksheets, args);

4. Работа со страницами. Объект Range. Использование записи макросов для автоматизации Excel.

Страница имеет ссылку на объект Range, который, по сути представляет собой объект-диапазон ячеек. Через объект Range мы получаем доступ к любой ячейке, а также к ее свойствам. Но объект Range содержит массу методов, и и для позднего связывания нужно знать не только формат передаваемых им формальных параметров, но и точное название метода (или свойства, которое по сути дела является комбинацией методов). Иными словами, нужно знать сигнатуру метода, чтобы успешно вызвать его через позднее связывание. До сих пор мы использовали простые методы типа Open, Close, Save, с которыми, в принципе, все понятно. Они не содержат большое количество параметров, и список параметров интуитивно ясен.

Для того, чтобы узнать, какие методы поддерживает объект Range, можно воспользоваться утилитой tlbimp.exe, и импортировав через нее библиотеку типов Excel, открыть эту библиотеку в дизассемблере IL-кода ildasm.exe. Дизассемблер покажет нам объект Range и все его методы. Можно использовать более продвинутые утилиты сторонних разработчиков (например, всем известный Anakrino).

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


Рис 2. Результат работы макроса.

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

Sub Макрос1()
'
' Макрос1 Макрос
' Макрос записан 17.04.2005 (Powerful)
'
    Range("B3").Select
    With Selection.Interior
        .ColorIndex = 45
        .Pattern = xlSolid
    End With
    Range("C3").Select
    Selection.Font.ColorIndex = 3
    Range("B3").Select
    ActiveCell.FormulaR1C1 = "Привет"
    Range("C3").Select
    ActiveCell.FormulaR1C1 = "из NET!"
    Range("B3:C3").Select
    Selection.Borders(xlDiagonalDown).LineStyle = xlNone
    Selection.Borders(xlDiagonalUp).LineStyle = xlNone
    With Selection.Borders(xlEdgeLeft)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
    With Selection.Borders(xlEdgeTop)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
    With Selection.Borders(xlEdgeBottom)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
    With Selection.Borders(xlEdgeRight)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
    With Selection.Borders(xlInsideVertical)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
End Sub

Как видно, здесь очень часто используется вызов метода Select у объекта Range. Но нам это не нужно, ведь мы можем работать с ячейками напрямую, минуя их выделение. Метод Select просто переопределяет ссылки, которые будут возвращаться объектом Selection. Сам объект Selection — это тот же самый Range. Таким образом, наша задача существенно упрощается, так как нам нужно просто получить ссылки на нужные объекты Range, получить доступ к их внутренним объектам и произвести вызов соответствующих методов или свойств, используя уже известный нам метод InvokeMember().

Возьмем, например следующий участок кода:

	...
    Range("B3").Select
    With Selection.Interior
        .ColorIndex = 45
        .Pattern = xlSolid
    End With
    Range("C3").Select
    Selection.Font.ColorIndex = 3
	...

Данный код окрашивает цвет фона ячейки B3 в оранжевый, причем заливка ячейки — сплошная, а цвет текста ячейки C3 устанавливает в красный.

Попробуем реализовать этот участок в нашем приложении. Допустим, что мы успешно получили ссылки на нужную книгу и страницу.

Ссылка на страницу у нас храниться в переменной oWorksheet.

// Получаем ссылку на ячейку B3 (точнее на объект Range("B3")),
object oRange = oWorksheet.GetType().InvokeMember("Range",
                                                  BindingFlags.GetProperty,
                                                  null,
                                                  oWorksheet, 
                                                  new object[]{"B3"});
 
// Получаем ссылку на объект Interior
object oInterior = oRange.GetType().InvokeMember("Interior",
                                                 BindingFlags.GetProperty,
                                                 null,
                                                 oRange,
                                                 null);
 
// Устанавливаем заливку (Аналог вызова 
// Range("B3").Interior.ColorIndex)
oInterior.GetType().InvokeMember("ColorIndex", BindingFlags.SetProperty,
                                 null, oInterior, new object[]{45});
 
// Устанавливаем способ заливки (Pattern = xlSolid)

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

// Задаем параметр xlSolid = 1;
object[] args = new object[]{1} 
// Устанавливаем свойство Pattern в xlSolid
oInterior.GetType().InvokeMember("Pattern", BindingFlags.SetProperty,
                                 null, oInterior, args);

Для того, чтобы задать текст, можно использовать свойство Value объекта Range.

oRange.GetType().InvokeMember("Value", BindingFlags.SetProperty,
                              null, oRange, new object[]{"Привет"});

Далее разбирать код я не буду, советую читателям самим поэкспериментировать с установкой свойств Excel из приложений .NET, по аналогии с приведенными здесь примерами. А сейчас перейдем к событиям Excel и их перехвату, используя позднее связывание.

5. Перехват событий Excel

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

Если объект (будь-то СОМ или RCW объекта .NET) хочет получать события другого COM объекта, то он должен уведомить об этом источник событий, зарегистрировав себя в списке объектов-получателей уведомлений о событиях. Для этого СОМ предоставляет интерфейс IConnectionPointContainer, содержащий метод FindConnectionPoint. С помощью вызова метода FindConnectionPoint, объект-получатель события получает — интерфейс IConnectionPoint и регистрирует c помощью метода Advise свою реализацию интерфейса IDispatch, методы которого будут реализовываться при возникновении тех или иных событий. Excel определяет интерфейс, который должен реализовываться классом-приемником событий.

interface
["00024413-0000-0000-C000-000000000046"]
{
DispId(0x61d)]
void NewWorkbook(object Wb);
 
DispId(0x616)]
void SheetSelectionChange(object Sh, object Target);
 
DispId(0x617)]
void SheetBeforeDoubleClick(object Sh, object Target, ref bool Cancel);
 
DispId(1560)]
void SheetBeforeRightClick(object Sh, object Target, ref bool Cancel);
 
DispId(0x619)]
void SheetActivate(object Sh);
 
DispId(0x61a)]
void SheetDeactivate(object Sh);
 
DispId(0x61b)]
void SheetCalculate(object Sh);
 
DispId(0x61c)]
void SheetChange(object Sh, object Target);
 
DispId(0x61f)]
void WorkbookOpen(object Wb);
 
DispId(0x620)]
void WorkbookActivate(object Wb);
 
DispId(0x621)]
void WorkbookDeactivate(object Wb);
 
DispId(1570)]
void WorkbookBeforeClose(object Wb, ref bool Cancel);
 
DispId(0x623)]
void WorkbookBeforeSave(object Wb, bool SaveAsUI, ref bool Cancel);
 
DispId(0x624)]
void WorkbookBeforePrint(object Wb, ref bool Cancel);
 
DispId(0x625)]
void WorkbookNewSheet(object Wb, object Sh);
 
DispId(0x626)]
void WorkbookAddinInstall(object Wb);
 
DispId(0x627)]
void WorkbookAddinUninstall(object Wb);
 
DispId(0x612)]
void WindowResize(object Wb, object Wn);
 
DispId(0x614)]
void WindowActivate(object Wb, object Wn);
 
DispId(0x615)]
void WindowDeactivate(object Wb, object Wn);
 
DispId(0x73e)]
void SheetFollowHyperlink(object Sh, object Target);
 
DispId(0x86d)]
void SheetPivotTableUpdate(object Sh, object Target);
 
DispId(2160)]
void WorkbookPivotTableCloseConnection(object Wb, object Target);
 
DispId(0x871)]
void WorkbookPivotTableOpenConnection(object Wb, object Target);
}

Таким образом наш класс — приемник событий должен реализовывать этот интерфейс и регистрировать себя используя IConnectionPointContainer и IConnectionPoint. Библиотека базовых классов .NET уже определяет managed-версии интерфейсов: для IConnectionPointContainer это UCOMIConnectionPointContainer, а для IConnectionPoint — UCOMIConnectionPoint, которые определены в пространстве имен — System.Runtime.InteropServices.

Регистрация класса-приемника событий будет выглядеть так:

 
// Объявляем ссылки на IConnectionPointContainer
UCOMIConnectionPointContainer icpc;
// и на IConnectionPoint
UCOMIConnectionPoint icp;
 
// Получаем ссылку на Excel 
FExcel = Marshal.GetActiveObject("Excel.Application");
 
// Получаем ссылку на интерфейс IConnectionPointContainer
icpc = FExcel as UCOMIConnectionPointContainer;
 
// Получаем "точку подключения"
Guid guid = new Guid("00024413-0000-0000-C000-000000000046");
icpc.FindConnectionPoint(ref guid, out icp);
 
// Регистрируем класс - приемник событий, который реализует
// интерфейс  с GUID ["00024413-0000-0000-C000-000000000046"]
// При этом наш класс получает уникальный идентификатор 
// cookie, который  нужно сохранить, чтобы иметь 
// возможность отключиться от источника событий
icp.Advise(ExcelEventSink, out cookie);

Для отключения от событий достаточно вызвать метод Unadvise(), и передать ему в качестве параметра идентификатор cookie, который мы получили при регистрации нашего класса-приемника событий методом Advise:

icp.Unadvise(cookie);

6. Заключение.

Мы рассмотрели в статье на примере с MS Excel взаимодействие COM и NET, используя позднее связывание. Используя аналогичный подход, можно организовать управление любым COM сервером. (Чаще всего автоматизируют приложения пакета MS Office и MS Internet Explorer).

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

7. Литература

  1. Эндрю Троелсен. С# и платформа .NET. Библиотека программиста. — СПб. Питер, 2004.
  2. Н. Елманова, С. Трепалин, А. Тенцер. Delphi 6 и технология СОМ. — СПб. Питер, 2002.
  3. Техническая документация MSDN.

Примеры классов.

  • Excel Event Provider

Понравилась статья? Поделить с друзьями:
  • Переформатить word в pdf
  • Переформатировать фото в word
  • Переформатировать xml в word
  • Переформатировать xml в excel онлайн
  • Переформатировать xlsx в excel