Excel vba target value

Содержание

  1. Worksheet.Change event (Excel)
  2. Syntax
  3. Parameters
  4. Return value
  5. Remarks
  6. Example
  7. Support and feedback
  8. Событие Worksheet.Change (Excel)
  9. Синтаксис
  10. Параметры
  11. Возвращаемое значение
  12. Замечания
  13. Пример
  14. Поддержка и обратная связь
  15. VBA Excel. Событие Worksheet.SelectionChange
  16. Синтаксис события Worksheet.SelectionChange
  17. Примеры кода с Worksheet.SelectionChange
  18. Пример разработчика
  19. Выбор одной отдельной ячейки
  20. Выбор диапазона с заданной ячейкой
  21. Выбор ячейки в заданной строке
  22. Ввод даты в ячейку первого столбца
  23. Пример без отслеживания Target
  24. Excel VBA
  25. Worksheet Change Event, Excel VBA

Worksheet.Change event (Excel)

Occurs when cells on the worksheet are changed by the user or by an external link.

Syntax

expression.Change (Target)

expression A variable that represents a Worksheet object.

Parameters

Name Required/Optional Data type Description
Target Required Range The changed range. Can be more than one cell.

Return value

Nothing

This event does not occur when cells change during a recalculation. Use the Calculate event to trap a sheet recalculation.

Example

The following code example changes the color of changed cells to blue.

The following code example verifies that, when a cell value changes, the changed cell is in column A, and if the changed value of the cell is greater than 100. If the value is greater than 100, the adjacent cell in column B is changed to the color red.

The following code example sets the values in the range A1:A10 to be uppercase as the data is entered into the cell.

Support and feedback

Have questions or feedback about Office VBA or this documentation? Please see Office VBA support and feedback for guidance about the ways you can receive support and provide feedback.

Источник

Событие Worksheet.Change (Excel)

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

Синтаксис

expression. Изменение (целевой объект)

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

Параметры

Имя Обязательный или необязательный Тип данных Описание
Target (Целевое значение) Обязательный Диапазон Измененный диапазон. Может быть несколько ячеек.

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

Nothing

Замечания

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

Пример

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

В следующем примере кода проверяется, что при изменении значения ячейки измененная ячейка находится в столбце A, а также если измененное значение ячейки больше 100. Если значение больше 100, смежная ячейка в столбце B изменяется на красный цвет.

В следующем примере кода значения в диапазоне A1:A10 задаются в верхнем регистре при вводе данных в ячейку.

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

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

Источник

VBA Excel. Событие Worksheet.SelectionChange

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

Синтаксис события Worksheet.SelectionChange

Синтаксис процедуры, выполнение которой инициируется событием Worksheet.SelectionChange:

Эта процедура VBA Excel запускается при смене на рабочем листе выделенного диапазона (SelectionChange). Она должна быть размещена в модуле рабочего листа Excel, смена выбранного диапазона ячеек которого будет инициировать ее запуск.

Шаблон процедуры можно скопировать и вставить в модуль рабочего листа, но не обязательно. Если открыть модуль нужного листа, выбрать в левом верхнем поле объект Worksheet , шаблон процедуры будет добавлен автоматически:

У объекта Worksheet есть и другие события, которые можно выбрать в правом верхнем поле модуля рабочего листа. Процедура с событием SelectionChange добавляется по умолчанию.

Примеры кода с Worksheet.SelectionChange

Пример разработчика

Замечательный пример дан на сайте разработчика:

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

Эта процедура работает и при выборе ячейки через адресную строку (слева над обозначениями столбцов), и при выборе из кода VBA Excel, например:

Выбор одной отдельной ячейки

Инициируем выполнение основных операторов процедуры с событием Worksheet.SelectionChange выбором одной отдельной ячейки:

Основной оператор MsgBox «Выбрана ячейка E5» будет выполнен при выборе ячейки E5.

Примечание:
В условии примера используется свойство Address переменной Target , так как в прямом выражении Target = Range(«E5») по умолчанию сравниваются значения диапазонов. В результате этого, при выборе другой ячейки со значением, совпадающим со значением ячейки E5, равенство будет истинным и основные операторы будут выполнены, а при выборе более одной ячейки, будет сгенерирована ошибка.

Выбор диапазона с заданной ячейкой

Выполнение основных операторов процедуры при вхождении заданной ячейки в выбранный диапазон:

Основной оператор MsgBox «Ячейка B3 входит в выбранный диапазон» будет выполнен при выделении диапазона, в который входит ячейка B3, в том числе и при выделении одной этой ячейки.

Выбор ячейки в заданной строке

Инициируем выполнение основных операторов процедуры с событием Worksheet.SelectionChange выбором любой отдельной ячейки во второй строке:

Дополнительный оператор If Target.Count > 1 Then Exit Sub необходим для выхода из процедуры при выделении более одной ячейки. Причина: при выделении произвольного диапазона, ограниченного сверху второй строкой, выражение Target.Row = 2 будет возвращать значение True , и операторы в блоке If . End If будут выполнены.

Ввод даты в ячейку первого столбца

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

Этот код VBA может быть полезен при ведении реестра, базы данных на листе Excel с записью текущей даты в первой колонке.

Условие If Target.Count > 1 Or Target.Row = 1 Or Target.Row = ActiveSheet.Rows.Count Then Exit Sub завершает процедуру при выборе более одной ячейки, при выборе ячейки A1 и при выборе последней ячейки первого столбца.

Выбор ячейки A1 приводит к ошибке при проверке условия Target.Offset(-1, 0) <> «» , так как происходит выход за границы диапазона рабочего листа.

Ошибка выхода за пределы рабочего листа происходит и при проверке условия Target.Offset(1, 0) = «» , если выбрать последнюю ячейку первой колонки.

Примечание:
Текущая дата будет введена в следующую пустую ячейку первого столбца при переходе к ней от заполненной в том числе нажатием клавиши «Enter».

Пример без отслеживания Target

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

Источник

Excel VBA

Worksheet Change Event, Excel VBA

User Rating: 5 / 5

Worksheet Change Event in VBA and Preventing Event Loops

Related Links:

Contents:

Worksheet_Change Event:

You can auto run a VBA code, when content of a worksheet cell changes, with the Worksheet_Change event. The change event occurs when cells on the worksheet are changed either by the user, or by any VBA application or by an external link, but not when a cell changes due to recalculation as a result from formula or due to format change. For changes made by calculation, use Worksheet_Calculate event.

Worksheet change procedure is installed with the worksheet, ie. it must be placed in the code module of the appropriate Sheet object. To create a worksheet change event: use the Visual Basic Editor -> in the Project Explorer, double click on the appropriate sheet (under ‘Microsoft Excel Objects’ which is under the VBAProject/name of your workbook) -> in the Code window, select «Worksheet» from the left-side «General» drop-down menu and then select «Change» from the right-side «Declarations» drop-down menu. You will get a procedure «shell» in the code window as follows:

Private Sub Worksheet_Change(ByVal Target As Range)

Target is a parameter of data type Range (ie. Target is a Range Object). It refers to the changed Range and can consist of one or multiple cells. If Target is in the defined Range, and its value or content changes, it will trigger the vba procedure. If Target is not in the defined Range, nothing will happen in the worksheet. In this manner, you can limit the events to a particular range for both the Change and SelectionChange events. This can be done in multiple ways:

Using Target Address. Trigger the procedure, if a single cell (A5) value is changed:

If Target.Address = «$A$5» Then MsgBox «Success»

If Target.Address = Range(«$A$5»).Address Then MsgBox «Success»

If Target.Address = Range(«A5»).Address Then MsgBox «Success»

Using Target Address. If cell (A1) or cell (A3) value is changed:

If Target.Address = «$A$1» Or Target.Address = «$A$3» Then MsgBox «Success»

Using Target Address. If any cell(s) value other than that of cell (A1) is changed:

If Target.Address <> «$A$1» Then MsgBox «Success»

The following use of Target.Address is not correct, and the code will not run:

If Target.Address = «$a$5» Then MsgBox «Success»

If Target.Address = «A1» Then MsgBox «Success»

If Target.Address = «$A$1:$A$10» Then MsgBox «Success»

If Target.Address = Range(«$A$1:$A$10») Then MsgBox «Success»

Note : Target.Address should be an absolute reference [unless used as Range(«A5»).Address — see above] and in Caps. Use this to run code when content of a single cell is changed or when any cell(s) other than a specific cell is changed.

Trigger the procedure, if any cell in a column(s) is changed, say for any change in a cell in column B or column C:

If Target.Column = 2 Or Target.Column = 3 Then MsgBox «Success»

Intersect method for a single cell. If Target intersects with the defined Range of A1 ie. if cell (A1) value is changed, the code is triggerred:

If Not Application.Intersect(Target, Range(«A1»)) Is Nothing Then MsgBox «Success»

Trigger the procedure, if at least one cell of Target is A1,B2,C3:

If Not Application.Intersect(Target, Range(«A1,B2,C3»)) Is Nothing Then MsgBox «Success»

At least one cell of Target is within the range C5:D25:

If Not Application.Intersect(Target, Me.Range(«C5:D25»)) Is Nothing Then MsgBox «Success»

If you want the code to run when only a single cell in Range(«C1:C10») is changed and do nothing if multiple cells are changed:

Private Sub Worksheet_Change(ByVal Target As Range)

If Intersect(Target, Range(«C1:C10»)) Is Nothing Or Target.Cells.Count > 1 Then

End Sub

Preventing Event Loops with Application.EnableEvents = False

Example of a recursive loop code:

Private Sub Worksheet_Change(ByVal Target As Range)

If Not Application.Intersect(Target, Range(«A1:A10»)) Is Nothing Then

Range(«A5»).Value = Range(«A5»).Value + 1

End Sub

Recursive Event Loop:

If, at each runtime, the worksheet_change event changes the content of a cell which itself is part of the Target Range (ie. which triggers the change event), it will result in reprocessing the change event repeatedly. Recursion is the process of repeating in a similar way viz. when the procedure calls itself. Refer to above example of a recursive loop code, if any cell content in Range(«A1:A10») is changed by the user, the cell A5 value will change and increment by 1; this will again trigger the change event [because of change in value of cell A5 which is in the Target Range(«A1:A10»)] and will in turn change the cell A5 value by incrementing it by 1; and then this change in cell A5 will again trigger the change event and change the cell A5 value by incrementing it by 1; and so on. This will result in a recursive loop which might result in a ‘Out Of Stack Space’ untrappable error, or depending on the Excel setting, the loop might terminate at a threshold limit of say 100. To prevent this, enter the following at the beginning of the code: Application.EnableEvents = False. This means that any change made by the VBA code will not trigger any event and will not enable restarting the worksheet_change event. EnableEvents is not automatically changed back to True, this should be specifically done in your code, by adding the following line at the end of the code: Application.EnableEvents = True. Meanwhile, if during runtime, your code encounters an error, you will need an ErrorHandler (to change EnableEvents back to True) because events have been disabled in the beginning of the code. This can be done as follows.

ErrorHandler, Example 1:

Private Sub Worksheet_Change(ByVal Target As Range)

‘on the occurrence of an error procedure flow is directed to the error-handling routine (ie. ErrHandler) which handles the error
On Error GoTo ErrorHandler

‘to prevent recursion — so that any change made by code will not trigger an event to restart the Worksheet_Change event

‘on changing cell A1 or B1, go to ErrorHandler which reverts EnableEvents to True & then exit sub

If Target.Address = «$A$1» Or Target.Address = «$B$1» Then GoTo ErrorHandler

‘if value of any cell in column 1 or 2 is changed

If Target.Column = 1 Or Target.Column = 2 Then

‘if changed cell value is numeric ie. new value is not text

If IsNumeric(Target) Then

‘increment cell B2 value by 1

Range(«B2»).Value = Range(«B2»).Value + 1

‘EnableEvents is not automatically changed back to True & hence this needs to be done specifically at the end of the code before exit.

‘because an exit statement (ex. Exit Sub) is not placed above, the error-handling routine will also execute when there is no error.

End Sub

ErrorHandler, Example 2:

Private Sub Worksheet_Change(ByVal Target As Range)

On Error Resume Next ‘skip all run-time errors

If Target.Address = «$A$1» Or Target.Address = «$B$1» Then Exit Sub

If Target.Column = 1 Or Target.Column = 2 Then

If IsNumeric(Target) Then

Range(«B2»).Value = Range(«B2»).Value + 1

On Error GoTo 0 ‘Turn off error trapping and re-allow run time errors

End Sub

On Error Statements explained:

On Error Resume Next: Specifies that when a run-time error occurs, control goes to the statement immediately following the statement where the error occurred, and execution continues from that point.

The On Error GoTo 0 statement turns off error trapping. It disables enabled error handler in the current procedure and resets it to Nothing.

On Error GoTo Line: Enables the error-handling routine that starts at the specified Line. The On Error GoTo statement traps all errors, regardless of the exception class.

Источник

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

Синтаксис процедуры, выполнение которой инициируется событием Worksheet.SelectionChange:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

‘Операторы процедуры

End Sub

Эта процедура VBA Excel запускается при смене на рабочем листе выделенного диапазона (SelectionChange). Она должна быть размещена в модуле рабочего листа Excel, смена выбранного диапазона ячеек которого будет инициировать ее запуск.

Аргумент Target — это новый выбранный диапазон на рабочем листе.

Шаблон процедуры можно скопировать и вставить в модуль рабочего листа, но не обязательно. Если открыть модуль нужного листа, выбрать в левом верхнем поле объект Worksheet, шаблон процедуры будет добавлен автоматически:

Выбор события Worksheet.SelectionChange в модуле рабочего листа

У объекта Worksheet есть и другие события, которые можно выбрать в правом верхнем поле модуля рабочего листа. Процедура с событием SelectionChange добавляется по умолчанию.

Примеры кода с Worksheet.SelectionChange

Пример разработчика

Замечательный пример дан на сайте разработчика:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

   With ActiveWindow

      .ScrollRow = Target.Row

      .ScrollColumn = Target.Column

   End With

End Sub

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

Эта процедура работает и при выборе ячейки через адресную строку (слева над обозначениями столбцов), и при выборе из кода VBA Excel, например:

Выбор одной отдельной ячейки

Инициируем выполнение основных операторов процедуры с событием Worksheet.SelectionChange выбором одной отдельной ячейки:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    If Target.Address = «$E$5» Then

        MsgBox «Выбрана ячейка E5»

    End If

End Sub

Основной оператор MsgBox "Выбрана ячейка E5" будет выполнен при выборе ячейки E5.

