как правильно удалить ChangeListener из ListBox

Автор skar-1980, 18 октября 2023, 15:42

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

skar-1980

Всем доброго дня. Никак не могу выполнить дерегистрацию (удаление) слушателя, который привязан к элементу управления ListBox.

Есть выполнять .removeChangeListrer из процедуры, в которой регистрируется ChangeListener, тогда он не регистрируется.
Выполнение из других процедур, к результату не приводит.
Я попробовал через .event Source и через отдельную процедуру, Listener остается на месте.


Global lBCl 'после завершения процедуры ликвидируется
Global lBC

Sub Main

oD = ThisComponent
lB = oD.DrawPage.Forms.getByName("Форма").getByName("Список 1") 'com.sun.star.form.OListBoxModel
lBC = oD.CurrentController.getControl (lB) 'SwXTextView
'getControl ( xModel as com.sun.star.awt.XControlModel ) AS com.sun.star.awt.XControl                    com.sun.star.view.XControlAccess

lBCl = CreateUnoListener ("lBCfunc_", "com.sun.star.form.XChangeListener")
lBC.addChangeListener  (lBCl)'       ( aListener as com.sun.star.form.XChangeListener )
'https://forumooo.ru/index.php?action=search2
'https://wiki.openoffice.org/wiki/Documentation/DevGuide/Forms/Scripting_and_Events
'https://forumooo.ru/index.php?action=search2
End Sub

Sub lBCfunc_changed (event)

sNeedFieldName = "com.sun.star.text.FieldMaster.User.переменная"
oFieldMasters = ThisComponent.getTextFieldMasters()
oNeedField = oFieldMasters.getByName(sNeedFieldName)
'xray event.Source.getSelectedItem
oNeedField.Content=event.Source.getSelectedItem
oContent=oNeedField.Content
ThisComponent.getTextFields.refresh
MsgBox "lBCfunc_changed"

oD = ThisComponent
lB = ThisComponent.DrawPage.Forms.getByName("Форма").getByName("Список 1")
lBC = oD.CurrentController.getControl (lB)
lBCl = CreateUnoListener ("lBCfunc_", "com.sun.star.form.XChangeListener")
removeListenerGlobal
print "removeListenerGlobal from Sub lBCfunc_changed (event)"

event.Source.removeChangeListener (lBCl)

print "event.Source.removeChangeListener (lBCl) from Sub lBCfunc_changed (event)"
end Sub


Sub lBCfunc_disposing
print "lBCfunc_disposed"
end sub

Sub removeListenerGlobal
lBC.removeChangeListener (lBCl)
print "removeListenerGlobal"
end Sub


sub loadToolsFoCurrentDoc
dim listOfTooles () as string
dim libLoader as string
listOfTooles = Array ( "MRILib", "Tools", "back_up", "ScriptForge", "XrayTool")
i=1
for each elem in listOfTooles
GlobalScope.BasicLibraries.LoadLibrary(elem)
'print GlobalScope.BasicLibraries().isLibraryLoaded(elem)
libLoader = libLoader + CStr(i) + elem + ": " + GlobalScope.BasicLibraries().isLibraryLoaded(elem) + Chr(10)
i=i+1
next
MsgBox libLoader
end sub

Sub refreshListBox
'ThisComponent.DrawPage.Forms.getByName("Форма").getByName("Список 1").getModel.refresh
end Sub



sokol92

#1
Переменные lBCl и lBC описаны как Global и присваиваются в Main. После этого слушатель начинает работать.
При первом изменении элемента в списке вызывается lBCfunc_changed. В процедуре lBCfunc_changed нужно убрать присвоение lBCl и lBC и строку
event.Source.removeChangeListener (lBCl)Эта процедура, в частности, удаляет слушатель посредством вызова процедуры removeListenerGlobal.
При дальнейших изменениях списка слушатель не вызывается.

Попробуйте и сообщите, что не так.

Для элементов управления слушатели гораздо удобнее (и надежнее) устанавивать через Свойства элемента управления, вкладка События. Тогда запуск и остановка слушателя производятся автоматически.
Владимир.

skar-1980

#2
спасибо! все получилось ;D  ;D  ;D , не знаю, где я делал ошибку раньше.

Я наспотыкался на пути написания этого макроса: требовалось написать код для действия скрыть/показать раздел. Схема действий: раздел (скрыть по значению переменной), поле со списком (устанвить значение переменной).   

1. выбрать тип Слушателя. После поиска на форуме стало понятно, какой слушатель использовать:

ListBox (com.sun.star.form.OListBoxModel), далее получаем контроль  .CurrentController.getControl (сom.sun.star.form.OListBoxControl), что бы зарегистрировать Слушатель .addChangeListener

2. написать процедуры для Слушателя
- используем глобальные переменные, объявленные в модуле. (Питоньяк).
- написать все процедуры для Слушателя _change, _disposing
- из процедуры Слушателя _change работать с переменной для скрытия раздела

3. передать значение из поля со списком в переменную
доступ к переменным .getTextFieldMasters().getByName(oVar)
виды переменных:
- com.sun.star.text.FieldMaster.User.ИмяПеременной
- com.sun.star.text.FieldMaster.SetExpression.ИмяПеременной

обновляем значение переменных .getTextFields.refresh

4. регистрируем Слушатель
при первичной загрузке документа использовать ViewCreated (Просмотр создан), иначе не зарегистрируется

