Остановить макрос если ошибка

Access для Microsoft 365 Access 2021 Access 2019 Access 2016 Access 2013 Access 2010 Access 2007 Еще…Меньше

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

Примечание: Макрокоманда «ПриОшибке» недоступна в веб-приложениях Access.

Настройка

Макрокоманда ПриОшибке имеет следующие аргументы:

Аргумент макрокоманды

Описание

Перейти

Определяет общее поведение после возникновения ошибки. Щелкните стрелку раскрывающегося списка и выберите одно из следующих значений:

Параметр

Описание

Далее

Access записывает подробные сведения об ошибке в объекте ОшибкаМакроса, но не останавливает макрос. Выполнение продолжается со следующей макрокоманды.

Имя макроса

Access останавливает выполнение текущего макроса и запускает макрос, указанный в аргументе Имя макроса.

Сбой

Access останавливает выполнение текущего макроса и отображает сообщение об ошибке.

Имя макроса

Если аргумент Перейти имеет значение Имя макроса, введите имя макроса, который будет использоваться для обработки ошибок. Введенное имя должно соответствовать имени вложенного макроса для текущего макроса; нельзя указать имя другого объекта. В следующем примере макрос «ОбработчикОшибок» содержится в том же объекте макроса, что и макрокоманда ПриОшибке.

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

Замечания

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

  • Если для аргумента «Перейти» установлено действие «Сбой», Access работает так же, как если бы в макросе не было макро макроса «При Входе». Таким образом, если произошла ошибка, Access останавливает макрос и выводит стандартное сообщение об ошибке. Основное использование параметра «Сбой» — отключение обработки ошибок, которые были установлены ранее в макросе.

Пример

Следующий макрос демонстрирует использование макрокоманды ПриОшибке. В данном примере макрокоманда ПриОшибке указывает, что при возникновении ошибки будет выполнен пользовательский вложенный макрос «ОбработчикОшибок». Если в любой из последующих макрокоманд произойдет ошибка, Access перейдет к вложенному макросу «ОбработчикОшибок». Макрос «ОбработчикОшибок» отображает окно сообщения с данными об ошибке из объекта ОшибкаМакроса.

Имя вложенного макроса

Макрокоманда

Аргументы

ПриОшибке

Перейти: Имя макроса

Имя макроса: ОбработчикОшибок

[Макрокоманда 2]

[Макрокоманда n]

ОбработчикОшибок

Окно сообщения

Сообщение: =»Ошибка» & [MacroError].[Номер] & «в макрокоманде» & [MacroError].[ИмяМакрокоманды].

Сигнал: Да

Тип: Отсутствует

Заголовок: Произошла ошибка

Ниже показан снимок экрана с конструктором макросов Access (в Access 2010 или более поздней версии), в котором настроен макрос из предыдущего примера. В этом случае выражение в макрокоманде ЗадатьЛокПеременную вызывает ошибку из-за попытки деления на нуль. Access переходит к вложенному макросу с именем «ОбработчикОшибок» и выводит окно сообщения со сведениями об ошибке.

Рабочая область конструирования макросов Access с макрокомандой "ПриОшибке".

Нужна дополнительная помощь?

Нужны дополнительные параметры?

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

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

 

Добрый день. Уменя маленькая проблема с макросом.  

  Sub Макрос  
   Sheets(2).Copy After:=Sheets(2)  
   Sheets(1).Select  
   Sheets(3).Name = Cells(1, 2)  
   End Sub  

  Этот макрос копирует лист2 и присваивает  имя из лист1 ячейка В1. Макрос работает, но если лист с таким именем уже существует, выбивает ошибку. Мне надо чтоб при возникновении ошибки робота макроса останавливалась, и всплывало сообщение «Лист с таким именем существует».

 

KuklP

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

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

E-mail и реквизиты в профиле.

Да нет, лучше перед копированием проверить, нет ли такого листа. И если есть — не копировать.

Я сам — дурнее всякого примера! …

 

Sub Макрос2()  
On Error Resume Next  
Set wsSh = Sheets(Как указать чтоб имя листа сверялось с Лист1 ячейка В1?)  
If wsSh Is Nothing Then MsgBox «Листа нет»  
End Sub

 

ikki

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

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

Set wsSh = Sheets(Sheets(«Лист1»).[B1])

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

KuklP

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

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

E-mail и реквизиты в профиле.

Function WorksheetExist(wsname As String) As Boolean  
‘Возвращает ИСТИНА, если лист существует  
   Dim x As Worksheet  
   On Error Resume Next  
   Set x = Worksheets(wsname)  
   WorksheetExist = (Err = 0)  
End Function

Я сам — дурнее всякого примера! …

 

Что-то ничего не получается

 

Sub Макрос2()  
On Error Resume Next  
Set wsSh = Sheets(Как указать чтоб имя листа бралось из Лист1 ячейка В1?)  
If wsSh Is Nothing Then MsgBox «Листа нет»  
End Sub  

  Ответ предложенный ikki н работает

 

