Пользовательская функция Excel с параметрами - PullRequest
0 голосов
/ 30 августа 2018

Я пытаюсь создать пользовательскую функцию в модуле Excel следующим образом:

Function STATUS(valuex As String)

    If ActiveCell.Offset(0, 1).Value = valuex Then

    ActiveCell.Value = ActiveCell.Offset(0, -1).Value

    'Remove value from left column
     Activecell.offset(0,1).clearcontents

   End If

End Function

это в основном сделало бы это:

Number  Result  Status
          11    System
22              Type
          33    System
          44    System
55              Hardware
66              Type
          77    System
          88    System
99              Software
110             Type
         121    System
         132    System
143             Hardware
154             Type
165             Type
         176    System
187             Hardware
198             Type
209             Software

Если правая ячейка = значение x (например, строка «Система»), равно значению x, то поместите значение левой ячейки в ячейку формулы / функции и удалите значение левой колонки.

Но что бы я ни программировал, все, что он возвращает, - это ноль (0) или ошибка #.

Пожалуйста, помогите

Ответы [ 2 ]

0 голосов
/ 30 августа 2018

Вы пишете определяемую пользователем функцию (UDF), то есть Public Function в общедоступном стандартном модуле, которую можно вызывать из ячейки таблицы - и этот конкретный тип функции имеет определенный набор ограничений. Например, нельзя иметь побочных эффектов . UDF принимает некоторые входные данные, обрабатывает их, , а затем возвращает результат .

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

Public Function {name}({args}) As {type}

Самое первое, о чем нужно подумать, когда вы пишете функцию, это , что вам нужно, чтобы она возвратила - другими словами, , что должна делать ячейка с надписью =MYFUNCTION(A1,A2) содержать после расчета . Например, если вы написали функцию Add, которая добавляет два значения Double, вы захотите, чтобы она возвращала Double:

Public Function Add(ByVal value1 As Double, ByVal value2 As Double) As Double

Тело функции функции вычисляет результат из заданных параметров :

    Dim result As Double
    result = value1 + value2

Прежде чем он вернется / выйдет, вам нужно присвоить возвращаемое значение функции . Это делается путем присвоения идентификатору функции:

    Add = result

Механизм вычислений Excel затем принимает этот результат, и вот как ячейка с формулой, такой как =Add(2, 2), заканчивается значением 4.


Ваша функция STATUS зависит от ActiveCell, то есть от любой ячейки, выбранной в данный момент на ActiveSheet: , она НЕ является ячейкой, вызвавшей функцию . Пересчет рабочей книги с выбранной случайной ячейкой, скорее всего, даст неверные результаты.

Будучи UDF, он не может .ClearContents в ячейке (или влиять на любую другую ячейку каким-либо образом) - поэтому функция возвращает ошибку #NAME? для пути выполнения, который входит в условный блок и так как возвращаемое значение никогда не назначается, другой путь выполнения выдает 0, который является числовым представлением варианта Empty, который в настоящее время возвращает ваша функция.

Если UDF необходимо знать о значении другой ячейки, лучше всего принять значение этой ячейки в качестве параметра: таким образом, функция работает без каких-либо предположений о компоновке рабочего листа. Насколько полезным было бы VLOOKUP, если бы он не принимал аргумент lookup_value и вместо этого брал это значение из ячейки .Offset(0, 1)? Там будут бунты!


Когда вам нужно сделать что-то вместо вычислить / вычислить что-то , вам нужен не UDF, а макрос .

Макрос - это процедура без параметров Public Sub в общедоступном стандартном модуле (или модуле Worksheet), которую можно вызывать из окна «Макросы» или выполнять при нажатии пользователем Shape, ActiveX CommandButton, или они могут быть назначены свойству OnAction какого-либо пользовательского пункта меню - что бы ни раскачивало вашу лодку.

Sub процедуры делают что-то, они действия . Они могут получать доступ и изменять глобальное состояние, изменять любую ячейку, рабочую таблицу или рабочую книгу; они даже могут порождать экземпляр PowerPoint и вставлять диаграмму в виде картинки на новый Slide - все, о чем вы только могли подумать, небо - предел!

Поскольку то, что вам нужно, это то, что делает вещи , код, который вам нужно написать, должен быть больше похож на макрос. Не называйте это STATUS; используйте глагол и опишите, что он делает: вы перемещаете значения из одного столбца в другой, основываясь на заданных критериях. Когда вы пишете Sub процедуру, подумайте сначала о том, как вы хотите вызвать it.

Я думаю, что-то вроде этого было бы аккуратно:

MoveValues Sheet1.Range("$B$2:$B$22"), "System"

Таким образом, подпись будет выглядеть так:

Private Sub MoveValues(ByVal Target As Range, ByVal Criteria As String)

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