Примечание:
В условии примера используется свойство Address переменной Target, так как в прямом выражении Target = Range("E5") по умолчанию сравниваются значения диапазонов. В результате этого, при выборе другой ячейки со значением, совпадающим со значением ячейки E5, равенство будет истинным и основные операторы будут выполнены, а при выборе более одной ячейки, будет сгенерирована ошибка.

Выбор диапазона с заданной ячейкой

Выполнение основных операторов процедуры при вхождении заданной ячейки в выбранный диапазон:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    If Not Intersect(Target, Range(«B3»)) Is Nothing Then

        MsgBox «Ячейка B3 входит в выбранный диапазон»

    End If

End Sub

Основной оператор MsgBox "Ячейка B3 входит в выбранный диапазон" будет выполнен при выделении диапазона, в который входит ячейка B3, в том числе и при выделении одной этой ячейки.

Выбор ячейки в заданной строке

Инициируем выполнение основных операторов процедуры с событием Worksheet.SelectionChange выбором любой отдельной ячейки во второй строке:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    If Target.Count > 1 Then Exit Sub

        If Target.Row = 2 Then

            MsgBox «Выбрана ячейка во второй строке»

        End If

End Sub

Дополнительный оператор If Target.Count > 1 Then Exit Sub необходим для выхода из процедуры при выделении более одной ячейки. Причина: при выделении произвольного диапазона, ограниченного сверху второй строкой, выражение Target.Row = 2 будет возвращать значение True, и операторы в блоке If ... End If будут выполнены.

Ввод даты в ячейку первого столбца

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

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    If Target.Count > 1 Or Target.Row = 1 Or Target.Row = ActiveSheet.Rows.Count Then Exit Sub

        If Target.Column = 1 And Target.Offset(1, 0) <> «» And Target.Offset(1, 0) = «» Then

            Target = Format(Now, «DD.MM.YYYY»)

        End If

End Sub

Этот код VBA может быть полезен при ведении реестра, базы данных на листе Excel с записью текущей даты в первой колонке.

Условие If Target.Count > 1 Or Target.Row = 1 Or Target.Row = ActiveSheet.Rows.Count Then Exit Sub завершает процедуру при выборе более одной ячейки, при выборе ячейки A1 и при выборе последней ячейки первого столбца.

Выбор ячейки A1 приводит к ошибке при проверке условия Target.Offset(-1, 0) <> "", так как происходит выход за границы диапазона рабочего листа.

Ошибка выхода за пределы рабочего листа происходит и при проверке условия Target.Offset(1, 0) = "", если выбрать последнюю ячейку первой колонки.

Примечание:
Текущая дата будет введена в следующую пустую ячейку первого столбца при переходе к ней от заполненной в том числе нажатием клавиши «Enter».

Пример без отслеживания Target

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

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    If [B1] > 100 Then

        [A1].Interior.Color = vbGreen

    Else

        [A1].Interior.Color = vbBlue

    End If

End Sub

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


Worksheet Change Event in VBA and Preventing Event Loops

Related Links: 

Excel VBA Events, Event Handlers, Trigger a VBA Macro.

Worksheet Selection Change Event, Excel VBA.

————————————————————————   

Contents:

Worksheet_Change Event

Preventing Event Loops with Application.EnableEvents = False

————————————————————————   

Worksheet_Change Event:

You can auto run a VBA code, when content of a worksheet cell changes, with the Worksheet_Change event. The change event occurs when cells on the worksheet are changed either by the user, or by any VBA application or by an external link, but not when a cell changes due to recalculation as a result from formula or due to format change. For changes made by calculation, use Worksheet_Calculate event.

Worksheet change procedure is installed with the worksheet, ie. it must be placed in the code module of the appropriate Sheet object. To create a worksheet change event: use the Visual Basic Editor -> in the Project Explorer, double click on the appropriate sheet (under ‘Microsoft Excel Objects’ which is under the VBAProject/name of your workbook) -> in the Code window, select «Worksheet» from the left-side «General» drop-down menu and then select «Change» from the right-side «Declarations» drop-down menu. You will get a procedure «shell» in the code window as follows:

Private Sub Worksheet_Change(ByVal Target As Range)

End Sub

Target is a parameter of data type Range (ie. Target is a Range Object). It refers to the changed Range and can consist of one or multiple cells. If Target is in the defined Range, and its value or content changes, it will trigger the vba procedure. If Target is not in the defined Range, nothing will happen in the worksheet. In this manner, you can limit the events to a particular range for both the Change and SelectionChange events. This can be done in multiple ways:

Using Target Address. Trigger the procedure, if a single cell (A5) value is changed:

If Target.Address = «$A$5» Then MsgBox «Success»

If Target.Address = Range(«$A$5»).Address Then MsgBox «Success»

If Target.Address = Range(«A5»).Address Then MsgBox «Success»

Using Target Address. If cell (A1) or cell (A3) value is changed:

If Target.Address = «$A$1» Or Target.Address = «$A$3» Then MsgBox «Success»

Using Target Address. If any cell(s) value other than that of cell (A1) is changed:

If Target.Address <> «$A$1» Then MsgBox «Success»

The following use of Target.Address is not correct, and the code will not run:

If Target.Address = «$a$5» Then MsgBox «Success»

If Target.Address = «A1» Then MsgBox «Success»

If Target.Address = «$A$1:$A$10» Then MsgBox «Success»

If Target.Address = Range(«$A$1:$A$10») Then MsgBox «Success»

Note: Target.Address should be an absolute reference [unless used as Range(«A5»).Address — see above] and in Caps. Use this to run code when content of a single cell is changed or when any cell(s) other than a specific cell is changed.

Trigger the procedure, if any cell in a column(s) is changed, say for any change in a cell in column B or column C:

If Target.Column = 2 Or Target.Column = 3 Then MsgBox «Success»

Intersect method for a single cell. If Target intersects with the defined Range of A1 ie. if cell (A1) value is changed, the code is triggerred:

If Not Application.Intersect(Target, Range(«A1»)) Is Nothing Then MsgBox «Success»

Trigger the procedure, if at least one cell of Target is A1,B2,C3:

If Not Application.Intersect(Target, Range(«A1,B2,C3»)) Is Nothing Then MsgBox «Success»

At least one cell of Target is within the range C5:D25:

If Not Application.Intersect(Target, Me.Range(«C5:D25»)) Is Nothing Then MsgBox «Success»

If you want the code to run when only a single cell in Range(«C1:C10») is changed and do nothing if multiple cells are changed:

Private Sub Worksheet_Change(ByVal Target As Range)

If Intersect(Target, Range(«C1:C10»)) Is Nothing Or Target.Cells.Count > 1 Then

Exit Sub

Else

MsgBox «Success»

End If

End Sub

Preventing Event Loops with Application.EnableEvents = False

Example of a recursive loop code:

Private Sub Worksheet_Change(ByVal Target As Range)

If Not Application.Intersect(Target, Range(«A1:A10»)) Is Nothing Then

Range(«A5»).Value = Range(«A5»).Value + 1

End If

End Sub

Recursive Event Loop:

If, at each runtime, the worksheet_change event changes the content of a cell which itself is part of the Target Range (ie. which triggers the change event), it will result in reprocessing the change event repeatedly.  Recursion is the process of repeating in a similar way viz. when the procedure calls itself. Refer to above example of a recursive loop code, if any cell content in Range(«A1:A10») is changed by the user, the cell A5 value will change and increment by 1; this will again trigger the change event [because of change in value of cell A5 which is in the Target Range(«A1:A10»)] and will in turn change the cell A5 value by incrementing it by 1; and then this change in cell A5 will again trigger the change event and change the cell A5 value by incrementing it by 1; and so on. This will result in a recursive loop which might result in a ‘Out Of Stack Space’ untrappable error, or depending on the Excel setting, the loop might terminate at a threshold limit of say 100. To prevent this, enter the following at the beginning of the code: Application.EnableEvents = False. This means that any change made by the VBA code will not trigger any event and will not enable restarting the worksheet_change event. EnableEvents is not automatically changed back to True, this should be specifically done in your code, by adding the following line at the end of the code: Application.EnableEvents = True. Meanwhile, if during runtime, your code encounters an error, you will need an ErrorHandler (to change EnableEvents back to True) because events have been disabled in the beginning of the code. This can be done as follows. 

ErrorHandler, Example 1:

Private Sub Worksheet_Change(ByVal Target As Range)

‘on the occurrence of an error procedure flow is directed to the error-handling routine (ie. ErrHandler) which handles the error
On Error GoTo ErrorHandler
 

‘to prevent recursion — so that any change made by code will not trigger an event to restart the Worksheet_Change event 

Application.EnableEvents = False

‘on changing cell A1 or B1, go to ErrorHandler which reverts EnableEvents to True & then exit sub

If Target.Address = «$A$1» Or Target.Address = «$B$1» Then GoTo ErrorHandler

‘if value of any cell in column 1 or 2 is changed

If Target.Column = 1 Or Target.Column = 2 Then

‘if changed cell value is numeric ie. new value is not text

If IsNumeric(Target) Then

‘increment cell B2 value by 1

Range(«B2»).Value = Range(«B2»).Value + 1

End If

End If

‘EnableEvents is not automatically changed back to True & hence this needs to be done specifically at the end of the code before exit.

‘because an exit statement (ex. Exit Sub) is not placed above, the error-handling routine will also execute when there is no error.

ErrorHandler:

Application.EnableEvents = True

End Sub

ErrorHandler, Example 2:

Private Sub Worksheet_Change(ByVal Target As Range)

On Error Resume Next  ‘skip all run-time errors

If Target.Address = «$A$1» Or Target.Address = «$B$1» Then Exit Sub

Application.EnableEvents = False

 
If Target.Column = 1 Or Target.Column = 2 Then

If IsNumeric(Target) Then

Range(«B2»).Value = Range(«B2»).Value + 1

End If

End If

Application.EnableEvents = True

On Error GoTo 0  ‘Turn off error trapping and re-allow run time errors

End Sub

On Error Statements explained:

On Error Resume Next: Specifies that when a run-time error occurs, control goes to the statement immediately following the statement where the error occurred, and execution continues from that point.

The On Error GoTo 0 statement turns off error trapping.  It disables enabled error handler in the current procedure and resets it to Nothing.

On Error GoTo Line: Enables the error-handling routine that starts at the specified Line. The On Error GoTo statement traps all errors, regardless of the exception class.

 

В ходе экспериментов написал такое:  

  Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)  
  Target.Value = Target.Value + 1  
End Sub  

  Нажимаешь на любую ячейку и в ней число увеличивается на единичку.  
А как сделать, чтобы — выделил несколько ячеек — и во всех числа увеличились на единичку?  
Я делал For each — Next в разных комбинациях, не получилось.  
(Это не для работы, это мне просто для эрудиции).  
Спасибо.

 

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

 

на первый вопрос:  
Private Sub Worksheet_SelectionChange(ByVal Target As Range)  
For Each tt In Target  
tt.Value = tt.Value + 1  
Next  
End Sub  
По второму:  
События Worksheet_SelectionChange в этом случае, как Вы уже заметили, не происходит.  
Могу порекомедовать события Worksheet_BeforeRightClick или Worksheet_BeforeDoubleClick с тем же кодом.

 
 

а можно отловить движение мышки? Чтобы просто водить мышкой не нажимая на нее, а в ячейках, где прошелся курсор, прибавлялись единички. Наверно есть такая фенька.(Пардон, функция типа MoveMouse или подобная).

 

Через WinAPI (пример дать не могу, т.к. сам не знаю)))

 

{quote}{login=dsapa}{date=03.07.2008 05:46}{thema=}{post}а можно отловить движение мышки? Чтобы просто водить мышкой не нажимая на нее, а в ячейках, где прошелся курсор, прибавлялись единички. Наверно есть такая фенька.(Пардон, функция типа MoveMouse или подобная).{/post}{/quote}:Жесть! Может еще и взглядом? Посмотрел на ячейку, а там — бац и плюсАдин

 

я пробовал с мышиным api работать(выкладывал тут) — поищите.

 
 

Всё не то.  

  Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)  

  отлавливает движение курсора на форме. А мне надо прямо на листе. Короче, пока не нашел.

 

Вот тут —

http://msoffice.nm.ru/faq/macros/winapi2.htm

— нашел такое:  

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

  Private Type POINTAPI    
   X As Long    
   Y As Long    
End Type    

  Private Declare Function GetCursorPos _    
       Lib «user32.dll» (lpPoint As POINTAPI) As Long    

  Private Sub GetRangeFromPoint()    
   Dim iPOINT As POINTAPI, iCell As Range    

     GetCursorPos iPOINT    

     Set iCell = ActiveWindow.RangeFromPoint(X:=iPOINT.X, Y:=iPOINT.Y)    

     If Not iCell Is Nothing Then    
      MsgBox «Курсор мышки находится над » & _    
      iCell.Address(External:=True), vbExclamation, «»    
   Else    
      MsgBox «Курсор мышки находится вне ячеек рабочего листа», , «»    
   End If    
End Sub  

  Только не работает. Может кто знает, как запустить прогу?  
Спасибо.

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

—  
См. приложение  
—  
ZVI

 

GRAFin

Пользователь

Сообщений: 3
Регистрация: 01.01.1970

Вот, похоже, нашел что искал! Но как применить не знаю. Ручки то кривенькие. Нужно чтоб число в ячейке при каком-либо РукиПальцевМыши(или чего еще)действии увеличивалось на 1, а так же при последующих повторах действия единичка прибавлялась . Желательно чтоб действие было простым типа щелчка мыши или сочетание клавиш. При попытке создать макрос и перенести в него текст из первого поста    
Worksheet_SelectionChange(ByVal Target As Excel.Range)  
Target.Value = Target.Value + 1  
получаю различного рода ошибки, которые описывать нет смысла. Скажу честно то, что написано в этой теме для меня темный лес, но чтоб единичка прибавлялась очень нужно. Пожалуйста, кто понимает, доходчиво объясните, как это сделать своими руками или файл, в котором такой макрос работает, выложите. У меня вроде Office10, если это имеет значение.

 

Юрий М

Модератор

Сообщений: 60570
Регистрация: 14.09.2012

Контакты см. в профиле

В модуль листа:  
Private Sub Worksheet_SelectionChange(ByVal Target As Range)  
   If Target.Cells.Count > 1 Then Exit Sub  
   If Not Intersect(Target, Range(«A1:A10»)) Is Nothing Then  
       If Not IsNumeric(Target) Then  
           Exit Sub  
       Else  
           Target = Target + 1  
       End If  
   End If  
End Sub  
Контролируется диапазон А1:А10

 

GRAFin

Пользователь

