Форум поддержки пользователей. LibreOffice, Apache OpenOffice, OpenOffice.org

Форум поддержки пользователей. LibreOffice, Apache OpenOffice, OpenOffice.org

11 Декабрь 2019, 14:35 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости: Часто задаваемые вопросы по LibreOffice и Apache OpenOffice.org
 
   Начало   Помощь Поиск Войти Регистрация    задать вопрос  
Страниц: 1   Вниз
  Печать  
Автор Тема: Остановка выполнения макроса  (Прочитано 1381 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Kadet
Форумчанин
***
Offline Offline

Сообщений: 220


« Стартовое сообщение: 19 Октябрь 2019, 10:13 »

Обыскал интернет не могу найти ответ.
В работе часто появляется следующая ситуация. Есть макросы, которые выполняются долго. Для объяснения обзовём Макро1 и Макро2, подразумевая при этом, что это один и тот же макрос, запущенный в разное время.
Так вот. Запускается Макро1 и начинает долго выполняться (заполнение таблиц). Оператор, не дождавшись окончания выполнения Макро1, заполняет фильтр и запускает этот же макрос (Макро2) повторно.
Получается следующая ситуация: Макро1 выполняется и во время этого запускается Макро2. Макро1 приостанавливается (засыпает) и начинает исполняться Макро2. После того, как Макро2 закончит исполнение (обычно второй запуск недолгий) Макро1 снова просыпается и продолжает исполняться.
В итоге вылезают некоторые нежелательные кракозябры и косяки.

Так вот, хочу найти способ при повторном запуске одного и того же макроса (Макро2) первый запуск этого макроса (Макро1) прекращал работу окончательно, а не приостанавливался, и потом не возобновлялся.

Должна быть какая-то команда. Пока не могу найти её.
Записан
Kadet
Форумчанин
***
Offline Offline

Сообщений: 220


« Ответ #1: 19 Октябрь 2019, 12:03 »

Клавиатурой это делается Ctrl+Shift+Q.
Если есть возможность остановки макросов клавиатурой, то должен быть соответствующий метод командой из макроса.
Записан
mikekaganski
Мастер
*****
Online Online

Пол: Мужской
Расположение: Хабаровск -> Москва
Сообщений: 1 627


« Ответ #2: 19 Октябрь 2019, 12:21 »

Клавиатурой это делается Ctrl+Shift+Q.
Если есть возможность остановки макросов клавиатурой, то должен быть соответствующий метод командой из макроса.

Естественно; эта комбинация клавиш (переназначаемая в Tools->Customize...) выполняет ".uno:BasicBreak". Но вот проблема: эта команда останавливает любой макрос; и если попытаться из макроса, который выполняется параллельно с другим, эту команду выполнить, остановятся оба. Ну и ещё вылезет диалог - он там вызывается без вариантов.

Можно попробовать по-другому (я не знаю подробностей Вашего макроса, и поэтому оно может быть неприменимо в Вашем случае): создать глобальную переменную-счётчик параллельно выполняемых макросов, и в начале функции делать инкремент её, а затем цикл ожидания, пока она станет равной 1; в теле в цикл вставить проверку, что она равна 1, и если больше - декремент и прерывание выполнения; в конце декремент. Оно может сработать - но только если принципиально невозможно получить три и больше параллельно выполняемых макроса...
« Последнее редактирование: 19 Октябрь 2019, 12:30 от mikekaganski » Записан

С уважением,
Михаил Каганский
Kadet
Форумчанин
***
Offline Offline

Сообщений: 220


« Ответ #3: 19 Октябрь 2019, 12:49 »

Спасибо за наводку. Я поковыряюсь в ".uno:BasicBreak". Возможно, что-нибудь накопаю в этом направлении. Какие-нибудь варианты.
По большому счёту в моей программе при выполнении текущего макроса фоновое выполнение всех прочих не существенно. Лишь бы перехватчики не вырубались. При необходимости прочие макросы и потом можно и повторно запустить.
Выброс окна, конечно, вещь нежелательная.

Второй вариант, со счётчиком, мне кажется не очень удобным. Ведь счётчик, как мне кажется, может приостановить или вовсе остановить исполнение Макро2, а не Макро1. А в процессе работы именно Макро2 является более важным, чем Макро1. И выполнение Макро1 нужно останавливать, а не Макро2.
К тому же, если не останавливать Макро2 по счётчику, а приостанавливать (т.е. зациклить режим ожидания выполнения Макро1), то не факт, что Макро1 при этом продолжит работу, ведь он останавливается аппаратно (самой LO) и именно Макро1 ждёт выполнения Макро2, а потом сам начинает продолжать. Может получиться вечное ожидание друг-друга.
Записан
mikekaganski
Мастер
*****
Online Online

Пол: Мужской
Расположение: Хабаровск -> Москва
Сообщений: 1 627


« Ответ #4: 19 Октябрь 2019, 13:11 »

Для объяснения обзовём Макро1 и Макро2, подразумевая при этом, что это один и тот же макрос, запущенный в разное время.

Итак, это один и тот же макрос.

Код:
Global MyMacroCounter As Long

Sub Macro
  On Error Resume Next
  ' Prevent running macros in parallel
  MyMacroCounter = MyMacroCounter + 1
  Do While MyMacroCounter > 1
    Wait 1
  Loop
  ' Now that we are alone, run actual code
  MacroImpl()
  ' Always decrement counter after exiting MacroImpl
  MyMacroCounter = MyMacroCounter - 1
End Sub

Sub MacroImpl
  ' ... some slow code
  ' A check somewhere in a loop
  If MyMacroCounter > 1 Then Exit Sub
  ' ... more slow code
End Sub
Записан

С уважением,
Михаил Каганский
mikekaganski
Мастер
*****
Online Online

Пол: Мужской
Расположение: Хабаровск -> Москва
Сообщений: 1 627


« Ответ #5: 19 Октябрь 2019, 13:53 »

ведь он останавливается аппаратно (самой LO) и именно Макро1 ждёт выполнения Макро2, а потом сам начинает продолжать. Может получиться вечное ожидание друг-друга

Ага, я об этом не подумал. Почему-то я решил, что оно работает в параллельных потоках.

Тогда надо сделать примерно то же самое, только без декремента:

Код:
Global MyMacroCounter As Long

Sub Macro
  Dim InitialMacroCount As Long
  InitialMacroCount = MyMacroCounter ' Remember initial value
  ' ... some slow code
  ' A check somewhere in a loop: if MyMacroCounter has incremented,
  ' then in the meanwhile, another macro instance was successfully run
  If MyMacroCounter > InitialMacroCount Then Exit Sub
  ' ... more slow code
  ' Increment counter after success
  MyMacroCounter = MyMacroCounter + 1
End Sub
Записан

С уважением,
Михаил Каганский
Kadet
Форумчанин
***
Offline Offline

Сообщений: 220


« Ответ #6: 19 Октябрь 2019, 13:58 »

mikekaganski, ну я так и понял. Единственное, вы предлагаете проверять счётчик в промежуточной (предзапускной) процедуре Macro. Тогда, конечно, приостановки первой запущенной процедуры не происходит.
Но, изменять счётчик (MyMacroCounter = MyMacroCounter - 1) нужно и в конце самой процедуры MacroImpl, а не только в предзапускной, иначе мы попадаем в вечный цикл.

Однако, спасибо, но опять таки, запуск Макро2 будет отложен до завершения работы Макро1. А мне нужно наоборот: при запуске Макро2 вообще прекратить выполнение Макро1.
Записан
Kadet
Форумчанин
***
Offline Offline

Сообщений: 220


« Ответ #7: 19 Октябрь 2019, 14:05 »

mikekaganski, ну, в принципе в длинном макросе идёт много вложенных циклов, поэтому-то он и длинный. В принципе проверку
Код:
If MyMacroCounter > InitialMacroCount Then Exit Sub
можно поставить в начале главного цикла, чтобы при каждой итерации проводил проверку и при MyMacroCounter>1 выбрасывал через Exit Sub. Тогда да. Вылетает именно Макро1, а Макро2, после уменьшения счётчика, запустится.

Спасибо за идею.
Записан
rami
Гуру
*******
Offline Offline

Пол: Мужской
Сообщений: 2 833


MacBook Pro, LibreOffice и Apache OpenOffice


« Ответ #8: 19 Октябрь 2019, 14:05 »

Выброс окна, конечно, вещь нежелательная.
Есть ещё .uno: BasicStop он останавливает без окна.
Записан

Kadet
Форумчанин
***
Offline Offline

Сообщений: 220


« Ответ #9: 19 Октябрь 2019, 14:19 »

rami, спасибо. Попробую.
Записан
Kadet
Форумчанин
***
Offline Offline

Сообщений: 220


« Ответ #10: 19 Октябрь 2019, 14:35 »

Спасибо за помощь. Вопрос решил ".uno:BasicStop"
Код:
Dim dispatcher
Dim document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
' dispatcher.executeDispatch(document, ".uno:BasicBreak", "", 0, Array())
dispatcher.executeDispatch(document, ".uno:BasicStop", "", 0, Array())
Поставил этот код в самый конец процедуры формирования таблиц. Останавливает все макросы. Перехватчики не выключаются.
В общем - всё устраивает.
« Последнее редактирование: 19 Октябрь 2019, 14:37 от Kadet » Записан
Kadet
Форумчанин
***
Offline Offline

Сообщений: 220


« Ответ #11: 19 Октябрь 2019, 16:24 »

Хотел таки воспользоваться идеей mikekaganski со счётчиком в другом месте. Там макросы исполняются последовательно - второй ждёт первого. Но не получилось.
Там два перехватчика отслеживают изменения значений двух ячеек Calc и в итоге вызывают один и тот же макрос. А ячейки играют роль фильтров. Так вот, в отличие от запуска макросов, тут второй Листенер не начинает работу, пока не закончит работу первый, а первый не заканчивается пока не закончит работу вызванный из него макрос. Именно его и желательно периодически останавливать. В общем из-за этого ожидания счётчик просто не срабатывае - всегда в работе только одна версия макроса.

Однако, идея mikekaganski с проверкой внутри цикла макроса оказалась полезной. Внедрил в цикл макроса проверку первичных значений этих ячеек, и если они изменяются, то Exit Sub. И начинает работать второй Листенер.

Спасибо за помощь!
« Последнее редактирование: 19 Октябрь 2019, 16:27 от Kadet » Записан
Kadet
Форумчанин
***
Offline Offline

Сообщений: 220


« Ответ #12: 5 Ноябрь 2019, 14:39 »

И ещё один непростой, для меня, вопрос. Может тоже подскажите как это решить.
Во вложенных документах calc по клику мыши (по событию "mouseReleased" - отжатие) выполняется первичное форматирование листа. Так вот иногда после подобного клика кнопка как бы не сбрасывается, а происходит как бы "удержание кнопки мыши", хотя этого на самом деле нет. Просто мышкой водишь, а за ней голубое окошко тянется.
Как можно макросом сбросить это фальшивое "удержание", выделение области.
Записан
Страниц: 1   Вверх
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!