5. дерегистрировать Слушатель (вот здесь начались проблемы)
для этого нужны глобальные переменные, в них хранятся:
- первично созданный объект Слушателя createUnoListener ()
- контроль для поля со списком .CurrentController.getControl()

Без них глобальных (как я понял) не удается получить эти объекты для удаления .removeChangeListener. Один без другого, как я понял не хранится.

удаление Слушателя может быть вызвано из
- отдельной процедуры путем использования глобальных переменных .removeChangeListener ()
- из процедуры Слушателя _change () путем использования event.Source.removeChangeListener ()

... не понятно следующее:
Каждый раз при регистрации Слушателя создается новый объект? У меня получается, что если зарегистрировать слушатель 3 раза, а удалить из отдельной процедуры только 1 раз. Слушатели удаляются при закрытии документа. Это я понял. Если "повесить" регистрацию слушателя на получение фокуса поля с списком, тогда он может быть зарегистрирован много раз. Соответственно количество вызовов _change тоже будет большим.

global lBCl ' CreateUnoListener ("lBCfunc_", "com.sun.star.form.XChangeListener")
global lBC '.CurrentController.getControl

Sub addChangeListener 'обычная регистрация
'доступ к ЛистБокс
i=i+1
oD = ThisComponent
lB = oD.DrawPage.Forms.getByName("Форма").getByName("Список 1")
lBC = oD.CurrentController.getControl (lB)
'создать Слушатель
lBCl = CreateUnoListener ("lBCfunc_", "com.sun.star.form.XChangeListener")
lBC.addChangeListener  (lBCl)

'показать в переменной что есть регистрация
sNeedFieldName = "com.sun.star.text.FieldMaster.User.переменнаяСлушатель"
oFieldMasters = ThisComponent.getTextFieldMasters()
oNeedField = oFieldMasters.getByName(sNeedFieldName)
oNeedField.Content = oNeedField.Content + " + addChangeListener"
ThisComponent.getTextFields.refresh
End Sub

Sub lBCfunc_changed (event)

' присваиваем значение переменной
sNeedFieldName = "com.sun.star.text.FieldMaster.User.переменная"
oFieldMasters = ThisComponent.getTextFieldMasters()
oNeedField = oFieldMasters.getByName(sNeedFieldName)

oNeedField.Content=event.Source.getSelectedItem
oContent=oNeedField.Content
ThisComponent.getTextFields.refresh
MsgBox "lBCfunc_changed"

'oD = ThisComponent
'lB = ThisComponent.DrawPage.Forms.getByName("Форма").getByName("Список 1")
'lBC = oD.CurrentController.getControl (lB)
'lBCl = CreateUnoListener ("lBCfunc_", "com.sun.star.form.XChangeListener")

'1
'пусть переменные Слушателя будут глобально зарегистрированы и не будет объявлены в данной процедуре
'первоначально вызывается ошибка, переменные не объявлены (объектная переменная не установлена), возвращается к строке MsgBox "lBCfunc_changed"
'потом ошибка пропала
'removeListenerGlobal
'print "removeListenerGlobal from Sub lBCfunc_changed (event) with Global"

'2
'пусть переменные Слушателя НЕ будут глобально зарегистрированы
' удаление слушателя не происходит
' объект lBC доступен
'oD = ThisComponent
'lB = ThisComponent.DrawPage.Forms.getByName("Форма").getByName("Список 1")
'lBC = oD.CurrentController.getControl (lB)
'print lBC.getSelectedItem
'lBCl = CreateUnoListener ("lBCfunc_", "com.sun.star.form.XChangeListener")
'removeListenerGlobal
'print "removeListenerGlobal from Sub lBCfunc_changed (event) with New CreateUnoListener"

'3
' вроде бы слушатель удалился
'event.Source.removeChangeListener (lBCl)
'print "event.Source.removeChangeListener (lBCl) from Sub lBCfunc_changed (event)"

end Sub

Sub removeListenerGlobal () 'скобочки что-то решают?

'lBC global
'lBCl global

lBC.removeChangeListener (lBCl)
print "removeListenerGlobal"
i = i-1
end Sub


Sub removeListenerGlobal1 () ' тестируем удаление без глобальных переменных
'lBC не global
'lBCl не global
' регистрируем все заново
oD1 = ThisComponent
lB1 = oD1.DrawPage.Forms.getByName("Форма").getByName("Список 1") 'com.sun.star.form.OListBoxModel
lBC1 = oD1.CurrentController.getControl (lB1)
lBCl1 = CreateUnoListener ("lBCfunc_", "com.sun.star.form.XChangeListener")
lBC1.removeChangeListener (lBCl1)
print "removeListenerGlobal1"
end Sub




sokol92

После того, как вызван метод
lBC.addChangeListener  lBClпри возникновении соответствующих интерфейсу событий будет вызываться соответствующий макрос. Если Вы второй  раз добавите слушатель (тот же самый или другой) к тому же "вещателю" lBC, то вызов макроса (макросов) при возникновении событий будет производится дважды - о событии оповещается каждый зарегистрировавшийся слушатель.
Как правило, для удаления слушателя мы должны вызывать метод remove...Listener с теми же объектами, которые были указаны для add...Listener, вот почему мы используем для lBC и lBCl глобальные переменные.
Владимир.