Сообщений: 3
Регистрация: 01.01.1970

{quote}{login=Юрий М}{date=03.08.2010 11:30}{thema=}{post}В модуль листа:  
Private Sub Worksheet_SelectionChange(ByVal Target As Range)  
   If Target.Cells.Count > 1 Then Exit Sub  
   If Not Intersect(Target, Range(«A1:A10»)) Is Nothing Then  
       If Not IsNumeric(Target) Then  
           Exit SubB  
       Else  
           Target = Target + 1  
       End If  
   End If  
End Sub  
Контролируется диапазон А1:А10{/post}{/quote}    

  Спасибо! Только что дальше? Что нужно нажать чтоб макрос сохранился и начал работать? Если просто закрыть Visual Basic, то ничего не происходит. И что значит «Контролируется диапазон А1:А10»? И при каком действии(щелчок,клавиши) будет прибавляться единичка?

 

Юрий М

Модератор

Сообщений: 60570
Регистрация: 14.09.2012

Контакты см. в профиле

Просто закройте редактор. Макрос сработает при активации любой ячейки в указанном диапазоне.

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

Увеличение значения ячейки по двойному клику подойдет?

 

GRAFin

Пользователь

Сообщений: 3
Регистрация: 01.01.1970

#18

04.08.2010 02:40:54

ZVI большое спасибо! Это то что нужно. Юрий М и тебе спасибо, но уже больше ничего проверять не буду раз все и так работает. Наверно я что то делал все равно не так.

ThreeWave
Events And Event Procedures In VBA

This page describes Events and Event Procedures in VB and/or VBA.
ShortFadeBar

Event programming is a very powerful tool that you can use within your VBA code to monitor user actions, take appropriate action
when a user does something, or monitor the state of the application as it changes. If you are programming with your own custom classes, you
can extend the functionality of these classes by defining and raising your own custom events, broadcasting the event message to any
object that is listening for events from your class.

Events and Event Procedures were introduced in Excel97. Earlier versions of Excel do not support events. Events and event
procedures are the same for versions 97 through 2007. No significant changes have been made to the event model since its
introduction in Excel97. A few new events have been added, but the overall structure of the event system is unchanged.

An Event is an action initiated either by user action or by other VBA code. An Event Procedure
is a Sub procedure that you write, according to the specification of the event, that is called
automatically by Excel when an event occurs. For example, a Worksheet object has an event named
Change. If you have properly programmed the event procedure for the Change
event, Excel will automatically call that procedure, always named Worksheet_Change and always in the code module of the worksheet,
whenever the value of any cell on the worksheet is changed by user input or by other VBA code (but not if the change in value is
a result of a formula calculation). You can write code in the Worksheet_Change event procedure to take
some action depending on which cell was changed or based upon the newly changed value. (The
Worksheet_Change event might more properly be called Worksheet_AfterChange
since it is called after the cell(s) has been changed. There is no way to access the previous value of the cell before it was changed.)
For the Change event, the system will pass you a Range reference named Target that refers to the
cell(s) being changed. You can examine that variable to determine if your code needs to carry out some action or whether it can ignore
the change and get out with an Exit Sub statement. See the Sample Event Procedure section below.

The events and their procedure declarations are fixed. You must not alter the name or parameter list of an event procedure. The VBA
Editor will automatically insert the correct procedure declaration. Do not alter this. You cannot create new events for an Excel
object. The events are «hard coded» into the object, such as a Worksheet, and may not be changed. (You can, however, create custom
events for your own classes. See the Creating Your Own Events In Your Class Modules section later in this article.

There are many events that are defined in a Worksheet object, the Workbook object, and the Excel Application object itself.
On this page, we will cover Application events in only in general terms, but not in much detail since they require a different
coding model. (See Application Events for a discussion of Application events.) An event is said to be
raised when the action that initiates the event occurs and the application automatically sends a signal to all
components connected to event-generating object (e.g, a Worksheet) indicating that the event has occured. An Event Procedure
is a VBA Sub procedure that is executed automatically by Excel when the event is raised. It is important to remember that
in addition to user input, events may run as the results of actions taken by other VBA code. There is no direct way to determine whether
the cause of the event was user input or VBA code. You should write your events procedures such that this distinction does not matter.
Since VBA can cause an event procedure to run, it is possible that your code may end up in a loop. See Preventing Event Loops
later in this article for information about event loops and how to avoid them with proper coding.

For the Change event in particular, it should be noted that this is triggered when a cell
is changed by user action or by other VBA code, but is not raised if the value of a cell is changed as a result of formula calculation.

EVENTS — On this page, we will be discussing only Excel’s events related to Sheets, Workbooks, and the Application,
which are completely independent of the events for user forms and controls on user forms. The EnableEvents
setting, discussed later, has no effect on events of user forms or controls on user forms. For information about supressing events
for controls on a form, see Suppressing Events In UserForms. Events on Charts are a special
case of events and need special code handling.

OBJECT MODULES — Everything related to event handling — the definition of event procedures, creating a
WithEvents variable to receive events, and creating your own events — takes place
within Object Modules. Besides setting the EnableEvents property, there is
nothing related to events in a standard code module; every thing is in an object module. An Object Module is
any one of the following:

A Class module.
A Sheet module (either a worksheet or a chart sheet).
The ThisWorkbook module
The code module behind a User Form

SectionBreak

You can use the Object Browser in the VBA Editor to determine what events are avaiable for the three objects that generate events — the Worksheet,
the Workbook, and the Application. (See the notes on ChartObjects and Charts in the blue box in the Event Hierarchy section below.)
Open the Object Browser in the VBA Editor (press F2 or choose Object Browser from the View menu.
In the Classes list, scroll down and select Worksheet. Right-click anywhere in the primary window and choose Group Members on the pop up menu.
Then scroll down in the Members Of «Worksheet» list until you see items with yellow lightening bolts next to them.
These are the events for the Worksheet objects. Do the same for the Workbook and
Application objects. For help on a particular object or event, select it in the Object Browser and
press F1 for Help on that topic (note that not all events are documented — you may have to access event information by going through
the object to which the event belongs.

Another method to determine what events are available is to create an empty class module, and enter the following code:

Dim WithEvents App As Application
Dim WithEvents WB As Workbook
Dim WithEvents WS As Worksheet
Dim WithEvents CHT as Chart

Then, select each of App, WB, WS, and CHT
elements in the left side dropdown at the top of the code window. All the events for the selected item in the left dropdown will be listed in the
right dropdown. If you see an item of interest, let go of the mouse button and the VBA editor will insert that event’s
procedure declaration in the code module. The declaration will tell you what the parameters for the event are, but you will still need
to use Help to obtain a description of the meaning and usage of the parameters. Event procedures must be declared exactly as they are defined.
This is why it is good practice to let the VBA Editor insert your procedure shell. Do not change any of the VBA generated code.

SectionBreak

The easiest way to start with events and event procedures is to allow the VBA editor to build the shell code for you. In Excel,
right click one of the sheet tabs at the bottom of the main window and choose View Code from the pop-up menu. This will
open the VBA Editor to the code module associated with that worksheet. In that code window you will see two dropdown boxes at
the top of the code window, as shown below:
EventProc1
Change the (General) setting to Worksheet and then change SeletionChange to Change. This will add
the event procedure declaration for the Change event to the code module, as shown below:
EventProc2
Within the Worksheet_Change procedure, you can add any code that you want to take place when a cell value
is changed. This event is raised automatically by Excel when a cell’s value is changed either by user input or by other VBA code. It
is not raised if the value of the cell is changed by a formula calculation in that cell. The Target parameter
is a Range type object referring to the cell(s) that were changed. To use other events of the worksheet, select the event in the right hand
dropdown at the top of the code pane. When you change this setting, VBA will insert the procedure shell in the code module for you,
ensuring that the procedure is properly declared. Under no circumstances should you change anything in the Sub
statement created by VBA. Doing so may cause the event not to work.

SectionBreak

For sheet (both worksheet and chart sheet) level events, the event procedure code must be placed in the Sheet module associated with that sheet.
Workbook level events must be placed in the ThisWorkbook code module. If an event procedure is not in the proper module, VBA will
not be able to find it and the event code will not be executed. It is generally accepted good programming practice that only event
procedures be included in the sheet modules and the ThisWorkbook modules. If you have no compelling reason to put other code in the
sheet or ThisWorkbook modules (and there are a few quite legitimate reasons to do so, but they are beyond the scope of this article)
you should put it in a standard code module.

There is no built in object to catch Application events. You can do either of two things, as described
below, in the Application Events section of this page: use the ThisWorkbook code module or use a dedicated class module.
Placing the code in the ThisWorkbook module requires slightly less code, but I prefer to use a dedicated class module for
organizational purposes — one module for each logical function group. Neither method is particularly better than the other.
Use the method that is easiest for you.

SectionBreak

As noted above, events are generated by:

  • The Application
  • The Workbook
  • The Worksheets
  • Charts

If a Chart is a Chart Sheet, then it follows the rules of a Worksheet, except that its events are no replicated by the Workbook
or Application objects. If a Chart is part of a ChartObject embedded on a worksheet, it follows its own rules. See
the Charts And ChartObjects subsection, in blue, later in the article.

An object contains events for itself as well as replications of events for its subordinate objects. Since the Worksheet
is at the bottom of the hierarchy and has no subordinate objects (at least no objects that have events, that have events), so the Worksheet contains
only events for itself. For example, each worksheet has an event named Worksheet_Change that is triggered when
a cell on that worksheet is changed either by user input or by VBA (but not if the change is the result of a calculation). Each worksheet’s
Worksheet_Change event is exclusive to that sheet.

SUBORDINATE AND SUPERIOR OBJECTS — In the article, we will use the term Subordinate object to refer to an object below some other
object in the hierarchy of event-generating objects. The term Superior object refers to an object that is higher up in the
hierarchy of event-generating objects. For example, Worksheet is a subordinate object, to both the
Workbook and Application object. The Workbook
is both a subordinate and superior object; it is a superior object to the Worksheet object and is
a subordinate object to the Application object. Though Charts (either Chart Sheets or Chart objects
in ChartObject objects on a worksheet) do raise events, they don’t fit into the hierarchy. As far as the event generation object
model is concerned, Charts are orphans. See the CHARTS AND CHARTOBJECTS notes later in this section.

The Workbook object is higher up in the hierarchy. Worksheets are subordinate to the workbook. Therefore, the
Workbook object has events for itself, such as BeforeSave as well has versions of all
the events of the Worksheet class. For example, every worksheet has a Worksheet_Change event
that is called in response to changes on that worksheet. The Workbook object also has a
Workbook_SheetChange event that is called when any cell on any worksheet is changed. When a cell value is changed,
both the worksheet’s Worksheet_Change and the workbook’s Workbook_SheetChange events
are triggered, and a reference to the changed cell(s) is passed to event procedure.

Since the Application object sits at the top of the hierarchy, it contains events for itself, such as App_NewWorkbook
as well as events for all Workbook events and all Worksheet events. Since every event «rolls up» to the Application
object, it would be possible to write all the event code within the structure of Application Events. However, this would be very cumbersome
and would not take advantage of the modularization that separates event drivers (Application, Workbook, and Worksheet) provide. The code would
get very complicated very quickly.

CHARTS AND CHARTOBJECTS — Charts do have events (although ChartObjects on a worksheet do not), but they do not fit nicely into the regular hierarchy
of the event-generating objects. If you have a Chart Sheet (as oppsosed to a Chart in a ChartObject residing on a Worksheet),
the chart sheet acts much the same way as a worksheet with respect to events, albeit with a different set of events. Moreover,
these events do not have counterparts in the Workbook object or the Application object.
Charts are kind of orphans in the grand scheme of events. A Chart object that is part of a ChartObject on a worksheet also has events,
but like the Application object, there is no ready-made container for events of Charts that are part of a ChartObject
on a sheet. Instead, you must use either of the techniques described later for the Application object
— just substitute «As Chart» for «As Application» and set the event class variable to
Sheet1.ChartObjects(«MyChart»).Chart. ChartObjects do not have events — it is the Chart object within the
ChartObject object that has the events. Events for Charts, either Chart Sheets or Charts in embedded ChartObject do not have their events
replicated in either the Workbook or the Application objects. Charts are sort of the «oddball» object of Excel’s event system.
The following code may be placed in the ThisWorkbook object module to access events of a
Chart in an embedded ChartObject object.

    Public WithEvents CHT As Chart

    Private Sub Workbook_Open()
        Set CHT = Worksheets(1).ChartObjects(1).Chart
    End Sub

    Private Sub CHT_Activate()
        MsgBox "CHT: TypeName: " & TypeName(CHT) & vbCrLf & _
            "CHT Name: '" & CHT.Name & "'" & vbCrLf & _
            "CHT Parent TypeName: " & TypeName(CHT.Parent) & vbCrLf & _
            "CHT Parent Name: " & CHT.Parent.Name
    End Sub

If you have event code in the sheet, the workbook, and the application classes, the event will be raised in all three of these objects. Even if a change
is trapped by a sheet level Worksheet_Change event, the event procedure in the Workbook and the Application will also be
raised. The order of events is from the least significant object (the Sheet) upwards through the most significant object (the Application).
You can stop the event from being triggered «upstream» (e.g., preventing the Workbook_SheetChange and the
App_SheetChange event from being raised) by setting the Application.EnableEvents
property to False. For example, in a sheet’s code module:

    Private Sub Worksheet_Change(ByVal Target As Range)
        Application.EnableEvents = False
        
        Application.EnableEvents = True
    End Sub

This code processes the cell change event at the Sheet level, but the line
Application.EnableEvents = False prevents the Worksheet and Applicaton
SheetChange events from being raised. Indeed, this line of code suppresses all events
from being raised until its value is reset to True. Note that Excel never automatically sets
Application.EnableEvents back to True
(as it does do with the ScreenUpdating property). It is up to your code, including well designed
error handling code, to ensure that Application.EnableEvents is properly reset to True.
See Error Handling In VBA for more information about error handling code.

SectionBreak

This section will examine a very simple event, the Worksheet_Change event, and illustrate
a few useful techniques you can use to determine whether your code needs to act in response to the event. The basic event code, as
generated by VBA is as follows:

    Private Sub Worksheet_Change(ByVal Target As Range)

    End Sub

As written, the event procedure does nothing — there is no code within the procedure. The Target
parameter is a Range object that refers to the cell(s) that were changed. Since Worksheet_Change runs for
every cell in the worksheet, you most likely will need to test whether Target is within some predefined
range of interest. If it is that range, you’ll do something. If Target is not in that range, you don’t
want to carry out the action of the procedure. The easiest way to do this is with the Intersect method.
Intersect returns a range of cells that are included in two ranges. For example, the Intersection of the range
A1:C3 and C3:F6 is the cell C3 since that cell
is common to both ranges. If there are no cells in common between two ranges, Intersect returns
Nothing. Thus, you can use intersect to see if Target is within the range
of interest:

    If Not Application.Intersect(Target, Me.Range("A1:C10")) Is Nothing Then
         
    Else
        
    Exit Sub

You could also use named ranges rather than hard coded cell references. This is the preferred approach.

There may be times you want to act only if a single cell was changed, and ignore it if multiple cells are changed. In that case,
you can use

    If Target.Cells.Count > 1 Then 
        
    Exit Sub

Here, if Target contains more than one cell, get out of the procedure. In a similar fashion you can test whether
Target is within a specified column or row or range of columns and rows. Any of the following code should get you
started:

    If Target.Cells.Count > 1 Then 
	    Exit Sub
    End If

    If Target.Columns >= 3 And Target.Columns <= 10 Then
    	
    Else
        Exit Sub
    End If 

    If Target.Row >= 5 And Target.Row <= 10 Then 
	    
    Else
        Exit Sub
    End If 

Since Target is a Range object, you can perform any number of tests using the vast flexibility of a Range
object to determine whether your code should act on the change or simply ignore it by calling Exit Sub.

SectionBreak

It is possible that you need to respond to the events of a specific worksheet differently than you would for other worksheets, and that
the name of the special worksheet is not known until run time (e.g., it might be a sheet added by your application). You could handle
this in the Workbook_SheetChange event, but it would require cumbersome logic to process events for
only one worksheet rather than all worksheets. A better and more elegant solution is to create a special class module and within that
module declare a variable of type Worksheet using the WithEvents keyword. For example,
suppose you want to handle events for a worksheet that is created at run time. In a standard code module, declare a
Collection object as:

    Public WSColl As Collection

Next, create a class named CWorksheetObject and insert the following code:

    Public WithEvents WS As Worksheet
Private Sub WS_Change(ByVal Target As Range) Debug.Print "Special Code For New Worksheet" End Sub

This code declares a variable named WS of type Worksheet using the
WithEvents keyword. WithEvents connects the event system to the
WS variable and lets you utilize the events of the object. Next, you would include the
event procedures for this worksheet:

    Private Sub WS_Change(ByVal Target As Range)
Debug.Print "Special Code For New Worksheet"
End Sub

Finally, you create an instance of the CWorksheetObject class and set its WS
variable to the newly created worksheet. Once the WS variable is set to a specific worksheet, the
event procedures in that class will run for events on the assigned worksheet.

    Sub TestProc()
        Dim WSObj As CWorksheetObject
        Dim WSheet As Worksheet

        If WSColl Is Nothing Then
            Set WSColl = New Collection
        End If

        Set WSObj = New CWorksheetObject
        Set WSheet = Worksheets.Add()
        WSheet.Name = "Some Name"
        Set WSObj.WS = WSheet
        WSColl.Add Item:=WSObj, key:=WSheet.Name

        
    End Sub

The TestProc procedure first declares a variable named WSObj of type
CWorksheetObject. At this point, the object exists, but its WS Worksheet
object has not yet been set to any specific workbook, so no events will fire in the class. The code then creates a new worksheet,
names that worksheet, and then sets the WSObj‘s WS object to the newly
created worksheet. Now that the WS object has been set to a specific worksheet, it will respond to
events generated by the newly created worksheet. Finally, it stores the WSObj variable in the
WSColl Collection variable so the object is not destroyed when it goes out of scope at the end
of the procedure.
Using the method above, and expanding on it to use other object types, you can simplify programming tasks that might otherwise
require much more complicated logic.

SectionBreak

There are two common ways to declare application events (though because VBA is as versatile as it is, there are many other
ways to implement Application events). The first is to declare the App variable (of type Application in
the ThisWorkbook code module. The second method is to use a dedicated code module.

In the ThisWorkbook code module, insert the following code:

    Public WithEvents App As Application

    Private Sub Workbook_Open()
        Set App = Application
    End Sub

Then, select App in the left side dropdown at the top of the ThisWorkbook code pane
and choose in the right side dropdown which of the available events you wish to use. VBA will automatically insert the
proper declarations for that event. Remember, never change the code that VBA inserts for you. If you do change it, it
is quite likely that the code will not work properly, if at all.

You can then use events for the App object such as:

    Private Sub App_NewWorkbook(ByVal Wb As Workbook)
        MsgBox "New Workbook: " & Wb.Name
    End Sub

The second approach to creating Application Events is to use a dedicated class module. Insert a class module into your project and
name the class module CExcelEvents. In that class module, enter the following code:

    Private WithEvents XLApp As Application
    
    Private Sub Class_Initialize()
        Set XLApp = Application
    End Sub

Then, change the left side dropdown at the top of the code pane to XLApp and choose an event from the right side dropdown. VBA
will automatically insert the proper procedure shell for that event. As before, do not change the code generated by VBA.

You can then define your application event procedures in the class module. For example,

Private Sub XLApp_NewWorkbook(ByVal Wb As Workbook)
    MsgBox "NewWorkbook" & Wb.Name
End Sub

The next step is to create a variable of type CExcelEvents and initialize that variable to a new instance
of CExcelEvents. In the ThisWorkbok code module, declare a variable as shown below:

    Private ExcelEvents As CExcelEvents

    Private Sub Workbook_Open()
        Set ExcelEvents = New CExcelEvents
    End Sub

Since the Class_Initialize procedure of the CExcelEvents class initializes the
XLApp variable when the class is created, we do not have to worry about initializing XLApp.
Any Application event procedures should be added to the CExcelEvents class.

Given that there are at least two method for creating an object to receive Application Events, you may be wondering which is better,
a separate class module or the ThisWorkbook module, Neither is better in any significant way. As a matter
of personal preference and coding style, I put my application events in a dedicated class module. In my opinion, this keeps to
project better organized. However, beyond that, there is no advantage to use a dedicated class module for Application events. You should
use the approach that seems most natural to your own coding style. Once you decide on a method, stick with that method across projects.
Don’t mix and match.

SectionBreak

Without proper coding, your event procedures can end up in infinite
recursive loops. Depending on your version of VBA and Excel, this may result in
an non-trappable Out Of Stack Space error or VBA will simply terminate execution when some threshold (approximately 300) number
of calls is met. Consider, for example, the following code:

    Private Sub Worksheet_Change(ByVal Target As Range)
        Target.Value = Target.Value + 1
    End Sub 

At first glance, this code may seem perfectly valid. When a cell is changed to some value by the user, the code adds one the that value,
so if a user enters 1, the code will change that to 2. However, this is not what will actually happen. When the user changes the cell to
1, the event procedure runs and changes the value to 2. This change, however, raises the Change event again
and the code will run to change the 2 to a 3. This again raises the Change event, which changes the value 3 to 4.
Yet again, the Change event runs, changing the 4 to a 5. This looping will continue until VBA aborts
the loop or you run out of stack space.

In order to prevent this runaway looping, you can use the EnableEvents property of the
Application object. When you set this property to False VBA will not raise any
events, and the example Change event will run once only for the input by the user. It will not run when
the value is changed by the VBA code. You should always be sure to set EnableEvents property back
to True to enable events to be called normally. Unlike some properties (such as ScreenUpdating),
Excel will not automatically change EnableEvents back to True. Your code must ensure that the value
is properly reset. For example, in the code that follows, the Target value is incremented once, but
since EnableEvents value is False, no subsequent Change
event is raised.

    Private Sub Worksheet_Change(ByVal Target As Range)
        Application.EnableEvents = False
        Target.Value = Target.Value + 1
        Application.EnableEvents = True
    End Sub

In some circumstances, it may not be desirable to disable all event handling using Application.EnableEvents = False.
Your application may rely on various events running when they should. You can work around this by creating a public Boolean variable, testing
that variables in your event procedure, and exiting the procedure if that variable is True. This way, you can turn off one event handler while
leaving the other event handling in place. For example, in a standard code module, declare a variable such as:

    Public AbortChangeEvent As Boolean

Then, in the Worksheet_Change event procedure, you test this variable. If it is true, you would
immediately exit the procedure, as shown in the example below.

Private Sub Worksheet_Change(ByVal Target As Range)
    If AbortChangeEvent = True Then
        Exit Sub
    End If
    
End Sub

Finally, you would disable the Worksheet_Change event by setting the AbortChangeEvent
variable to True. For example,

    AbortChangeEvent = True
    Range("A1").Value = 1234
    AbortChangeEvent = False

The code above disables only the Worksheet_Change event and only for the one line code. In general,
using Application.EnableEvents = False is sufficient, but there may be circumstances in which more
complex event handling is necessary.

SectionBreak

Because the event object model includes implementations of the events of subordinate objects (e.g.,
Application has events for the Workbook and the
Worksheet objects), you may find that some results are different than what you may expect.

EVENT ORDER: It is important to note that the event procedures of a subordinate object (e.g., the Worksheet
will run to completion before an event of a superior object (e.g., Workbook) is called. That is, the Worksheet
event procedure Worksheet_Change will run to conclusion, to the End Sub statement,
before the Workbook event procedure Workbook_SheetChange occurs. Thus, you cannot assume that the Workbook and/or
Application SheetChange have been executed within your code in the Worksheet_Change event
procedure. You should assume the opposite — the events of the superior object will not yet have run.

For example, create a class named CExcelEvents and insert the following code:

    Public WithEvents App As Application

    Private Sub App_SheetChange(ByVal Sh As Object, ByVal Target As Range)
        Counter=Counter + 1
        Debug.Print "Counter: " & CStr(Counter)
    End Sub

Then, put the following code in the ThisWorkbook module:

    Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
        Counter = Counter + 1
        Debug.Print "Counter: " & CStr(Counter)
    End Sub

Next, put the following code in the code module for Sheet1:

    Private Sub Worksheet_Change(ByVal Target As Range)
        Counter = Counter + 1
        Debug.Print "Counter: ", CStr(Counter)
    End Sub

Finally, put the following code in a standard code module like Module1:

    Public Counter As Long
    Public XLApp As CExcelEvents

    Sub AAA()
        Set XLApp = New CExcelEvents
        Counter = 0
    End Sub

    Sub BBB()
        Debug.Print "*** COUNTER: ", CStr(Counter)
    End Sub

Now run the procedure AAA to get things set up. Next, type something into any cell on Sheet1. Finally
run the procedure BBB. Open the Immediate Window if it is not already open (CTRL G)
and look at the messages. You should see:

    Counter: 1
    Counter: 2
    Counter: 3
    *** COUNTER: 3

The counter is incremented first by the event procedure Worksheet_Change in the Worksheet
module, then incremented again in the Workbook_SheetChange procedure in the ThisWorkbook
code module, and then incremented yet again by the App_SheetChange event procedure. Thus, the counter
gets a value of 3, not 1 as you might expect. If you are using events in a superior object, you must take care that the events in
the superior object do not duplicate work done in the subordinate procedure. Not properly managing events in subordinate and superior objects
can cause unexpected results, such as the result of 3 in the example above.

SectionBreak

If you are writing your own class modules (see Introduction To Classes for an introduction to
working with and creating classes), you may want a class to raise an event when a specified action or condition occurs. This is
a fairly simple process. Note that only object modules (class modules, userform code modules, the sheet modules, and
the ThisWorkbook code module) may declare events. You cannot define, raise, or receive events in standard code modules. Also,
only object modules may declare variable WithEvents and therefore only object modules may receive
event triggers.

In the class that will create the events, you must first declare the events themselves with the
Public Event statement, such as:

    Public Event EventName(Parameters, ByRef Cancel As Boolean)

Here, EventName is the name of the event. This should be a meaningful name. Parameters
is a list of any parameters that you want to pass to the class that is receiving this event, such as
X As Long, Y As Double, Z As String
This is optional. Finally, Cancel is an optional but useful parameter. It allows the class that is receiving
the event to respond back to the class that contains the event that the action in question should be cancelled. For example,
the Workbook_BeforeSave event has a Cancel parameter that allows you to cancel
the Save operation. While a Cancel parameter is entirely optional, it is a
nice touch that can add flexibility and a professional touch to your application.

Once you have declared your events, (one Public Event declaration for each event), you need
raise the event at the appropriate location in your class. Where you raise the events depends entirely on the context of the executing
code and what action or condition the event signifies. When I design commercial software, I use events extensively, using both a
BeforeSomeAction and AfterSomeAction event pair to notify any listener that my code is
about to carry out some action and to notify the listener than the action has been completed. If possible, I like to include
a Cancel parameter to allow the event listener to cancel a pending operation. However, you can use events
in any way you want.

You raise an event using the RaiseEvent statement. Once the event is declared, you trigger it with the
RaiseEvent statement. Both declaration and raising of the event EventName are
shown in the code below. Note that you cannot use Named Arguments when passing parameters to the
RaiseEvent procedure.

    Public Event EventName(IDNumber As Long, ByRef Cancel As Boolean)

    Sub AAA()
        Dim B As Boolean
        Dim IDNumber As Long
        IDNumber = 1234
        Cancel = False
        RaiseEvent EventName(IDNumber, Cancel)

        If Cancel = False Then
            
        Else
            
        End If
    End Sub

Once you have created your class with events, you need to write the code that will receive the event triggers. Note that only object modules
(class modules, a user form code module, a Sheet module, or the ThisWorkbook module — standard code modules cannot receive events) can receive
event messages. In a suitable object module, declare the event class using WithEvents:

    Dim WithEvents XLEvents As CExcelEvents
    

At some point in your code, you will need to set the XLEvents variable to an instance of the
CExcelEvents class, with the code:

    Set XLEvents = New CExcelEvents

Exactly when and where you put the object initialization code depends on what sort of module contains the event
declaration. While it is technically possible to put the initialization of the variable in another procedure, this is generally
a bad programming practice: it makes the code more difficult to debug and maintain. As a general rule, the code that initializes
the events variable should be in the same class as the events variable. Of course, the actual event code must reside in the
same object module as the events variable declaration. In a class module, the initialization would normally be in the Class_Initialize event.
For a user form, the code would go in the UserForm_Initialize event.

    Private Sub XLEvents_EventName(IDNumber Long, Cancel As Boolean)
        Cancel = True 
    End Sub

This page last updated: 23-March-2010

Like this post? Please share to your friends:
  • Excel vba with синтаксис
  • Excel vba table to range
  • Excel vba with внутри with
  • Excel vba table this row
  • Excel vba with worksheets range