KuklP

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

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

E-mail и реквизиты в профиле.

Set wsSh = Sheets(Sheets(«Лист1»).[B1].VALUE)

Я сам — дурнее всякого примера! …

 

Огромное спасибо за помощь. Все работает.

 

ikki

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

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

а ведь я проверял… работало :(

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

ikki

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

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

мда… понял: не находило несуществующий лист, но существующий тоже не находило.  
а «проверял» я только первый вариант :(  

  DimaLulchuk, прошу прощения.    

    пс. и всё-таки… немножко странно — разве свойство Value не является «умолчальным»?

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

ikki

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

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

(заставь дурака богу молиться… :)  
я дальше полез  

  Sheets(…) — это ведь короткая форма записи для Sheets.Item(…), да?  
всё-таки Sheets() — это не массив, а коллекшн.  

  а для Item в справке написано:  

  Returns a single object from a collection.  

  expression.Item(Index)  
expression —   Required. An expression that returns all other objects in the Applies To list.  

  Index —  Required Variant. The name {!!!} or index number {!!!} for the object.  

  фигурные скобки — мои, конечно :)  

  так что объект-то Item() принять может (т.к. объект — это подтип для Variant). но почему такой вариант для него предпочтительный — всё же непонятно.    

  впрочем, это не страшно и не сложно дописать пяток символов в коде.  
но — когда знаешь.

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

KuklP

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

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

E-mail и реквизиты в профиле.

Мож так понятней:  
Set Statement  
Assigns an object reference to a variable or property.  
Syntax  
Set objectvar = {[New] objectexpression | Nothing}
То есть из-за ключевого слов Set компилятор ожидает именно объект. А  
Sheets(«Лист1»).[B1] и есть объект range. Если явно не указать его свойство — value.

Я сам — дурнее всякого примера! …

 

ikki

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

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

а разве Set ждет объекты от ЛЮБОЙ части того что справа? :)  

  set x=sheets(…) — да, конечно.  
но sheets(…) и вернет объект — указанный по имени или индексу элемент коллекции.  
это понятно. вопросов нет.  
но это же не означает, что «…» — тоже должен быть объект?  
это непонятно.  

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

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

KuklP

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

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

E-mail и реквизиты в профиле.

#15

09.02.2012 22:04:55

ikki, можно проверить, отключив On Error Resume Next. Получим неверный тип данных. Не вилит Экс в range строку, видит объект.

Я сам — дурнее всякого примера! …

Обработка ошибок в VBA Excel с помощью оператора On Error. Синтаксис выражений с оператором On Error. Пример кода с простым обработчиком ошибок.

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

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

Обработчик ошибок позволяет завершить выполнение программы при возникновении ошибки и вывести сообщение пользователю с ее описанием.

Синтаксис выражений с On Error

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

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

Отключает любой включенный обработчик ошибок в текущей процедуре.

Простой обработчик ошибок

Шаблон простейшего обработчика ошибок:

Sub Primer()

On Error GoTo Stroka

    ‘Блок операторов процедуры

Exit Sub

Stroka:

    MsgBox «Произошла ошибка: « & Err.Description

End Sub

Оператор On Error GoTo размещается в начале процедуры, метка и обработчик ошибок – в конце процедуры. Название метки можно сменить на другое, в том числе на кириллице.

Оператор Exit Sub обеспечивает выход из процедуры, если блок операторов выполнен без ошибок. Для вывода описания ошибки используется свойство Description объекта Err.

Примеры обработки ошибок

Пример 1
Деление на ноль:

Sub Primer1()

On Error GoTo Инструкция

    Dim a As Double

    a = 45 / 0

Exit Sub

Instr:

    MsgBox «Произошла ошибка: « & Err.Description

End Sub

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

Пример 2
Выход за границы диапазона:

Sub Primer2()

On Error GoTo Instr

    Dim myRange As Range

    Set myRange = Range(«A1:D4»).Offset(2)

Exit Sub

Instr:

    MsgBox «Произошла ошибка: « & Err.Description

End Sub

Результат выполнения кода VBA Excel с оператором On Error GoTo:

Пример использования выражений On Error Resume Next и On Error GoTo 0 смотрите в статье: Отбор уникальных значений с помощью Collection.

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

pabchek

Дата: Вторник, 24.05.2016, 10:29 |
Сообщение № 1

Группа: Проверенные

Ранг: Ветеран

Сообщений: 931


Репутация:

218

±

Замечаний:
0% ±


Excel 2007

Здравствуйте, всем!
Подскажите, плз. Нужно чтобы выполнение макроса прерывалось если в столбце есть ошибка (Н/Д). Пробовал несколько способов, но никак не соображу. Вот один из них.
[vba]

Код

    If IsError(Range(«A:A»)) Then
        MsgBox «Есть НД»
    End If

[/vba]
(В файле формула исключительно для формирования ошибки)

К сообщению приложен файл:

1200444.xlsb
(12.4 Kb)


«Учиться, учиться и еще раз учиться!»
WM: R399923528092

 

Ответить

wild_pig

Дата: Вторник, 24.05.2016, 10:36 |
Сообщение № 2

Группа: Проверенные

Ранг: Обитатель

Сообщений: 516


Репутация:

97

±

Замечаний:
0% ±


2003, 2013

[vba]

Код

Sub dd()
    For Each cel In Cells(1, 1).CurrentRegion
        If IsError(cel.Value) Then
            MsgBox cel.Address
            Exit Sub ‘Exit For
        End If
    Next
End Sub

[/vba]

 

Ответить

_Boroda_

Дата: Вторник, 24.05.2016, 10:40 |
Сообщение № 3

Группа: Модераторы

Ранг: Местный житель

Сообщений: 16620


Репутация:

6465

±

Замечаний:
0% ±


2003; 2007; 2010; 2013 RUS

А вот так не подойдет?
[vba]

Код

Sub dd()
    On Error Resume Next
    If Not WorksheetFunction.Sum(Range(«A:A»)) Then
        MsgBox «Есть ошибка»
    End If
End Sub

[/vba]
Вернее, вот так
[vba]

Код

Sub dd()
    On Error Resume Next
    a = WorksheetFunction.Sum(Range(«A:A»))
    If Err.Number Then
        MsgBox «Есть ошибка»
    End If
End Sub

[/vba]
И вообще, если у тебя там вычисления какие-то, которые при наличии ошибки не работают (дебагер вылетает), то
[vba]

Код

Sub dd()
    On Error Resume Next
    ‘вычисления
    If Err.Number Then
        MsgBox «Есть ошибка»
Exit sub
    End If
End Sub

[/vba]


Скажи мне, кудесник, любимец ба’гов…
Платная помощь:
Boroda_Excel@mail.ru
Яндекс-деньги: 41001632713405 | Webmoney: R289877159277; Z102172301748; E177867141995

 

Ответить

pabchek

Дата: Вторник, 24.05.2016, 10:45 |
Сообщение № 4

Группа: Проверенные

Ранг: Ветеран

Сообщений: 931


Репутация:

218

±

Замечаний:
0% ±


Excel 2007

wild_pig, не работает, если ошибка не в первой строке
_Boroda_, Саш, к сожалению, ввел в заблуждение проставив цифры. На самом деле в колонке текстовые значения. Не подумал, что это важно.
Но второй вариант работает. Но почему? Там же сумма.


«Учиться, учиться и еще раз учиться!»
WM: R399923528092

Сообщение отредактировал pabchekВторник, 24.05.2016, 10:58

 

Ответить

_Boroda_

Дата: Вторник, 24.05.2016, 11:06 |
Сообщение № 5

Группа: Модераторы

Ранг: Местный житель

Сообщений: 16620


Репутация:

6465

±

Замечаний:
0% ±


2003; 2007; 2010; 2013 RUS

Сумма текста = 0.
Первый вариант как раз не учитывал то, что там или текст, или все нули, или +1,-1,+1,-1
А сумма чего угодно, если в этом что угодно есть ошибка, даст ошибку.

wild_pig, не работает, если ошибка не в первой строке

Не совсем так. Обрати внимание на кусок Cells(1, 1).CurrentRegion — это текущая область относительно ячейки А1. Попробуй нажать F5 — выделить — Текущая область и поймешь сам. Только встань сначала вовнутрь таблицы.


Скажи мне, кудесник, любимец ба’гов…
Платная помощь:
Boroda_Excel@mail.ru
Яндекс-деньги: 41001632713405 | Webmoney: R289877159277; Z102172301748; E177867141995

 

Ответить

pabchek

Дата: Вторник, 24.05.2016, 11:09 |
Сообщение № 6

Группа: Проверенные

Ранг: Ветеран

Сообщений: 931


Репутация:

218

±

Замечаний:
0% ±


Excel 2007

Никак не привыкну, что в VBA отличаются результаты от обычных формул. Спасибо большое!


«Учиться, учиться и еще раз учиться!»
WM: R399923528092

 

Ответить

_Boroda_

Дата: Вторник, 24.05.2016, 11:16 |
Сообщение № 7

Группа: Модераторы

Ранг: Местный житель

Сообщений: 16620


Репутация:

6465

±

Замечаний:
0% ±


2003; 2007; 2010; 2013 RUS

в VBA отличаются результаты от обычных формул

Не-не-не,
1. в Excel даст 0.
2. Слово WorksheetFunction как раз и подразумевает, что мы используем функцию Excel, а не VBA.

И еще я там выше дописал немного, посмотри.


Скажи мне, кудесник, любимец ба’гов…
Платная помощь:
Boroda_Excel@mail.ru
Яндекс-деньги: 41001632713405 | Webmoney: R289877159277; Z102172301748; E177867141995

 

Ответить

pabchek

Дата: Вторник, 24.05.2016, 11:28 |
Сообщение № 8