1114 * *

Теперь, если нам когда-нибудь понадобится вставить столбец между A и B или между B и C, нам нужно только изменить аргументы, которые мы передаем нашей процедуре, а не саму процедуру!

Private Sub MoveValues(ByVal Source As Range, ByVal Target As Range, ByVal Status As Range, ByVal Criteria As String)

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

Во многих случаях лучше всего поднять ошибку во время выполнения. Ошибка № 5 «Недопустимый вызов процедуры или аргумент», кажется, достаточно хорошо подходит:

    If Source.Columns.Count <> 1 Or Target.Columns.Count <> 1 Or  Status.Columns.Count <> 1 Or _
       Source.Rows.Count <> Target.Columns.Count Or _
       Status.Rows.Count <> Target.Columns.Count _
    Then
        Err.Raise 5
    End If

Мы даже можем настроить сообщение об ошибке, чтобы помочь нам отладить вызывающий код позже, когда мы изменим параметры через 6 месяцев и забыли все о предположениях этой MoveValues процедуры:

    If Source.Columns.Count <> 1 Or Target.Columns.Count <> 1 Or  Status.Columns.Count <> 1 Or _
       Source.Rows.Count <> Target.Columns.Count Or _
       Status.Rows.Count <> Target.Columns.Count _
    Then
        Err.Raise 5, "MoveValues", _
            "Source, Target, and Status ranges must be 1 column and the same number of rows."
    End If

Нам также нужно убедиться, что наш Criteria не пустой или просто пробел!

    If Trim$(Criteria) = vbNullString Then
        Err.Raise 5, "MoveValues", "Criteria string cannot be empty or whitespace."
    End If

Теперь, когда мы проверили наши входные данные , в остальной части процедуры можно смело предположить, что диапазоны Source, Target и Status представляют собой диапазоны из одного столбца, что они все одинакового размера, и у нас есть действующие критерии для работы. Итак, мы можем перейти к итерации ячеек и сделать свое дело:

    Dim current As Long
    For current = 1 To Target.Rows.Count
        If Status.Cells(current).Value = Criteria Then
            Target.Cells(current).Value = Source.Cells(current).Value
            Source.Cells(current).ClearContents 
        End If
    Next

Теперь осталось только написать макрос, который его вызывает:

Public Sub MoveSystemValues()
    With Sheet1
        MoveValues .Range("A2:A22"), .Range("B2:B22"), .Range("C2:C22"), "System"
    End With
End Sub

И теперь мы можем запустить этот макрос MoveSystemValues из окна Макросы в Excel или назначить MoveSystemValues некоторой Shape или кнопке ... и затем понять, что он работает довольно хорошо для небольшого количество рядов, но довольно медленное, учитывая большие диапазоны - но пока нам достаточно жевать.

0 голосов
/ 30 августа 2018

Вы не можете делать то, что хотите, с пользовательской функцией (UDF).

Вы начинаете в VBA, поэтому вам необходимо знать основное различие между SUBS и FUNCTIONS.

Сабвуферы выполняют действия с файлом Excel (такие действия, как выбор, очистка содержимого, изменение рабочих таблиц, открытие другой рабочей книги, выполнение расчетов и многое другое).

Функции возвращают значение, но не выполняют никаких действий . Думайте о них как о своей формуле Excel. Формулы в Excel не выполняют никаких действий, они просто возвращают значение, основанное на некоторых аргументах.

Подробнее здесь: http://excelhints.com/2009/02/12/difference-between-sub-and-function/

Так что вам нужно переписать ваш код как подпроцедуру и затем выполнить ее:)

ОБНОВЛЕНИЕ: То, что я сказал в предыдущих строках , не всегда на 100% верно . Я написал это, потому что для новичка в разработке кода на VBA я думаю, что это хорошая отправная точка. Когда вы новичок, и, с моей точки зрения, я думаю, что легче учиться, используя только подпрограммы для выполнения действий и используя только функции для получения индивидуальных вычислений. А затем, с некоторым опытом, перейдите на следующий уровень и начните объединять их и использовать их, чтобы делать более сложные вещи. Subs и функции могут быть объединены при выполнении кода.

Когда вы вызываете UDF из подпрограммы, может выполнять некоторые действия (например, удаление листа). И я сказал некоторые действия , потому что, если честно, я не знаю, доступны ли все действия.

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

Пример:

Public Function DeleteWorkSheet() As Boolean
Sheets(3).Delete
End Function

Этот UDF удалит третий лист моей книги.

Чтобы вызвать его из подпрограммы, это будет:

Sub Macro1()
DeleteWorkSheet
End Sub

И да, будет удален третий лист.

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

Надеюсь, это разъяснение поможет.

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