Russian Qt Forum
Ноябрь 24, 2024, 16:53 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QAction добавить сигналы ДО triggeted  (Прочитано 5118 раз)
Nimbus
Гость
« : Октябрь 08, 2014, 13:15 »

Доброго времени суток.

В приложении на С++ где-то внутри сохранён указатель на экземпляр QAction и добавлен на какие-то меню/тулбары. На сигнал triggered() этого экземпляра законнекчено неизвестное количество каких-то QObject-ов (пусть набор этих соединений со слотами будет называться "хэндлером по-умолчанию").

Теперь, получив извне доступ к этому экземпляру QAction (в данном случае запускается питоновый интерпретатор, в котором запускается какой-то кастомный питоновый код, в контексте этого самого процесса с QAction'ом, имеющий у себя в арсенале биндинги PySide, но это сейчас не важно), очень нужно обернуть хэндлер по-умолчанию своим кодом. То есть, чтобы сигнал triggered() вызвал сначала какой-то наш кастомный слот ДО вызова хэндлера по-умолчанию, затем сам хэндлер по-умолчанию, и затем ещё какой-то наш кастомный слот.

Типичный сценарий такой -- имеется QMenu в С++ приложении. Добавить вызов какого-то кода ДО клика на определённом пункте меню и ПОСЛЕ.
 
С вызовом слота после проблем нет -- добавить новый коннект. А вот ДО...
Можно попытаться добавить Proxy-объект, хранящий оригинальный QAction, который заменял бы его когда нужно на свой кастомный QAction, в слоте на on_triggered вызывался бы код ДО, затем оригинальный QAction.trigger() и код ПОСЛЕ. Однако, такой механизм имеет ряд недостатков, один из которых -- приложение по прежнему оперирует оригинальным экземпляром QAction'а и не знает ничего, что его подменили в меню, соответственно попытки сделать недоступным для клика (или изменить shortcut) приведут лишь к изменению оригинального, а proxy-объект не узнает об этом.

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

Другой вариант -- изменить само С++ приложение, чтобы  QAction имел в своём составе Proxy-объект, к которому он бы коннектился и к которому уже коннектился бы хэндлер-по умолчанию и имелась бы возможность получить этот объект извне, например через вызов QMetaObject::invokeMethod. К сожалению это серьёзное архитектурное изменение, требующее значительных затрат и изменений кода и тестов.

Хорошо бы иметь какую-то очередь коннектов, в которую уже можно будет вставлять элементы с начала или конца. Но это лишь пожелание.
И да, я лишь описал единичный случай. Хотелось бы такое проделывать для любых QAction'ов, которые мы возьмём из приложения.

Кто-нибудь знает другие способы?
« Последнее редактирование: Октябрь 08, 2014, 13:20 от JC » Записан
Bepec
Гость
« Ответ #1 : Октябрь 08, 2014, 13:25 »

На мой взгляд очень ненужная и опасная штука у вас выходит. А если там цикл бесконечный или ошибка?

К тому же не видно смысла. Зачем вам это?

Вкратце - вам нужно чтобы вызывался слот triggered после обработки питоновского скрипта.
Как делать - создать своего потомка от QAction в котором перед посылкой сигнала вызывать питоновский скрипт.
Записан
Nimbus
Гость
« Ответ #2 : Октябрь 08, 2014, 13:32 »

На мой взгляд очень ненужная и опасная штука у вас выходит. А если там цикл бесконечный или ошибка?

К тому же не видно смысла. Зачем вам это?

Вкратце - вам нужно чтобы вызывался слот triggered после обработки питоновского скрипта.
Как делать - создать своего потомка от QAction в котором перед посылкой сигнала вызывать питоновский скрипт.

Это уже пользователям решать, они будут писать скрипт.
К тому же, С++ приложение НЕ знает ничего что внутри питонового скрипта.
Оно просто поднимает интерпретатор и запускает скрипт.
Скрипт вызывает единожды, а уже в нём навешиваются какие-то хэндлеры и кастомизируется приложение.
Записан
Nimbus
Гость
« Ответ #3 : Октябрь 08, 2014, 13:40 »

Я имею в виду, что у пользователей ДОЛЖНА быть возможно завернуть обработку сигнала triggered в свой код, имея в контексте возможность вызвать хэндлер по-умолчанию.
Записан
Bepec
Гость
« Ответ #4 : Октябрь 08, 2014, 17:49 »

Ну блин поставьте там запуск файла myscript.py.
Если файла нет, то стандартный вызов сигнала.

Вот и вся логика.
Записан
Nimbus
Гость
« Ответ #5 : Октябрь 08, 2014, 18:08 »

Ну блин поставьте там запуск файла myscript.py.
Если файла нет, то стандартный вызов сигнала.

Вот и вся логика.

Видимо я неясно выразился. Это было бы нарушением абстракции. У нас нет цели сделать запуск скрипта по какому-то событию. У нас есть цель обеспечить возможность пользователям-программистам вклинить(/заменить наши на) свои хэндлеры на наши QAction'ы.
Записан
Bepec
Гость
« Ответ #6 : Октябрь 08, 2014, 23:13 »

Так и не понял вашей логики. Можете привести цепочку вызовов без словесной шелухи?

Нажатие экшена - вызов *** - вызов Qt слотов?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Октябрь 09, 2014, 07:42 »

А не дописать ли нужный код в moc файл? (ну конечно запретив его пере-генерацию)
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #8 : Октябрь 09, 2014, 08:37 »

2JC Если есть возможность заменить в c++ программе все QAction на, какие нибудь, MyAction, то я придумал неплохое решение.
Да, MyAction это прямой наследник QAction, т.е. в программе ничего кроме названия класса переделывать не придётся.

P.S. Пишу с телефона, поэтому сразу решение расписывать лениво. Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Октябрь 09, 2014, 08:51 »

Есть такой ходик (qt_signal_spy_callback_set)

Код
C++ (Qt)
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
{
   int signal_index = signalOffset + local_signal_index;
 
   if (!sender->d_func()->isSignalConnected(signal_index)
       && !qt_signal_spy_callback_set.signal_begin_callback
       && !qt_signal_spy_callback_set.signal_end_callback) {
       return; // nothing connected to these signals, and no spy
   }
 
   if (sender->d_func()->blockSig)
       return;
 
   if (sender->d_func()->declarativeData && QAbstractDeclarativeData::signalEmitted)
       QAbstractDeclarativeData::signalEmitted(sender->d_func()->declarativeData, sender,
                                               signal_index, argv);
 
   void *empty_argv[] = { 0 };
   if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
       qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index,
                                                        argv ? argv : empty_argv);
 
Блокировать не видно как, но "до" и "после" есть
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.267 секунд. Запросов: 23.