Группа: Проверенные

Ранг: Ветеран

Сообщений: 931


Репутация:

218

±

Замечаний:
0% ±


Excel 2007

Ну да, млин… Я ж это знаю. Тупанул((( А то, что дописал, да — это я уже понял и принял на вооружение


«Учиться, учиться и еще раз учиться!»
WM: R399923528092

 

Ответить

pabchek

Дата: Вторник, 24.05.2016, 11:34 |
Сообщение № 9

Группа: Проверенные

Ранг: Ветеран

Сообщений: 931


Репутация:

218

±

Замечаний:
0% ±


Excel 2007

Cells(1, 1).CurrentRegion

Да, я понял. Тем не менее, для пробы я НД-шку перетащил в середину столбца и образовалась пустая ячейка А2. И в этом случае ошибку не ищет.


«Учиться, учиться и еще раз учиться!»
WM: R399923528092

Сообщение отредактировал pabchekВторник, 24.05.2016, 11:35

 

Ответить

_Boroda_

Дата: Вторник, 24.05.2016, 11:57 |
Сообщение № 10

Группа: Модераторы

Ранг: Местный житель

Сообщений: 16620


Репутация:

6465

±

Замечаний:
0% ±


2003; 2007; 2010; 2013 RUS

в этом случае Текущая область нулевая

Не совсем. Текущая область равна одной ячейке — А1.

А вообще если, то CurrentRegion может именно из-за наличия пустых строк/столбцов дать не совсем нужный результат. Поэтому я, например, его практически не использую — у меня-то в таблицах безобразия с пустыми строками-столбцами не бывает, но завтра с моим файлом начнет работать девочка Виолетта (с ресницами длиннее ногтей, которые длиннее пальцев [ногти и пальцы на руках, естественно]) и с файлом может случиться что угодно.

Если очень нужно, то использую
[vba]

Код

    Dim d_ As Range
    ActiveSheet.UsedRange
    Set d_ = Range(Range(«A1»), Range(«A1»).SpecialCells(xlLastCell))

[/vba]
а обычно считаю считаю строки и столбцы там, где точно знаю, что заполнено всегда
[vba]

Код

    Dim d_ As Range
    r1_ = Range(«A» & Rows.Count).End(xlUp).Row
    c1_ = Cells(1, Columns.Count).End(xlToLeft).Column
    Set d_ = Range(Cells(1, 1), Cells(r1_, c1_))

[/vba]
В первом куске ActiveSheet.UsedRange очень желательно — эта штука нормализует диапазон. Например, ты написал случайно в ячейке L999 цифру 5, потом понял, что ошибся и стер ее. А таблица у тебя А1:В9 и все, больше ничего на листе нет. Тогда SpecialCells(xlLastCell) даст тебе ячейку L999 (и без разницы, что там уже ничего нет, главное, что было). Убрать это из памяти можно или сохранением файла, или строкой ActiveSheet.UsedRange


Скажи мне, кудесник, любимец ба’гов…
Платная помощь:
Boroda_Excel@mail.ru
Яндекс-деньги: 41001632713405 | Webmoney: R289877159277; Z102172301748; E177867141995

 

Ответить

pabchek

Дата: Вторник, 24.05.2016, 12:36 |
Сообщение № 11

Группа: Проверенные

Ранг: Ветеран

Сообщений: 931


Репутация:

218

±

Замечаний:
0% ±


Excel 2007

у меня-то в таблицах безобразия с пустыми строками-столбцами не бывает

У меня тоже, но правда жизни гораздо суровее с ногтеносными девочками. Оттуда же и . Кстати, я на это уже натыкался и знаю. На автомате удаляю пустой конец файла с последующим сохранением.
И да, спасибо за код подсчета строк/столбцов!


«Учиться, учиться и еще раз учиться!»
WM: R399923528092

 

Ответить

pabchek

Дата: Вторник, 24.05.2016, 12:49 |
Сообщение № 12

Группа: Проверенные

Ранг: Ветеран

Сообщений: 931


Репутация:

218

±

Замечаний:
0% ±


Excel 2007

Да, вот еще натолкнулся, но сам сообразил:
Поскольку у меня не единственные, и по ходу выполнения макроса нужно учитывать результат последних. Добавил
[vba][/vba]
Получилось:


«Учиться, учиться и еще раз учиться!»
WM: R399923528092

Сообщение отредактировал pabchekВторник, 24.05.2016, 12:52

 

Ответить

_Boroda_

Дата: Вторник, 24.05.2016, 13:33 |
Сообщение № 13

Группа: Модераторы

Ранг: Местный житель

Сообщений: 16620


Репутация:

6465

±

Замечаний:
0% ±


2003; 2007; 2010; 2013 RUS

Так у тебя будет пропускать вообще все ошибки. И в Вычислениях_1 тоже. А вдруг там ошибка в коде?
on error resume next в самом начале пишут обычно тогда, когда отдают код кому-то наружу. Чтобы на дебаг не выскакивало в случае чего. Да, в случае ошибки отрабатывать может неверно, но пугать пользователя окном VBA не будет. А при написании/отладке On Error… нужно писать только там, где он действительно необходим.
Возможно, второй вариант из поста 3 все-таки лучше. Что-то типа
[vba]

Код

Sub dd()
    ‘вычисления 1
    ‘вычисления 2
    Err.Clear’на всякий случай, вдруг ошибка уже была в коде раньше, мы ее пропустили, но не обнулили
    On Error Resume Next
    a = WorksheetFunction.Sum(Range(«A:A»))
    If Err.Number Then
        MsgBox «Есть ошибка»
        Exit Sub
        ‘ здесь «on error goto 0» не нужно — мы все равно уже вышли из Sub
    End If
    ‘ здесь «on error goto 0» не нужно — ошибки и так не было
End Sub

[/vba]
Про On Error можно почитать здесь
https://msdn.microsoft.com/ru-ru/library/5hsw66as.aspx


Скажи мне, кудесник, любимец ба’гов…
Платная помощь:
Boroda_Excel@mail.ru
Яндекс-деньги: 41001632713405 | Webmoney: R289877159277; Z102172301748; E177867141995

 

Ответить

pabchek

Дата: Вторник, 24.05.2016, 14:28 |
Сообщение № 14

Группа: Проверенные

Ранг: Ветеран

Сообщений: 931


Репутация:

218

±

Замечаний:
0% ±


Excel 2007

Так у тебя будет пропускать вообще все ошибки

Не совсем. В файле я смоделировал ситуацию, в которой если On Error… не поставить первым, получается ошибка функции. И если во втором случае не поставить Err.Clear, то запоминается ошибка из первых вычислений и выскакивает MsgBox.

К сообщению приложен файл:

8238817.xlsb
(13.7 Kb)


«Учиться, учиться и еще раз учиться!»
WM: R399923528092

Сообщение отредактировал pabchekВторник, 24.05.2016, 14:30

 

Ответить

KuklP

Дата: Вторник, 24.05.2016, 15:49 |
Сообщение № 15

Группа: Проверенные

Ранг: Старожил

Сообщений: 2369


Репутация:

486

±

Замечаний:
0% ±


2003-2010

[vba]

Код

Public Sub www()
    On Error Resume Next
    Set r = [A:a].CurrentRegion.SpecialCells(xlCellTypeFormulas, 16)
    If Err = 0 Then MsgBox «ERROR!»
    Err.Clear
End Sub

[/vba]


Ну с НДС и мы чего-то стoим! kuklp60@gmail.com
WM Z206653985942, R334086032478, U238399322728

 

Ответить

Хитрости »

21 Март 2015              96288 просмотров


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

  Пример таблицы и кода (35,5 KiB, 2 877 скачиваний)


Что будет рассмотрено:

  • Способы отладки кода в момент появления ошибки
  • Использование окон Locals и Watches для отладки
  • Пошаговая отладка кода — что это такое, как и когда применять
  • Ошибок нет, но код все равно не выполняется

Помимо этого в конце статьи можно скачать файл с кодами ошибок VBA и их расшифровками.

Исходные данные
Допустим, имеется простая таблица
Таблица данных
И код, который должен пройтись по каждой строке таблицы, перемножить цену (столбец Цена) на количество (столбец Продажи шт), просуммировать перемноженные данные и вывести результирующую сумму в ячейку В17:

Option Explicit
Sub PrimitiveCode()
    Dim lr As Long, dblSumm As Double, dblIncr As Double
    'цикл от первой строки таблицы до последней
    For lr = 1 To 14
        'перемножение Цены на Количество (C*E)
        dblIncr = Cells(l, 3).Value * Cells(lr, 5).Value
        'прибавление результата к переменной общей суммы
        dblSumm = dblSumm + dblIncr
    Next
    'выводим результат в ячейку B17
    Cells(17, 2).Value = dblSumm
End Sub
Отладка кода в момент появления ошибки

Если посмотреть на код выше, то опытный программист VBA сразу поймет, что в таком виде код работать не будет – не выполнится и одна строка. Сразу появится ошибка:
Variable not defined

Ошибка означает, что внутри кода есть переменная, которая ранее не была объявлена.
Сама переменная, которую VBA считает не объявленной будет выделена:
Не объявленная переменная
Подробнее об этой ошибке и её причинах можно почитать в статье: Variable not defined или что такое Option Explicit и зачем оно нужно?
Если строки Option Explicit нет, то ошибка появится в момент выполнения строки с этой переменной, т.к. значение этой переменной будет 0, что нельзя использовать в качестве номер строки на листе. Как определить причину ошибки в конкретной строке описано ниже.

Если кратко, то переменной l нет среди объявленных переменных(Dim l As) и мы не можем её использовать, если объявлена директива Option Explicit(настоятельно рекомендую Option Explicit использовать всегда во избежание опечаток). В данном случае это опечатка и там должна быть lr, а не l. Исправляем переменную и код будет выглядеть так:

Sub PrimitiveCode()
    Dim lr As Long, dblSumm As Double, dblIncr As Double
    'цикл от первой строки таблицы до последней
    For lr = 1 To 14
        'перемножение Цены на Количество (C*E)
        dblIncr = Cells(lr, 3).Value * Cells(lr, 5).Value
        'прибавление результата к переменной общей суммы
        dblSumm = dblSumm + dblIncr
    Next
    'выводим результат в ячейку B17
    Cells(17, 2).Value = dblSumm
End Sub

С виду код теперь выполнен правильно и ошибок вызывать не должен. Однако, если его попытаться выполнить опять получим ошибку – на этот раз ошибку типов данных — Type Mismatch:
Type Mismatch
В момент появления главное нажать Debug, а не End (если будет желание прочитать про тип ошибки подробнее – можно еще нажать Help, текст будет на английском). VBA подсветит желтым строку, вычисления или операции в которой вызывают ошибку:
Строка ошибки
Теперь самый важный этап – необходимо определить причину ошибки. С виду все хорошо – одна ячейка перемножается на другую. Без опыта сложно сходу понять, что это ошибка типов данных, хоть VBA прямо об этом говорит(Type Mismatch – в переводе «Несовпадение типов»). Поэтому самое надежное в этом случае – это определить значение каждой составляющей той строки, в которой возникла ошибка. В случае с кодом выше можно воспользоваться двумя методами:

  1. Навести курсор мыши на любую переменную(dblSum, lr) и посмотреть всплывающую подсказку, которая показывает имя переменной и её текущее значение:
    Значение переменной
    Значение нашей переменной lr = 1. Запоминаем и переходим на лист с таблицей и смотрим, какое значение в ячейке первой строки третьего столбца(Cells(1,3)). Там значение Закуп цена, что явно не является числом. Следовательно перемножить его нельзя, т.к. это текст. Отсюда и ошибка типов – с текстом нельзя производить математические операции. Для вычислений предполагается в данном случае числовой тип данных(Integer,Long,Double).
  2. Узнать сразу значение ячейки Cells(lr, 3).Value и ячейки Cells(lr, 5).Value. Наведение курсора мыши в данном случае не даст результата. Как правило наведение курсора мыши не имеет эффекта если это не объявленные как переменные объекты (как в этом случае — Cells). Такие объекты не всегда могут быть вычислены в памяти в момент отладки. Поэтому чтобы просмотреть значение ячейки сначала необходимо отобразить окно Immediate(отобразить можно сочетанием клавиш Ctrl+G или через меню ViewImmediate Window). Выделить и скопировать полностью нужную переменную Cells(i, 3).Value и в окне Immediate написать:
    ?
    и после вопр.знака вставить скопированное. Должно получиться:
    ?Cells(i, 3).Value
    И нажать Enter. Строкой ниже в этом окне будет выведено значение для объекта или переменной (если оно может быть получено):
    Значение в окне Immediate
    По сути результат будет как и в первом примере – мы увидим, что в ячейке текст. Чем второй метод лучше первого? Тем, что таким образом можно сразу получить значение, не переходя на лист и не выискивая нужный номер строки. Ведь это в примере он равен 1, в реальности же строка может быть и 24451.

Окна Locals и Watches

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

Locals

и окно

Watches

.

Окно Locals

Окно Locals отображает все локальные переменные, задействованные в выполняемой в настоящий момент процедуре:
Locals Window
Как видно в этом окне отображается имя переменной, её тип и значение. Все хорошо, но в этом окне отображаются исключительно локальные переменные, объявленные на уровне модуля. Переменных других модулей, объявленные как Public и используемые в текущей процедуре там не отображаются. Подробнее про видимость переменных можно узнать в статье: Что такое переменная и как правильно её объявить?

Окно Watches
Окно Watches представляет большую ценность – в это окно можно просто «перетащить» нужную переменную или объект и в этом окне будут отражены все данные об имени переменной, её типе и текущем значении:
Watches Window
Теперь рассмотрим чуть подробнее как перетаскивать в это окно данные. На примере кода выше:

  • Выделяем Cells(i, 3).Value
  • Не снимая выделения наводим курсор мыши на это выделение
  • Зажимаем левую кнопку мыши и не отпуская её переносим курсор в любое место окна Watches

Теперь данные по переменной загружены и доступны для просмотра. По сути все умеют это делать — процесс очень схож с обычным перемещением файлов и папок по рабочему столу. Выделили и с зажатой левой кнопкой мыши перенесли в нужное место.
В чем еще один плюс этого окна – в этом окне можно оставлять эти значения и просматривать в моменты пошаговой отладки только занесенные в это окно переменные(про пошаговую отладку будет рассказано ниже). Если вдруг какая-то переменная/объект стали не нужны для постоянного отслеживания их данных – можно удалить их из окна Watches, чтобы не мешалась. Для этого выделяем переменную-правая кнопка мыши – Delete Watch. Так же можно поиграть с иными пунктами, наибольший интерес из которых на мой взгляд, представляет пункт Edit Watch. После его нажатия появится окно
Edit Watch
Самые основные пункты в этом окне, важные для отладки:

  • Break Then value Changes. Если его установить, VBA будет отслеживать значение этой переменной и останавливать код при любом изменении значения переменной. Это может пригодится для отслеживания значений в циклах
  • Break Then value Is True – пункт пригодится для переменных с типом Boolean или для логических выражений. Как только переменная или результат выражения примет значение True – код будет остановлен на этой строке.
    Например, необходимо остановить код, если номер строки будет равен 10(т.е. переменная lr примет значение 10). Тогда выражение будет иметь вид:

    If lr = 10 Then
    'код
    End if

    Тогда надо будет выделить в строке If lr = 10 Then само условное выражение lr = 10, перенести её в окно Watches, выделить строку в окне Watches с этим выражением, нажать правую кнопку мыши и выбрать Edit Watch. Выбрать в окне Break Then value Is True. Теперь как только переменная lr достигнет значения 10(т.е. обрабатываться будет 10-я строка таблицы) – код остановится и строка с выражением будет выделена желтым. Можно будет проанализировать другие переменные или продолжить выполнение кода в пошаговом режиме(см.далее).


Пошаговая отладка кода

После знакомства с отладкой кода при возникновении ошибки работать с пошаговой отладкой будет проще.

Что такое вообще пошаговая отладка?

Это просмотр этапов выполнения кода строка за строкой.

Для чего это может быть нужно?

  • Чтобы проанализировать чужой код и понять более точно, что он делает изнутри, а не только увидеть результат его выполнения
  • Если вы начинающий программист и часто используете макрорекордер(записываете макросы) — то пошаговая отладка поможет понять какое действия выполняет каждая строка. Это поможет быстрее научиться понимать код и убирать из него лишнее, а так же совмещать различные коды
  • Если внутри кода есть ошибка логики выполнения. Это, пожалуй, самая сложная ошибка, т.к. в этом случае VBA не останавливает работу и не говорит об ошибке. Код выполняется без ошибок, но результат не такой, как ожидалось. Это означает, что либо какой-то переменной назначается не то значение, либо какое-то условие неверно или выполняется не в тот момент, в который должно. В общем по сути это ошибка разработчика, не приводящая к ошибкам синтаксиса или типов, которые VBA может отследить.

Как делать пошаговую отладку? Все просто: устанавливаете курсор в любом месте внутри кода и нажимаете клавишу F8 (либо выбрать в меню DegubStep Into). Теперь при каждом нажатии клавиши F8 код будет выполнять одну строку кода за другой в той очередности, в которой они расположены в процедуре. Если внутри процедуры будет вызов второй процедуры или функции – код пошагово выполнит и её и затем вернется в основную процедуру.
Так же хочу привести еще пару сочетаний клавиш, которые удобно применять при пошаговой отладке:

  • Shift+F8(DegubStep Over) — выполнение вложенной функции/процедуры без захода в неё. Если внутри основной процедуры или функции выполняется другая процедура или функция и Вы уверены, что она работает правильно — просматривать пошагово весь код вложенной процедуры/функции не имеет смысла. Чтобы вложенная процедура/функция выполнилась без пошагового просмотра надо просто нажать указанное сочетание клавиш тогда, когда строка вызова вложенной процедуры/функции будет подсвечена желтым
  • Ctrl+Shift+F8(DegubStep Out) — завершение вложенной функции/процедуры и выход в основную с остановкой. Если все же перестарались и перешли в пошаговый проход вложенной функции(или сделали это специально, но посмотрели все, что надо) — то нажимаете это сочетание и код быстро выполнить вложенную функцию, перейдет в основную и остановится для дальнейшей пошаговой отладки
  • Ctrl+F8(DegubRun to Cursor) — выполнение процедуры до строки, в которой на данный момент установлен курсор

Точки останова
Но куда чаще бывает нужно не просто весь код пройти пошагово, а начать пошаговое выполнение только начиная с какой-либо одной строки, чтобы не мотать строк 40 кода(да еще с циклами) ради достижения одной какой-то строки. Еще точки останова очень полезны при отладке событийных процедур(вроде Worksheet_Change, Worksheet_BeforeDoubleClick, событий элементов форм и т.п.), т.к. они в большинстве своем содержат аргументы и выполнить по F8 их просто невозможно и выполняются они только при наступлении самого события, которые они призваны обработать. Тоже самое справедливо для функций пользователя(UDF) именно для проверки их работы из листа, т.к. эти функции нельзя начать выполнять по F5 — они начинают выполняться только после их пересчета и зачастую ошибки можно выявить исключительно при вызове именно с листа.
Чтобы дать понять VBA на какой строке необходимо будет остановится необходимо установить курсор мыши в любое место нужной строки и нажать F9 или DebugToggle Breakpoint. Строка будет выделена темно-красным цветом.
Это еще называется установкой точки останова. Убрать точку останова можно так же, как она была установлена – F9 или DebugToggle Breakpoint. Так же точку основа можно установить с помощью мыши: для этого необходимо в области левее окна с кодом напротив нужной строки один раз щелкнуть левой кнопкой мыши:
Точка останова

Теперь можно запустить код любым удобным способом (в отладке это как правило делается клавишей F5 или с панели: RunRun Sub/UserForm). Как только код дойдет до указанной точки останова он остановится и строка будет подсвечена желтым. Дальше можно либо продолжить выполнение в пошаговом режиме (нажимая F8), либо (проверив значения нужных переменных и объектов) нажать опять F5 и код продолжит выполняться автоматически, пока не выполнится или не достигнет другой точки останова. Самих же точек останова может быть сколько угодно и расположены они могут быть в любой процедуре или функции.
Следует помнить, что после закрытия файла с кодом точки останова не сохраняются и при следующем открытии книги их необходимо будет установить заново, если это необходимо.


Ошибок нет, но код все равно не выполняется

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

  1. Логика кода построена неверно и ошибок VBA действительно не возникает. Но т.к. логика неверна — код выполняет не то, что от него ожидается. Решение одно — пошагово выполнить весь код и детально просмотреть всё, чтобы обнаружить в какой строке или строках нарушена логика
  2. Один из очень распространенных вариантов: в начале кода стоит обработчик ошибок On Error Resume Next и дальше обработчик не отменяется. Данный обработчик указывает VBA, что при возникновении ошибки её следует игнорировать и переходит к выполнению следующего оператора/строки. Таким образом ошибка хоть и возникает, но она пропускается и не показывается, а выполнение кода продолжается как ни в чем не бывало. Однако как правило одна ошибка влечет другую и третью и т.д. и может получиться так, что все строки после первой ошибочной станут так же ошибочными и как следствие не выполнятся. Данный оператор будет применяться либо до конца процедуры, либо до тех пор, пока в коде не будет поставлен иной обработчик ошибок:
    On Error GoTo Метка — переход выполнения кода к указанной метке(Метка).
    On Error GoTo 0 — по сути отменяет условный переход при возникновении ошибок. Метка 0 считается обнулением переходов

Один из примеров того, для чего может применяться обработчик ошибок можно найти в статье: Как из Excel обратиться к другому приложению. Там данный обработчик необходим, чтобы проверить открыто ли уже приложение Word. Если открыто — то ошибка не возникнет. Если же закрыто — то будет ошибка. И этот момент как правило и отслеживается. Я расставил подробные комментарии в коде, чтобы было более понятно что к чему:

Sub Check_OpenWord()
    Dim objWrdApp As Object
    On Error Resume Next 'необходимо, чтобы на первой же строке код не выдал ошибку при закрытом Word
    'пытаемся подключится к объекту Word
    Set objWrdApp = GetObject(, "Word.Application")
    'если Word закрыт - обязательно возникнет ошибка 429, 
    'указывающая на то, что невозможно подключиться к объекту Word
    'при этом переменная objWrdApp будет равняться Nothing, т.к. значение не удалось присвоить
    If objWrdApp Is Nothing Then
    'так же можно использовать и такую строку:
    'If Err.Number = 429 Then 'если ошибка 429 - значит Word не запущен - надо создавать новый
        'создаем новый экземпляр
        Set objWrdApp = CreateObject("Word.Application")
        'делаем приложение видимым. По умолчанию открывается в скрытом режиме
        objWrdApp.Visible = True
    Else
        'приложение открыто - выдаем сообщение
        MsgBox "Приложение Word уже открыто", vbInformation, "Check_OpenWord"
    End If
End Sub

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


Конечно, статья не описывает способы устранения ошибок — это просто невозможно. Только известных типов ошибок в VBA более 3 тысяч. Все их упоминать бессмысленно. Целью статьи было помочь начинающим найти строку с ошибкой и рассказать как производить отладку кода при необходимости. А все остальное придет с опытом. Однако на всякий случай я решил выложить файл Excel с описанием большей части ошибок, которые могут возникнуть. В файле указан номер ошибки, описание на английском и описание на русском. Причин ошибки может быть множество, поэтому нет однозначных рекомендаций по устранению каждой из них. Все зависит от данных и от самого кода.

  Ошибки VBA с описанием (152,0 KiB, 5 640 скачиваний)

Удачи в программировании!


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

  Плейлист   Видеоуроки


Поиск по меткам



Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика

Понравилась статья? Поделить с друзьями:

Не пропустите эти материалы по теме:

  • Яндекс еда ошибка привязки карты
  • Остановите на остановке вид ошибки
  • Основные причины возникновения ошибок при обучении плаванию
  • Основные принципы кодирования расчет вероятностей ошибок
  • Основные ошибки этикета

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии