Перейти к содержимому
Наше приложение «Дешевые авиабилеты» в AppGallery >>

VBA Excel. Пользовательская функция (синтаксис, компоненты)

    Создание пользовательской функции в VBA Excel, ее синтаксис и компоненты. Описание пользовательской функции и ее аргументов. Метод Application.MacroOptions.

    Пользовательская функция — это процедура VBA, которая производит заданные вычисления и возвращает полученный результат. Используется для вставки в ячейки рабочего листа Excel или для вызова из других процедур.

    Объявление пользовательской функции

    Синтаксис функции

    Компоненты функции

    • Static — необязательное ключевое слово, указывающее на то, что значения переменных, объявленных в функции, сохраняются между ее вызовами.
    • Имя — обязательный компонент, имя пользовательской функции.
    • СписокАргументов — необязательный компонент, одна или более переменных, представляющих аргументы, которые передаются в функцию. Аргументы заключаются в скобки и разделяются между собой запятыми.
    • Операторы — необязательный компонент, блок операторов (инструкций).
    • Имя = выражение — необязательный* компонент, присвоение имени функции значения выражения или переменной. Обычно, значение присваивается функции непосредственно перед выходом из нее.
    • Exit Function — необязательный компонент, принудительный выход из функции, если ей уже присвоено окончательное значение.

    *Один из компонентов Имя = выражение следует считать обязательным, так как если не присвоить функции значения, смысл ее использования теряется.

    Видимость функции

    Видимость пользовательской функции определяется необязательными ключевыми словами Public и Private, которые могут быть указаны перед оператором Function (или Static, в случае его использования).

    Ключевое слово Public указывает на то, что функция будет доступна для вызова из других процедур во всех модулях открытых книг Excel. Функция, объявленная как Public, отображается в диалоговом окне Мастера функций.

    Ключевое слово Private указывает на то, что функция будет доступна для вызова из других процедур только в пределах программного модуля, в котором она находится. Функция, объявленная как Private, не отображается в диалоговом окне Мастера функций, но ее можно ввести в ячейку вручную.

    Если ключевое слово Public или Private не указано, функция считается по умолчанию объявленной, как Public.

    Чтобы пользовательская функция всегда была доступна во всех открытых книгах Excel, сохраните ее в Личной книге макросов без объявления видимости или как Public. Но если вы планируете передать рабочую книгу с пользовательской функцией на другой компьютер, код функции должен быть в программном модуле передаваемой книги.

    Пример пользовательской функции

    Для примера мы рассмотрим простейшую пользовательскую функцию, которой в следующем параграфе добавим описание. Называется функция «Деление», объявлена с типом данных Variant, так как ее возвращаемое значение может быть и числом, и текстом. Аргументы функции — Делимое и Делитель — тоже объявлены как Variant, так как в ячейках Excel могут быть числовые значения разных типов, и функция IsNumeric тоже проверяет разные типы данных и требует, чтобы ее аргументы были объявлены как Variant.

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

    • Если делимое или делитель не являются числом, функция возвращает значение: «Ошибка: Делимое и Делитель должны быть числами!», и производится принудительный выход из функции оператором Exit Function.
    • Если делитель равен нулю, функция возвращает значение: «Ошибка: деление на ноль!», и производится принудительный выход из функции оператором Exit Function.

    Если проверяемые условия не выполняются (возвращают значение False) производится деление чисел и функция возвращает частное (результат деления).

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

    Практического смысла функция «Деление» не имеет, но она хорошо демонстрирует как объявляются, создаются и работают пользовательские функции в VBA Excel. А еще она поможет продемонстрировать, как добавлять к функциям и аргументам описания. С полноценной пользовательской функцией вы можете ознакомиться здесь.

    Добавление описания функции

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

    • Запустите Мастер функций, посмотрите, как отображается имя нужной функции и закройте его.
    • Откройте список макросов и в поле «Имя макроса» впишите имя пользовательской функции.
    • Нажмите кнопку «Параметры» и в открывшемся окне добавьте или отредактируйте описание.
    • Нажмите кнопку «OK», затем в окне списка макросов — «Отмена». Описание готово!

    Добавление описания на примере функции «Деление»:

    Добавление описания пользовательской функции в окне «Параметры макроса»
    Добавление описания пользовательской функции

    Описание функции «Деление» в диалоговом окне Мастера функций «Аргументы функции»:

    Описание пользовательской функции в диалоговом окне «Аргументы функции»
    Описание пользовательской функции в окне «Аргументы функции»

    С помощью окна «Список макросов» можно добавить описание самой функции, а ее аргументам нельзя. Но это можно сделать, используя метод Application.MacroOptions.

    Метод Application.MacroOptions

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

    Пример кода с методом Application.MacroOptions:

    • ИмяПодпрограммы — любое уникальное имя, подходящее для наименования процедур.
    • ИмяФункции — имя функции, параметры которой добавляются или изменяются.
    • Описание функции — описание функции, которое добавляется или изменяется.
    • Название категории — название категории в которую будет помещена функция. Если параметр Category отсутствует, пользовательская функция будет записана в раздел по умолчанию — «Определенные пользователем». Если указанное Название категории соответствует одному из названий стандартного списка, функция будет записана в него. Если такого Названия категории нет в списке, будет создан новый раздел с этим названием и функция будет помещена в него.
    • «Описание 1», «Описание 2», «Описание 3», … — описания аргументов в том порядке, как они расположены в объявлении пользовательской функции.

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

    Сейчас с помощью метода Application.MacroOptions попробуем изменить описание пользовательской функции «Деление» и добавить описания аргументов.

    После однократного запуска этой подпрограммы получаем следующий результат:

    Новое описание пользовательской функции и ее второго аргумента
    Новое описание пользовательской функции и ее второго аргумента

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

    Содержание рубрики VBA Excel по тематическим разделам со ссылками на все статьи.

    80 комментариев для “VBA Excel. Пользовательская функция (синтаксис, компоненты)”

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

      Функция нормально работает и вставляет формулу в нужные ячейки. Функция ссылается на два диапазона ячеек. Когда в последующей процедуре добавляются в пустые ячейки этих диапазонов значения, формула в ячейке вместо числа выдает #ЗНАЧ, пишет, что несоответствующий тип данных и, естественно нарушает все последующие действия в процедуре.
      Я попробовал вставлять в ячейки значения =СLng(i), как вы и говорили, но это не помогает. Да и это происходит при пошаговой проверке через F8. Когда это в цикле происходит, то выдает какую-то другую ошибку.Когда же через F8, то формула в ячейке меняет значение с числа на #ЗНАЧ(это происходит именно в момент вставки числа в пустую ячейку из диапазона), а в процедуре перескакивает на выполнение функции и начинает многократно ее выполнять и заполняет и остальные значения с формулами величинами #ЗНАЧ. Как еще с этим можно бороться? Когда вручную вставляешь значения в пустые ячейки, то ничего не происходит, машина правильно пересчитывает эту функцию

      1. Евгений

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

        1. Александр

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

        2. Александр

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

          1. Евгений

            Александр, у меня некоторые процедуры с циклами, запущенные из редактора VBA, начинают выполняться очень долго (сначала думал зависают, прерывал Ctrl+Break), хотя при нажатии на кнопку на рабочем листе выполняются моментально. Заметил это после перехода на 64-разрядную версию. Может быть и у вас нечто подобное.

    2. Александр

      У меня еще такой вопрос если можно.
      А где-то есть список математических функций VBA, чтобы не пользоваться встроенными функциями эксела? Там, например, среднее, минимум, максимум, корень, логарифм и т.д.?

      1. Евгений

        Без встроенных математических функций рабочего листа (WorksheetFunction) не обойтись, так как в VBA их очень мало.

    3. Здравствуйте,
      Не вижу что бы кто то в комментарии писал , поэтому вопрос

      После добавления комментариев к функции Делимое — не закомментирован , почему ?
      В моем тестовом варианте не воспринимает наоборот делитель

    4. Сделал пару функций для личных нужд, но вдруг кому из читающих пригодятся. Если же умные люди найдут, что их можно оптимизировать, только спасибо.
      У нас в организации графики делают с цветовым обозначением смен. Разных смен много, цветов много. А хотелось бы автоматизировать подсчет значений по сменам.
      Первая функция просто вытаскивает код цвета из ячейки. Она скорее утилитарное значение имеет (не нашел аналогов в стандартных)

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

      А в целом спасибо за ваш ресурс, очень помогает в саморазвитии )

    5. Извиняюсь сразу, если глупый вопрос, но искал несколько раз и так и не нашел ответ.
      При добавлении функции в личную книгу макросов я могу её вызвать через «Вставить функцию» (Insert Function), она всегда вставляется как Personal.xlsb!Имя функции.

      Если я правильно понял, если сделано по уму, то функцию можно набирать без personal.xlsb. А как это сделать по уму — нигде не могу найти и понять сам…

      1. Евгений

        Добрый день, Sergey!
        Если функция размещена в личной книге макросов, имя книги (Personal.xlsb) должно быть указано, иначе Excel будет искать эту функцию в текущей книге, не найдет и возвратит ошибку «#ИМЯ?».

        1. Спасибо, Евгений.
          А есть возможность макросом записывать функцию в открытую книгу, чтобы каждый раз через алт+ф11 не копировать из модуля в модуль?
          А то так себе удобство получается…

    6. Віталій

      =НАЙТИ("В";A2) Мне нужно в этой формуле вместо конкретного текстового фрагмента (в данном случае "В") указать текстовую переменную, например =НАЙТИ(текст.перем;A2), поскольку функция используется в цикле и искомые значения разные. Как я могу это сделать?

      1. Евгений

        Привет, Віталій!
        Если текстовую переменную назвать myTxt, тогда
        "=НАЙТИ(" & myTxt & ";A2)"

        1. Віталій

          Здравствуйте, Евгений.
          Был немного занят, поэтому не сразу попытался применить формулу по Вашему совету.
          Но… В моем примере (вместо текстового значения "В" для большей наглядности искал "cloud") получается подстановка в формулу =НАЙТИ(cloud;$A2), то есть текстовое значение не в кавычках, следовательно, в ячейке А2 ищется не "cloud", а нечто по ссылке на cloud.
          Фрагмент кода таков:

          В результате получаем =НАЙТИ(cloud;$A2). А хочется очень получить =НАЙТИ("cloud";$A2)

          Я не сильный специалист в VBA, понимаю, что с основами проблемы, но задача у меня разовая и ради нее выучить язык досконально кажется не очень целесообразным. Поиск в интернете по теме синтаксиса, подстановок в формулы переменных значений делал, но все как-то или бедно, или не о том. Буду благодарен, если поможете заключить cloud в кавычки в итоговой формуле.

          1. Евгений

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

            1. Віталій

              Спасибо огромное, у меня получилось. Уррра.
              Но как-то все-таки сложно, не думаю, что это так редко встречающаяся операция — поиск изменяющегося в цикле текста, почему это не предусмотрено стандартными средствами языка? Вопрос не Вам, конечно.

              А вот еще вопрос, который мучает меня много дней.
              Если, находясь на рабочем листе, выделить диапазон ячеек и нажать Ctrl-F, в открывшейся форме поиска ввести искомую строку и нажать «Найти все» — получим список всех найденных ячеек с вхождением искомого текста. А ниже, типа в строке статистики, написано, например, 227 ячеек найдено. Так вот вопрос: существует ли какой-либо способ получить вот эту цифру 227 из примера средствами VBA.
              Я реализовал эту задачу с помощью цикла, но это занимает на порядок(-ки) больше времени…

              1. Евгений

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

                1. Віталій

                  Присвоил значения ячеек диапазона переменной массива, но тут опять незадача: известные мне функции поиска, такие как ПОИСК, НАЙТИ, ПСТР… легко работают с данными в ячейках таблицы, но я не смог заставить их работать с элементами массива. Или не те инструменты рассматриваю?
                  Задача заключается в том, чтобы найти количество вхождений заданного текста в ячейках одного столбца, текст этот в ячейке может быть как целиком, так и являться фрагментом ячейки (или элемента массива после присвоения массиву значений ячеек заданного диапазона). С виду элементарная задача, но при большом количестве данных (в моем случае ок. 6000 строк) приходится долго смотреть в потолок.
                  И еще обнаружил странную вещь: если вот это

                  1. Евгений

                    Віталій, похоже я нашел, как получить число ячеек с искомым текстом в заданном диапазоне средствами VBA. Попробуйте метод WorksheetFunction.CountIf.

                    Неработающую функцию =MUTCH замените на =MATCH.

                    1. Віталій

                      Опечатка.
                      Спасибо, попробую уже позже, устал бороться.

    7. Здравствуйте! сделал по инструкции в статье функцию. при попытке компиляции выдает ошибку
      «Syntax error». Что тут не так?
      В качестве ошибочного элемента выделяет оператор присваивания (:=)

      1. Евгений

        Здравствуйте, Даниил!
        Попробуйте убрать пробелы перед и после :=.

        1. Здравствуйте! Попробовал убрать пробелы. Не проходит. мне надо чтобы в нижней части формы пользовательской функции были описание назначения функции и аргументов и не было сообщения «справка недоступна». как понимаю это можно сделать только через метод MacroOptions

          1. Евгений

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

            Проверил у себя — работает.

    8. Здравствуйте! А как можно сделать одну функцию для кучи кнопок
      код кнопок идентичный

      Вопрос можно как-то сделать одну функцию а кнопками её вызывать?

      1. Евгений

        Здравствуйте, Юрий!
        Вставьте общую процедуру в стандартный модуль и вызывайте ее из процедур нажатия кнопок. Например, для вызова процедуры Primer() из модуля Module1 код будет таким:

        Ключевое слово Call можно не указывать, но по нему сразу видно, что происходит вызов сторонней процедуры.

    Обсуждение закрыто.