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

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

4 Июль 2022, 03:38 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости: Доступно и просто о работе в офисных пакетах
 
   Начало   Помощь Поиск Войти Регистрация    задать вопрос  
Страниц: 1 2 3 4 »   Вниз
  Печать  
Автор Тема: Как работает ChartDataChangeEventListener?  (Прочитано 3859 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Kadet
Форумчанин
***
Offline Offline

Сообщений: 698


« Стартовое сообщение: 14 Январь 2022, 21:07 »

Добрый день!
Помогите разобраться с тем, как работает Listener - com.sun.star.chart.XChartDataChangeEventListener

В описаниях написано, что он отслеживает изменение данных или состояния ячеек Calc, диаграмм и т.п.

Макросом заношу данные в ячейки документа Calc и вешаю на эти ячейки этот слушатель.
Потом, макросом же, создаю в этом документе новый лист, не касаясь заполненных ячеек, но при этом почему-то начинают срабатывать листенеры, которые висят на предыдущем листе.

Почему же так происходит? На что они реагируют?

К тому же, никак не удаётся удалять этих слушателей, допустим если очистить лист и заполнить его новыми данными, то старые листенеры продолжают существовать. По-моему не помогает даже удаление листа, к которому они якобы привязаны.
А не удаётся их удалять потому что их много и все они созданы одним макросом и повешены на одну переменную. Так LO позволяет сделать, и все они работают, но для удаления каждого нужно чётко дать объект удаления, а при одинаковых названиях - даёт ошибку.

В общем, собрал маленькую простую демку.
Она заполняет 10 ячеек и на каждую вешает слушателя. Потом создаёт новый лист, но при его создании почему-то начинают срабатывать ранее установленные листенеры, привязанные к предыдущему листу, который никто не трогает. О чём сообщают сообщалки.

* tttt.ods (11.09 Кб - загружено 9 раз.)
« Последнее редактирование: 14 Январь 2022, 21:11 от Kadet » Записан
eeigor
Опытный пользователь
***
Offline Offline

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


« Ответ #1: 14 Январь 2022, 23:38 »

Глянул навскидку без запуска. Почему переменные объявлены как Public? Global.
Public Global ANCell
Public Global ANListener

Вы подключаете слушатель к каждой ячейке в цикле через вызов ANListenerSUB и перезаписываете переменную ANCell:
    ANCell = oSheet.getCellByPosition(oColumn,oRow)
Но, извините, ANCell - это не массив переменных для каждой ячейки, к которой подключается независимый слушатель.
Т.о., процедурой UnregisterANlistener Вы останавливаете последний запущенный слушатель.
Я не знаю по какой причине Вы не хотите подключить один слушатель ко всему диапазону ячеек...

com.sun.star.chart.XChartDataChangeEventListener
Метод disposing надо добавить тоже.


* Снимок экрана от 2022-01-14 23-43-40.png (22.22 Кб, 428x199 - просмотрено 9 раз.)
« Последнее редактирование: 15 Январь 2022, 00:00 от eeigor » Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
Kadet
Форумчанин
***
Offline Offline

Сообщений: 698


« Ответ #2: 15 Январь 2022, 00:09 »

Паблик только в демке. В оригинале глобал.

Года два назад уже крутил тему с листенерами. В том числе экспериментировал с массивами переменных. Только что-то пошло не так, а что конкретно уж не упомню. Эта проблема с выключением листенеров у меня крутится уже давно, но пока ещё не нашёл нормальный способ их отключения.
И понятно, что в переменной остаётся последний слушатель, но дело в том, что все они всё равно работают... в других версиях, где не нужно создавать дополнительные листы.

Диспозинг действительно нужно вставить. Всё размышлял нужен ли он или нет. Но... думаю не помешает.

Однако, вопрос всё таки в другом.
« Последнее редактирование: 15 Январь 2022, 00:14 от Kadet » Записан
Kadet
Форумчанин
***
Offline Offline

Сообщений: 698


« Ответ #3: 15 Январь 2022, 00:12 »

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

Но, всё таки хотелось бы разобраться почему такое нечто случается. Хотя бы, чтобы не попадать в подобные ситуации в аналогичных случаях.
Записан
eeigor
Опытный пользователь
***
Offline Offline

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


« Ответ #4: 15 Январь 2022, 00:31 »

Я понял проблему.
Упростил ваш пример (прилагаю), оставив одну ячейку. Но при добавлении/удалении другого листа или перемещении любого листа возникает события слушателя изначально первого листа.
Работает с графиком (диаграммой) только или же с ячейками в том числе?
XChartDataChangeEventListenermakes makes it possible to receive events when chart data changes.
chartDataChanged is called whenever chart data changes in value or structure.

С другой стороны, chart data - это и есть диапазон ячеек.

* tttt.ods (10.77 Кб - загружено 5 раз.)
« Последнее редактирование: 15 Январь 2022, 00:34 от eeigor » Записан

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

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


« Ответ #5: 15 Январь 2022, 01:13 »

chartDataChanged is called whenever chart data changes in value or structure.
Я подготовил новый, облегченный пример. Ваш пример не годится для исследования.
Вероятно, что вставка/удаление или перемещение листа есть изменение структуры. Не знаю.
Однако Вы можете аккуратно отключить слушатель перед этими операциями и потом заново включить. Это если делать кнопкой (макросом). А если через интерфейс мышкой или в меню, то потребуется подключить XUndoManagerListener. Слишком сложно. Проще никак?

Во всяком случае подождем ответов других участников.

В прилагаемом примере обращение к листу осуществляется по имени листа.

Updated:
К примеру, при перемещении листа (любого, даже без изменения позиции листа с запущенным слушателем) запущенный слушатель теряется (но объектная переменная не пуста). Остановите (переменная будет сброшена) и заново запустите слушатель. Опять работает...
Теряется, как сказал, но опять таки не всегда. Вставил новый лист после второго (слушатель на первом) - и слушатель работает.

Я использую событие листа "Content changed", и мне хватает... Смотрите в сторону упрощения решения. Я предпочитаю принцип проектирования KISS (акроним для «Keep it simple, stupid»).

* XChartDataChangeEventListener.ods (11.16 Кб - загружено 6 раз.)
« Последнее редактирование: 15 Январь 2022, 01:39 от eeigor » Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
Kadet
Форумчанин
***
Offline Offline

Сообщений: 698


« Ответ #6: 15 Январь 2022, 07:43 »

Проще никак?
Можно. Как описывал ранее, формировать структуру документа перед тем как развешивать слушателей. Тогда и Вкл/Выкл не потребуется. В итоге так и сделаю. По крайней мере это надёжней.
Но, проблема всё таки остаётся не разгаданной.
Видимо таки ChartDataChangeEventListener реагирует не только на изменения диапазонов, к которым привязан, но и на изменение структуры самого документа.
изначально первого листа.
Не факт. В оригинале слушателей вешаю начиная с третьего листа документа и при создании нового листа они реагируют. Далее не исследовал какие реагируют при создании следующих листов.

Однако, спасибо! Подали парочку идей.
Во-первых, да... всё таки диапазоны, а не отдельные ячейки. Попробую постестить этот вариант. Повесить на диапазон -два столбца в десяток строк. Что получится. Один слушатель ведь лучше чем двадцать.
Ну и, снова повручу с массивами переменных, в которые буду загонять переменные листенеров. Может таки получится.
« Последнее редактирование: 15 Январь 2022, 07:46 от Kadet » Записан
mikekaganski
Гуру
*******
Offline Offline

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


« Ответ #7: 15 Январь 2022, 09:28 »

При добавлении листа генерируется событие "все формулы нужно пересчитать" (ScDocument::SetAllFormulasDirty), которое в т.ч. явно вызывает ScChartListenerCollection::SetDirty - все слушатели изменений диаграмм помечаются для оповещения, что и происходит по таймеру (то есть сразу после добавления).
« Последнее редактирование: 15 Январь 2022, 09:47 от mikekaganski » Записан

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

Сообщений: 698


« Ответ #8: 15 Январь 2022, 09:44 »

Каждая ячейка - это ещё и диапазон, состоящий из одной ячейки.
Это понятно.
При добавлении листа генерируется событие ...
Т.е. от срабатывания слушателей при создании новых листов не уйти.
Ясно. Спасибо за пояснения!

Значит остаётся один путь - "нормальные герои всегда идут в обход".
Записан
mikekaganski
Гуру
*******
Offline Offline

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


« Ответ #9: 15 Январь 2022, 09:50 »

Надо просто понимать, что любой слушатель может срабатывать при многих разных условиях, не только при реальном изменении данных в его диапазоне. То есть сработка слушателя - это не событие "мои данные изменились", а событие "требуется обновление".
Записан

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

Сообщений: 698


« Ответ #10: 15 Январь 2022, 10:10 »

Однако, с привязыванием листенеров к диапазонам снова засада, как и предполагалось. В итоге листенеры нужны не только для отслеживания самого факта изменений, но, и это главное, получение данных что изменилось и где. А при диапазонах сообщается лишь, что где-то внутри произошли некие изменения. А где и что изменилось - не сообщается. Или я плохо искал.

С занесением листенеров как переменных в массив тоже не всё так просто. Массив-то оно формирует, но при остановке помимо самой переменной листенера ещё требуется правильный диапазон, к которому он привязан. Т.е. массив должен быть как минимум двух-трёх мерный, где помимо самой переменной объекта листенера ещё должны храниться и адрес диапозона. А в идеале лучше сделать вообще отдельный тип, где первая подпеременая буд хранить RangeAdress, а вторая сам объект листенера.
« Последнее редактирование: 15 Январь 2022, 10:15 от Kadet » Записан
Kadet
Форумчанин
***
Offline Offline

Сообщений: 698


« Ответ #11: 15 Январь 2022, 10:11 »

То есть сработка слушателя - это не событие "мои данные изменились", а событие "требуется обновление".
Непонимающий
Записан
mikekaganski
Гуру
*******
Offline Offline

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


« Ответ #12: 15 Январь 2022, 10:14 »

Вы не описали, зачем Вам вообще слушатели. Для чего знать, какая именно ячейка изменилась. В принципе идея этого слушателя в том, чтобы получать данные о необходимости обновления для всего диапазона. Если для каждого диапазона объекты обновления разные, то нужны разные слушатели. Если обновляемый объект один - то и нет нужды знать, что именно изменилось внутри диапазона.
Записан

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

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


« Ответ #13: 15 Январь 2022, 10:15 »

Непонимающий

И как отвечать на такое содержательное сообщение?
Записан

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

Сообщений: 698


« Ответ #14: 15 Январь 2022, 10:30 »

Непонимающий

И как отвечать на такое содержательное сообщение?
Это риторическое сообщение, ответа не требует. Означает - "озадачен".

Эти листенеры в моей программе нужны для следующего.
В некоей ячейке происходят некие изменения. Чаще всего я вешаю такие листенеры на ячейки со списками выбора. Допустим - "номенклатура материалов". По изменению данных в этой ячейке должен запуститься макрос, который получает изменённые данные, так же получает ГДЕ конкретно изменились эти данные. Затем эти новые данные как фильтр идут в SQL-запрос  БД, и оттуда получаются новые отфильтрованные данные. На выходе я получаю: список данных, из которых допустим нужно сформировать/переформировать список выбора в зависимой от изменённой ячейки ячейке... Либо получаю ID/коэф. или ещё т.п. из таблицы БД той позиции, которая появилась в измененной ячейке... Либо запускается макрос на пересчёт и вычисление значений для других ячейках, связанных с изменённой ячейкой....
В общем - случаев использования этого слушателя у меня масса.
(запутал, сам с трудом понимаю что написал)

Но, в общем и целом мне нужно:
- отловить момент произошедших в некоей ячейке изменений;
- получить новые данные из этой ячейки;
- получить адрес где конкретно произошли изменения.

Возможно я использую не тот листенер, но... другого способа не придумал.
« Последнее редактирование: 15 Январь 2022, 10:37 от Kadet » Записан
Страниц: 1 2 3 4 »   Вверх
  Печать  
 
Перейти в:  

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