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

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

22 Январь 2022, 20:50 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости: Часто задаваемые вопросы по LibreOffice и Apache OpenOffice.org
 
   Начало   Помощь Поиск Войти Регистрация    задать вопрос  
Страниц: 1 2 »   Вниз
  Печать  
Автор Тема: Как подключить Menu Event Listener ?  (Прочитано 1616 раз)
0 Пользователей и 1 Гость смотрят эту тему.
eeigor
Опытный пользователь
***
Offline Offline

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



« Стартовое сообщение: 26 Ноябрь 2021, 07:46 »

Как подключить прослушиватель событий меню для отслеживания изменения конкретного параметра:
Tools - Options - LibreOffice Calc - Calculate - Search criteria = and <> must apply to whole cells

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

С указанным параметром непосредственно связано свойство ThisComponent.MatchWholeCell и свойство SearchCriteria в файле реестра.

P.S. У дескриптора фильтра есть только два свойства, которые я могу задать сам перед фильтрацией согласно установкам пользователя: Case sensitive и Regular expressions (на листе есть также два одноимённых флажка). Это удобно. Но указанный выше параметр влияет на поиск с использованием регулярных выражений, и надо синхронизировать состояние третьего одноимённого флажка на листе.
« Последнее редактирование: 26 Ноябрь 2021, 08:26 от eeigor » Записан

Ubuntu 18.04 LTS • LO 7.2.4.1 Community
mikekaganski
Гуру
*******
Online Online

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


« Ответ #1: 26 Ноябрь 2021, 09:56 »

Что-то вроде

Код:
Sub StartListening
  Dim oManager As Object, oConfigProvider As Object, oConfigAccess As Object, oListener As Object
  Dim aArg(0 to 0) As New com.sun.star.beans.PropertyValue
  oManager = GetProcessServiceManager()
  oConfigProvider = oManager.createInstance("com.sun.star.configuration.ConfigurationProvider")
  aArg(0).Name = "nodepath"
  aArg(0).Value = "/org.openoffice.Office.Calc/Calculate/Other"
  oConfigAccess = oConfigProvider.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", aArg)
  oListener = CreateUnoListener("SearchCriteriaListener_", "com.sun.star.beans.XPropertyChangeListener")
  oConfigAccess.addPropertyChangeListener("", oListener)
End Sub

Sub SearchCriteriaListener_propertyChange(oEvent)
  If oEvent.PropertyName = "SearchCriteria" Then
    MsgBox "New value: " & oEvent.Source.SearchCriteria
  End If
End Sub

Или лучше вместо

Код:
oConfigAccess.addPropertyChangeListener("", oListener)

использовать

Код:
oConfigAccess.addPropertyChangeListener("SearchCriteria", oListener)

и упростить обработчик:

Код:
Sub SearchCriteriaListener_propertyChange(oEvent)
  MsgBox "New value: " & oEvent.Source.SearchCriteria
End Sub
« Последнее редактирование: 26 Ноябрь 2021, 10:15 от mikekaganski » Записан

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

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


« Ответ #2: 26 Ноябрь 2021, 10:26 »

Но указанный выше параметр влияет на поиск с использованием регулярных выражений

И не только с использованием регулярных выражений (см. https://forumooo.ru/index.php/topic,8469.45/msg,60298.html)
Записан

С уважением,
Михаил Каганский
eeigor
Опытный пользователь
***
Offline Offline

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



« Ответ #3: 26 Ноябрь 2021, 13:50 »

Михаил, большое спасибо за отклик. Опробую только в воскресенье и отпишусь.
Смутило, конечно, что решение дано через:
oConfigAccess.addPropertyChangeListener("SearchCriteria", oListener)

Мне казалось, что через меню Calc’а как-то тоже можно было и проще… Но я этого никогда не делал.
« Последнее редактирование: 26 Ноябрь 2021, 15:33 от eeigor » Записан

Ubuntu 18.04 LTS • LO 7.2.4.1 Community
mikekaganski
Гуру
*******
Online Online

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


« Ответ #4: 26 Ноябрь 2021, 14:06 »

Любые настройки программы проще и правильнее всего отслеживать через доступ к конфигурации (com.sun.star.configuration.ConfigurationAccess). Я не имею представления, что это за способ через меню, но даже если он есть, он был бы совершенно неправильным решением, т.к. эту настройку можно изменить кучей способов помимо "меню". Именно неиспользование правильного отслеживания настроек ответственно за баги типа tdf#132145 "com.sun.star.sheet.GlobalSheetSettings" properties, "org.openoffice.Office.Math" and "org.openoffice.Office.Calc/Input/" entries are not synchronized и иже с ним.
« Последнее редактирование: 26 Ноябрь 2021, 14:12 от mikekaganski » Записан

С уважением,
Михаил Каганский
eeigor
Опытный пользователь
***
Offline Offline

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



« Ответ #5: 26 Ноябрь 2021, 15:37 »

Спасибо. Я обязательно попробую, как представится возможность.
Надеюсь, что в этот раз Улыбка я достаточно обстоятельно и в то же время кратко описал проблему…
Записан

Ubuntu 18.04 LTS • LO 7.2.4.1 Community
eeigor
Опытный пользователь
***
Offline Offline

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



« Ответ #6: 27 Ноябрь 2021, 20:54 »

Михаил, код работает. Благодарю за помощь.
Мы пока не можем (можем, конечно) изменить значение некоторых параметров через реестр, поскольку требуется перезагрузка приложения (известная проблема, поднятая ещё А.Питоньяком давным давно). Зато можем отследить изменение параметра пользователем. И в моём случае это оказалось важно.

Замечена некоторая погрешность, с темой этого поста не связанная.
Если я изменяю значение рассмотренного здесь параметра (сбрасываю или устанавливаю флажок), а затем, не закрывая окна диалога, нажимаю кнопку Apply (Применить), то значения параметра визуально отменяется (устанавливается обратно или сбрасывается соответственно), но после закрытия/открытия окна диалога параметр всё равно установлен верно, в соответствии со значением реестра.
Записан

Ubuntu 18.04 LTS • LO 7.2.4.1 Community
eeigor
Опытный пользователь
***
Offline Offline

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



« Ответ #7: 27 Ноябрь 2021, 22:56 »

Михаил, я несколько развернул код, но заметил странность:
глобальная переменная не устанавливается (Is Null), соответственно остановить слушатель нельзя.
Впрочем, мне так и надо, чтобы он работал на всём протяжении работы приложения.
Но, вроде как, я должен обозначить процедуру:
Sub SearchCriteriaListener_disposing(oEvent): End Sub

В Вашем примере локальная переменная oListener запускает слушатель, и он работает, пока открыт файл:
oListener = CreateUnoListener("SearchCriteriaListener_", "com.sun.star.beans.XPropertyChangeListener")

Вопрос носит чисто теоретический характер: что не так с обработчиком com.sun.star.beans.XPropertyChangeListener ?

Приведу пример своей версии кода (ключевой блок, написанный Вами, остался прежним).
'
Код:
'''''''''''''''''''' SearchCriteria PropertyChangeListener '''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Global oConfigAccess As Object
Global oSearchCriteriaListener As Object

Sub StartSearchCriteriaListener()
If Not IsNull(oSearchCriteriaListener) Then Exit Sub  'just to be sure it doesn't start twice

Dim oManager As Object, oConfigProvider As Object  ', oConfigAccess As Object
Dim aArg(0) As New com.sun.star.beans.PropertyValue

oManager = GetProcessServiceManager()
oConfigProvider = oManager.createInstance("com.sun.star.configuration.ConfigurationProvider")
aArg(0).Name = "nodepath"
aArg(0).Value = "/org.openoffice.Office.Calc/Calculate/Other"
oConfigAccess = oConfigProvider _
.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", aArg)

oSearchCriteriaListener = CreateUnoListener("SearchCriteriaListener_", "com.sun.star.beans.XPropertyChangeListener")
oConfigAccess.addPropertyChangeListener("SearchCriteria", oSearchCriteriaListener)
End Sub

Sub StopSearchCriteriaListener()
If IsNull(oSearchCriteriaListener) Then Exit Sub  'only if still running

oConfigAccess.removePropertyChangeListener("SearchCriteria", oSearchCriteriaListener)
oSearchCriteriaListener = Nothing  'to know later the listener has stopt
End Sub

'Sub SearchCriteriaListener_disposing(oEvent)
''' Remarks: In the case of configuration listeners, disposing will never be called,
''' because Basic will be unloaded earlier than the configuration.
''' So it's not needed here.
' Call StopSearchCriteriaListener
'End Sub

Sub SearchCriteriaListener_propertyChange(oEvent)
MsgBox "New value: " & oEvent.Source.SearchCriteria
End Sub

Таким образом, Михаил, Ваш код оказывается необходимым и достаточным, а всё, что я добавил, ничего не дало. Но что-то здесь не так...
UPDATED: Код выше исправлен.

« Последнее редактирование: 28 Ноябрь 2021, 15:55 от eeigor » Записан

Ubuntu 18.04 LTS • LO 7.2.4.1 Community
mikekaganski
Гуру
*******
Online Online

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


« Ответ #8: 28 Ноябрь 2021, 12:53 »

Но, вроде как, я должен обозначить процедуру:
Sub SearchCriteriaListener_disposing(oEvent): End Sub

Не должны. Если соответствующий метод не найден, он не вызывается.
В случае слушателей конфигурации disposing никогда не вызовется, потому что Basic выгрузится раньше, чем конфигурация. Так что здесь он не нужен.

В Вашем примере локальная переменная oListener запускает слушатель

oListener не "запускает" слушатель, это и есть сам слушатель (точнее - count-referenced ссылка на него). "Запускает" слушатель вызов addPropertyChangeListener.

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

С уважением,
Михаил Каганский
eeigor
Опытный пользователь
***
Offline Offline

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



« Ответ #9: 28 Ноябрь 2021, 15:58 »

Михаил, спасибо ещё раз. Я поправил код. Действительно Global oConfigAccess выгружает тот же экземпляр слушателя. Всё работает. Но можно этого и не делать.
Думаю, что это решение ещё не раз пригодится. На других форумах я подобных решений не нашёл...
« Последнее редактирование: 28 Ноябрь 2021, 16:22 от eeigor » Записан

Ubuntu 18.04 LTS • LO 7.2.4.1 Community
sokol92
Опытный пользователь
***
Offline Offline

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


WWW
« Ответ #10: 28 Ноябрь 2021, 16:34 »

Добрый день!

Михаил, спасибо за, как всегда, интересные разъяснения!

Для меня один вопрос остается не понятным. Добавляем код из #1 в документ, запускаем слушатель. Закрываем документ и при следующей попытке корректировки соответствующего параметра LO ошибка не возникает (вопреки моим ожиданиям и аналогичным ситуациям в прошлом).

Вы пишите, что слушатель "сам выгрузится при последующей попытке его вызова". Это относится к данному конкретному случаю (слушателю) или есть какие-то общие правила?
Записан

Владимир.
eeigor
Опытный пользователь
***
Offline Offline

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



« Ответ #11: 28 Ноябрь 2021, 17:25 »

@sokol92, Ваш вопрос лично мне не совсем понятен. О какой ошибке идёт речь, если ошибка не возникает? В сообщение #7 показано, как выгрузить слушатель явно.
Записан

Ubuntu 18.04 LTS • LO 7.2.4.1 Community
sokol92
Опытный пользователь
***
Offline Offline

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


WWW
« Ответ #12: 28 Ноябрь 2021, 20:27 »

@eeigor, постараюсь сам понять свой вопрос. Улыбка

Я представлял процесс функционирования Listener (слушателя) в Basic следующим образом:

  1. Создаем слушателя путем вызова функции createUnoListener. Функция возвращает объект, поддерживающий соответствующий интерфейс. При вызове методов этого объекта (соответствующих событиям) слушатель вызывает макрос Basic с определенным именем.
  Для каждого события, которое может возникнуть, необходимо создать соответствующим макрос, иначе при возникновении события (после действия в пункте 2) возникнет ошибка времени выполнения.

  2. Добавляем слушатель к вещателю (Broadcaster) путем вызова соответствующего метода (обычно Add...Listener). С этого момента слушатель получает уведомление о каждом событии. Один и тот же слушатель может добавляться к вещателям несколько раз. Например, если мы повторно добавим слушателя к тому же самому вещателю, то наши макросы будут дважды вызываться при каждом событии.

  3. Если модуль Basic, в котором находится слушатель, принадлежит библиотеке документа, то необходимо перед закрытием документа отключиться от всех вещателей, к которым добавлялся слушатель. Для обеспечения этой возможности на шаге 2 нужно запомнить (в глобальные переменные) объекты (ссылки на объекты) слушателя и вещателя.

  Похоже, необходимость (выделенная в пункте 3 жирным шрифтом) отсутствует.

« Последнее редактирование: 28 Ноябрь 2021, 20:36 от sokol92 » Записан

Владимир.
eeigor
Опытный пользователь
***
Offline Offline

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



« Ответ #13: 28 Ноябрь 2021, 21:41 »

Выгружать слушатель по идее желательно (но по факту, если не выгружать - он сам выгрузится при последующей попытке его вызова).
В случае слушателей конфигурации disposing никогда не вызовется, потому что Basic выгрузится раньше, чем конфигурация. Так что здесь он не нужен.
@sokol92, вы всё пишите правильно. Но нельзя однозначно утверждать, что ваш пункт 3 не нужен. Он, как сказал Михаил, не нужен в моём конкретном случае.
А если я запускаю слушатель ещё раз, то количество запущенных слушателей увеличивается с каждым разом. Я полагаю, слушатель сам выгрузится не при попытке его вызова, а при закрытии приложения.

Но у меня с данной задачей всё получилось идеально.

P.S. А при вызове StopSearchCriteriaListener() метод SearchCriteriaListener_disposing(oEvent) всё равно не вызывается. С другими слушателями это не так.
« Последнее редактирование: 28 Ноябрь 2021, 22:23 от eeigor » Записан

Ubuntu 18.04 LTS • LO 7.2.4.1 Community
mikekaganski
Гуру
*******
Online Online

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


« Ответ #14: 29 Ноябрь 2021, 10:08 »

Для меня один вопрос остается не понятным. Добавляем код из #1 в документ, запускаем слушатель. Закрываем документ и при следующей попытке корректировки соответствующего параметра LO ошибка не возникает (вопреки моим ожиданиям и аналогичным ситуациям в прошлом).

Вы пишите, что слушатель "сам выгрузится при последующей попытке его вызова". Это относится к данному конкретному случаю (слушателю) или есть какие-то общие правила?

Правильный вопрос, и мне потребовался отладчик, чтобы ответить.
Я не совсем прав, слушатель никогда не выгрузится, если это не сделать вручную. Он просто не будет вызываться, поскольку у соответствующего объекта не будет родительского контейнера (см. BasicAllListener_Impl::firing_impl, где есть проверка while( pP->GetParent() )). Обнуление родителя происходит в момент выгрузки библиотеки (при выгрузке документа), а сам слушатель, поскольку имеет активные ссылки, не выгружается.

В принципе полагаться на такое правильное поведение опасно; с другой стороны, если в аналогичных случаях возникают краши, это однозначный баг (я надеюсь, что именно из-за исправления багов Вы видите теперь другое, правильное поведение). Ошибка Basic была бы разумной альтернативой (может, Вы видели именно такие ошибки?) - не знаю, возникнет ли она у слушателей других объектов, но судя по тому, что я вижу в коде, у любого слушателя из библиотек документов должен обнуляться родитель при выгрузке.

Я представлял процесс функционирования Listener (слушателя) в Basic следующим образом:

  1. Создаем слушателя путем вызова функции createUnoListener. Функция возвращает объект, поддерживающий соответствующий интерфейс. При вызове методов этого объекта (соответствующих событиям) слушатель вызывает макрос Basic с определенным именем.
  Для каждого события, которое может возникнуть, необходимо создать соответствующим макрос, иначе при возникновении события (после действия в пункте 2) возникнет ошибка времени выполнения.

Да. Именно при возникновении события. В случае слушателей конфигурации такого возникнуть не может.

  3. Если модуль Basic, в котором находится слушатель, принадлежит библиотеке документа, то необходимо перед закрытием документа отключиться от всех вещателей, к которым добавлялся слушатель. Для обеспечения этой возможности на шаге 2 нужно запомнить (в глобальные переменные) объекты (ссылки на объекты) слушателя и вещателя.

См. выше Улыбка

P.S. А при вызове StopSearchCriteriaListener() метод SearchCriteriaListener_disposing(oEvent) всё равно не вызывается. С другими слушателями это не так.

Он и не должен вызываться при отсоединении слушателя. См. XEventListener, где описан метод disposing:

Цитата:
gets called when the broadcaster is about to be disposed.

Он не имеет отношения к отсоединению слушателя, а только к уничтожению бродкастера (источника событий). В данном случае бродкастером является подсистема конфигурации. Она не уничтожается, пока Basic активен. К моменту её уничтожения все слушатели Basic уже сами будут уничтожены.

И у других слушателей должно быть то же самое.
Записан

С уважением,
Михаил Каганский
Страниц: 1 2 »   Вверх
  Печать  
 
Перейти в:  

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