Создать макросом/функцией другой макрос/функцию и выполнить его/ee.

Автор calc4fem, 25 ноября 2012, 21:25

0 Пользователи и 1 гость просматривают эту тему.

calc4fem

Давно как то интересовался этим вопросом, но воспроизвести так и не получилось.
например макрос

sub test

'создаем функцию ff1 в модуле
Function ff1(a,b)
ff1=a+b
End Function

далее по ходу выполнения макроса обращаемся к этой функции

var123=ff1(3,6)

end sub

как то так в общем.

Hasim

Как-то так.
Функция создается в новом модуле New_Module.

Sub InsertFunction
   oBLibs = BasicLibraries
   oBL =  oBLibs.getByName("Standard")

' Код функции в виде строки
    s = "Function ff1(a,b)" & CHR(10) & "ff1=a+b" & CHR(10) & "End Function" & CHR(10)

' Записывается код функции в новый модуль
If Not oBL.hasByName("New_Module") Then
    oBL.insertByName("New_Module", s)
End If

' Выполняется новая функция
If oBL.hasByName("New_Module") Then
var123=ff1(3,6)
MsgBox var123
End If

End Sub



calc4fem

ого спасибо!
А вот странно почему этот код удаляет модуль а вставляет его опять через раз
мистика какая то. Как правильно заменить вставленную функцию для повторного использования (повторной вставки)?

Function TableOfResults( formula As String , LowerPoint As Double, UpperPoint As Double, NumOfValues As Integer) As Variable

'Create UserFunction in the New Module
  oBLibs = BasicLibraries
  oBL =  oBLibs.getByName("Standard")

'Text of new Function
Dim TextOfFunction As String

TextOfFunction = "Function results_by_formula(x)" & CHR(10) & "results_by_formula="& Str(formula) & CHR(10) & "End Function" & CHR(10)  

'Write the test of new function into the new module

If oBL.hasByName("New_Module") Then oBL.removeByName("New_Module")

oBL.insertByName("New_Module", TextOfFunction)

'.....to be continued

End Function

Hasim

Цитата: calc4fem от 26 ноября 2012, 03:49почему этот код удаляет модуль а вставляет его опять через раз

Нужно закрыть окно редактора Basic (спасибо mathnew за подсказку), повесить макрос, например fff на панель инструментов (создать кнопку) и запускать макрос с панели инструментов при закрытом окне редактора Basic.

Макрос теперь срабатывает без пропусков, каждый раз перезаписывая функцию.

Sub fff
For n=1 To 10
   s = "Function ff1(a,b)" & CHR(10) & "ff1=a+b+" & Trim(Str(n)) & CHR(10) & "End Function" & CHR(10)
InsertFunction(s)
Next n
End Sub


Sub InsertFunction(s)
  oBLibs = BasicLibraries
  oBL =  oBLibs.getByName("Standard")

If oBL.hasByName("New_Module") Then
   oBL.removeByName("New_Module")
End If

' Записывается код функции в новый модуль
If Not oBL.hasByName("New_Module") Then
   oBL.insertByName("New_Module", s)
End If

' Выполняется новая функция
If oBL.hasByName("New_Module") Then
var123=ff1(3,6)
MsgBox var123
End If

End Sub




calc4fem

да - кстати спасибо
дело было в открытом модуле потому и через раз. вот пример функции на эту тему (без обработчика ошибок код - надо вводить переменную корректно, а то будет двадцать раз MsgBox)



[вложение удалено Администратором]

Hasim

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

calc4fem

спасибо вам за подсказку
обнаружил что в ООо бэйсик свободно работает рекурсия (ссылка например функции на саму себя). то есть это нормально - просто я раньше не задавался вопросом. Тот же факториал числа.

Function factori(n)

If n=0 Then factori=1
If n=1 Then factori=1
If n>1 Then factori=factori(n-1)*n

End Function


У функций массива есть один недостаток который связан с тем, что например в данном примере для того чтобы поменять количество точек (количество строк) на большее
нужно функцию выделить, потом удалить, и ввести снова. иначе выданы будут не все значения. если ввести функцию с меньшим числом точек - то в оставшихся с предыдущего ввода будет возвращено N/A (not applicable)
Чтобы преодолеть эти особенности функция массива - я делаю обычно так. Массив для результата беру больше чем это может быть нужно с запасом (например таблица может содержать 15-20 строк, редко 50, я беру в коде массив на 50 в запас) а чтобы не было неряшливо перед определением результата ставлю во всех ячейках пустой текст  " "
у меня есть идея как это можно было бы преодолеть программно - я имею в виду этот недостаток. например чтобы функция искала свою ячейку куда введена, а потом удаляла все данные что ниже и возвращала массив нужной величины на ячейку ниже.

JohnSUN

Цитата: calc4fem от 28 ноября 2012, 16:38
у меня есть идея как это можно было бы преодолеть программно - я имею в виду этот недостаток. например чтобы функция искала свою ячейку куда введена, а потом удаляла все данные что ниже и возвращала массив нужной величины на ячейку ниже.
А вот этот фокус, к сожалению, провернуть не удастся: во время пересчета функции ТЕКУЩИЙ лист (на котором расположена рассчитываемая ячейка) блокируется от изменений. В соседних листах и в других книгах делай что хочешь, а на текущем листе - ни-ни... И в принципе это правильно
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

calc4fem

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

JohnSUN

Ну, для "простоты" уже придумали несколько вариантов... Например, передавать в функцию в явном виде (например, строкой) диапазон, подготовленный для результата. Или отдельными параметрами указать количество строк-колонок отведенных под него. Или оформить весь алгоритм не функцией, а процедурой - пусть она вычисляет сколько строк-колонок потребуется для результата и вставляет в эти ячейки функцию массива, очищая ячейки, которые в этот раз не понадобятся...
А, вообще-то, это обсуждение уже отклонение от первоначально объявленной темы.
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

calc4fem

а можно ли как то запустить макрос из функции. я понимаю что нельзя,но если очень хочется?

Hasim

Можно, но с ограничениями (типа указанных JohnSUN).
Простейший пример:
Global nn As Integer

Sub Main1
nn = nn + 1
MsgBox nn
End Sub


Function FU() As Integer
Main1
FU=nn
End Function



[вложение удалено Администратором]

calc4fem

Спасибо. Попробовал с имеющимися у меня макросами (довольно сложными). http://sourceforge.net/projects/calc4fem/
Например макрос main
Функция
Function Fu()
main
Fu=1
End Function

Из пяти запусков 2 раза программа упала. Например падает когда запускаю
main
main
Может быть из за параллельного обращения к одним и тем же данным
А какие в общим ограничения? Можно ли найти формулировку чтобы понять?

Hasim

Вставил FU с двумя main в ваш ODS на лист UserFun в Н1, не вникая.
Global nn As Integer
Function Fu()
main
main
Fu=nn
End Function

Работает, не падая.
Выполняются оба main (Н1 увеличивается на 2, счетчик добавлен в main)
Пересчет функции FU() выполняется при изменении данных на листе, или просто при нажатии Delete на пустой ячейке.



[вложение удалено Администратором]

calc4fem

Libre3.5/Ubuntu при первом запуске упало. При повторном открытии работало без падений. Проверю потом на винде