Как работает ChartDataChangeEventListener?

Автор Kadet, 14 января 2022, 21:07

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

eeigor

#30
@Kadet, в ответе #15 в коде есть небольшая неточность:
ячейка не имеет метода queryIntersection, поэтому надо использовать диапазон из одной ячейки (в прилагаемом примере это учтено).

Цитата: Kadet от 15 января 2022, 11:13Цитата: eeigor от Сегодня в 10:41
Макрос Sheet_OnChange подключается вручную щелчком ПКМ по ярлычку листа >> Sheet Events...
Вот этот момент совсем не годится.
Прилагаю пример с программным подключением события листа, как Вы просили.
Однако как всё просто!  :)
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

Kadet

Цитата: eeigor от 15 января 2022, 12:54Прилагаю пример с программным подключением события листа, как Вы просили.
Однако как всё просто!  Улыбка
Хорошо. Я посмотрю. Спасибо!


Kadet

Цитата: mikekaganski от 15 января 2022, 12:40Вы проверяли, помогает ли addActionLock/removeActionLock вокруг кода, меняющего большие массивы данных?
Да. Заморозку использую.

Kadet

#33
Цитата: eeigor от 15 января 2022, 12:54Однако как всё просто!
Посмотрел. Подвязку событий макросом делать умею. Это мы уже проходили и rimi помог с этим.
Вопрос стоит ли это делать. (см. выше).

eeigor

А вот Вы и попробуйте на реальных данных, а нам потом расскажете
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

Kadet

Однако, если вернуться к нашим "баранам".

Сделал обработку листенеров с помощью сложного массива рукописного типа. Вроде бы при remove ошибок не выдаёт. Но, сдаётся, мне, что эти листенеры так и не отключаются.

Type TListener
ra As New com.sun.star.table.CellRangeAddress 'RangeAdress
ltr As New com.sun.star.chart.XChartDataChangeEventListener 'объект Listener
End Type

'*****************************************************
Global ANListener(0) As New TListener
'******************************************************
Sub ANListenerSUB(oRange)
Dim n%
n =UBound(ANListener)
If NOT IsNull(ANListener(n).ra) Then
n = n+1
ReDim preserve ANListener(n) As New TListener
End If

ANListener(n).ra = oRange.RangeAddress
ANListener(n).ltr = CreateUnoListener( "AN_", "com.sun.star.chart.XChartDataChangeEventListener" )
oRange.addChartDataChangeEventListener(ANListener(n).ltr)
End Sub

'******************************************************
Sub AN_disposing(oEvent)
End Sub

'******************************************************
Sub AN_chartDataChanged(oEvent)
ANSet(oEvent)
End Sub

'******************************************************
Sub UnregisterANlistener(n%)
Dim oDoc, oSheet, oRange, iSh%, iStCl%, iStRw%, iEnCl%, iEnRw%
' ON LOCAL ERROR resume next
oDoc = ThisComponent

iSh = ANListener(n).ra.Sheet
iStCl = ANListener(n).ra.StartColumn
iStRw = ANListener(n).ra.StartRow
iEnCl = ANListener(n).ra.EndColumn
iEnRw = ANListener(n).ra.EndRow

oSheet = oDoc.Sheets(iSh)

oRange = oSheet.getCellRangeByPosition(iSh, iStCl, iStRw, iEnCl, iEnRw)
oRange.removeChartDataChangeEventListener(ANListener(n).ltr)
' ON LOCAL ERROR GOTO 0
End Sub


Делаю тип TListener. В ra записываю RangeAddress, а в ltr объект листенера.
При отключении достаю всё это и получаю диапозон, к которому привязываю листенер и пытаюсь отключить листенер, привязанный к нему.
Проходит гладко.
Но когда после отключения всех листенеров снова пытаюсь создать или удалить лист - все листенеры срабатывают.
Получается, что, несмотря на то, что команда removeChartDataChangeEventListener прошла гладко, листенеры всё одно продолжают работать.

Kadet

Цитата: eeigor от 15 января 2022, 14:58А вот Вы и попробуйте на реальных данных, а нам потом расскажете
Хорошо. Попробую.

eeigor

Ну, про слушатели Вам пояснил Михаил. Потому и срабатывают. И на моем облегчённом примере в ответе #5 это лучше демонстрировать.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

Kadet

Ну, прежде всего я допустил ошибку в строчке:
oRange = oSheet.getCellRangeByPosition(iSh, iStCl, iStRw, iEnCl, iEnRw)

Нужно так:
oRange = oSheet.getCellRangeByPosition(iStCl, iStRw, iEnCl, iEnRw)

Но, и это видимо не помогает. Срабатывают.

mikekaganski

Цитата: Kadet от 15 января 2022, 15:00
Вроде бы при remove ошибок не выдаёт. Но, сдаётся, мне, что эти листенеры так и не отключаются.
...
При отключении достаю всё это и получаю диапозон, к которому привязываю листенер и пытаюсь отключить листенер, привязанный к нему.
Проходит гладко.

Вы создаёте новый объект. Не тот же объект, который использовали при регистрации слушателя, а такой же, для того же диапазона, но не тот же самый. Это и есть проблема.
С уважением,
Михаил Каганский

sokol92

#40
Раньше не смотрел  XChartDataChangeEventListener. Для "обычных" диапазонов ячеек он при изменении любой ячейки диапазона порождает событие, в котором источником (Source) является диапазон, а в структуре ChartDataChangeEvent возвращается адрес диапазона (а не измененной ячейки).
На мой взгляд, проще использовать старый испытанный XModifyListener.

Событие листа "OnChange" отлавливает не все изменения ячеек листа (например, если ячейки меняются в результате пересчета формул). В Excel ситуация не лучше.

Что касается остановки слушателя, то замечание Михаила носит универсальный характер: лучше в глобальных переменных сохранять как сам слушатель, так и "вещатель" - объект, к которому слушатель добавляется.

Насколько я понимаю, методы removeXXXXListener нормально завершаются при попытке удалить слушатель, который ранее к вещателю не подключался.
Владимир.

Kadet

Цитата: mikekaganski от 15 января 2022, 16:35Вы создаёте новый объект. Не тот же объект, который использовали при регистрации слушателя, а такой же, для того же диапазона, но не тот же самый. Это и есть проблема.
"Интересное кино"?! А как же тогда получить "тот же самый"?
Вроде бы логически должно быть всё верно. Я сохраняю создаваемый листенер в массиве и сохраняю адрес диапазона, к которому его привязываю.

А как же тогда достать "тот самый"? Чего-то я окончательно запутался. По вашему получается - "те самые" листенеры просто недосягаемы.

mikekaganski

Цитата: Kadet от 15 января 2022, 22:06А как же тогда получить "тот же самый"?

Сохранять в ANListener(n) не oRange.RangeAddress, а oRange.
С уважением,
Михаил Каганский

Kadet

Цитата: sokol92 от 15 января 2022, 18:17Что касается остановки слушателя, то замечание Михаила носит универсальный характер: лучше в глобальных переменных сохранять как сам слушатель, так и "вещатель" - объект, к которому слушатель добавляется.
Ага. Кажется начинаю догонять. Вы предлагаете в массиве сохранять не адрес диапазона, а сам диапазон как объект.
Интересная идея. Попробую.

Кстати, "обходной манёвр" реализовал. Вроде бы стало работать правильно.

Kadet

Цитата: mikekaganski от 15 января 2022, 22:10Сохранять в ANListener(n) не oRange.RangeAddress, а oRange.
Да, да. Я уже понял предыдущие объяснения. Спасибо!