Сигналы PyQt: сработает ли сигнал после отключения ()? - PullRequest
0 голосов
/ 22 мая 2018

Я имею дело с приложением, в котором запускается много сигналов, после чего следует повторное подключение.Я подробно объясню, как работает приложение, а также где начинается моя путаница.


1.Повторное подключение сигнала

В моем приложении я часто повторно подключаю сигналы.Для этого я буду использовать следующую статическую функцию, взятую из ответа @ekhumoro (и немного измененного) из этого поста: PyQt Widget connect () и disconnect ()

def reconnect(signal, newhandler):
    while True:
        try:
            signal.disconnect()
        except TypeError:
            break
    if newhandler is not None:
        signal.connect(newhandler)


2.Приложение

Представьте себе функцию emitterFunc(self), проходящую по списку объектов.После каждой итерации функция подключает mySignal к объекту, запускает сигнал и затем снова отключает mySignal в начале следующего шага итерации.Сработавший сигнал также несет некоторую полезную нагрузку, например, объект Foo().


enter image description here

РЕДАКТИРОВАТЬ:

  • Показанный выше дизайн значительно упрощен .В окончательном варианте излучатель сигнала и приемный слот могут работать в разных потоках.

  • По причинам, которые могут увести нас слишком далеко, я не могу просто соединить все объекты одновременно,подайте сигнал и, наконец, отключите их все.Я должен последовательно просмотреть их, выполняя процедуру connect-emit-disconnect.

  • Опять же, по причинам, которые могут привести нас слишком далеко, я не могу просто вызвать эти слоты напрямую.


3.Ментальный образ механизма «Сигнальный слот»

Со временем я создал мысленный образ того, как работает механизм «Сигнальный слот».Я представляю себе Signal-Slot engine , который поглощает все запущенные сигналы и помещает их в очередь.Каждый сигнал ждет своей очереди.Когда время готово, двигатель передает данный сигнал соответствующему обработчику.Чтобы сделать это правильно, в двигателе есть некоторая «бухгалтерская» работа, чтобы каждый сигнал попал в правый слот.

enter image description here


4.Поведение механизма Signal-Slot

Представьте, что мы на шаге n th .Мы подключаем self.mySignal к object_n .Затем мы запускаем сигнал с его полезной нагрузкой.Почти сразу после этого мы разрываем соединение и устанавливаем новое соединение с object_n + 1 .В тот момент, когда мы разрываем связь, сработавший сигнал, вероятно, еще не сделал свою работу.Я могу представить три возможных варианта работы механизма Signal-Slot:

  • [ВАРИАНТ 1] Механизм замечает, что соединение разорвано, и отбрасывает sig_n из своей очереди.

  • [ВАРИАНТ 2] Двигатель замечает, что соединение установлено с другим обработчиком, и отправляет sig_n обработчику object_n + 1 (как только онпопадает в начало очереди).

  • [ВАРИАНТ 3] Двигатель ничего не меняет для sig_n.При запуске он был предназначен для обработчика object_n , и на этом все закончится.


5.Мои вопросы

Мой первый вопрос довольно очевиден.Каково правильное поведение двигателя Signal-Slot?Я надеюсь, что это третий вариант.

В качестве второго вопроса я хотел бы знать, в какой степени данный мысленный образ является правильным.Например, могу ли я рассчитывать на сигналы, выходящие из очереди по порядку?Этот вопрос менее важен - он определенно не важен для моего заявления.

Третий вопрос 1113 * связан с эффективностью времени.Повторное подключение к другому обработчику занимает много времени?Узнав ответ на первый вопрос, я приступлю к созданию приложения и смогу измерить время переподключения самостоятельно.Так что этот вопрос не так актуален.Но если вы все равно знаете ответ, пожалуйста, поделитесь: -)

1 Ответ

0 голосов
/ 22 мая 2018

Я бы начал с вашего второго вопроса , чтобы сказать, что ваш мысленный образ частично верен, потому что очередь включена, но не всегда.Когда излучается сигнал, существует три возможных способа вызова подключенного слота (-ов), и два из них используют очередь событий (QMetaCallEvent создается на лету и отправляется с помощью метода QCoreApplication postEvent,где целью события является держатель слота или приемник сигнала, если вы предпочитаете).Третий случай - это прямой вызов, поэтому излучение сигнала похоже на вызов слота, и ничего не ставится в очередь.

Теперь к первому вопросу : в любом случае, когда излучается сигнал, просматривается список соединений (принадлежащих источнику сигнала), и слоты вызываются одно за другим, используяодин из трех методов, указанных выше.Всякий раз, когда соединение установлено или разорвано, список будет обновляться, но это обязательно произойдет до или после передачи сигнала.Короче говоря: очень мало шансов преуспеть в блокировании вызова в подключенный слот после того, как сигнал был испущен, по крайней мере, не разрывая соединение с disconnect().Поэтому я бы пометил [OPTION 3] как правильный.

Если вы хотите копать дальше, начните с документации перечисления ConnectionType , где три основных типа соединения (прямое, поставленное в очередь и блокирующее -в очереди) хорошо объяснили. тип соединения может быть указан в качестве пятого аргумента для метода QObject connect, но, как вы узнаете из вышеупомянутых связанных документов, очень часто Qt сам выбирает тип соединенияэто лучше всего соответствует ситуации.Спойлер: темы участвуют:)

О третьем вопросе : У меня нет под рукой тестов, поэтому я дам так называемое в основном основанное на мнении ответ, вид ответа, который начинается с ИМХО.Я думаю, что сфера сигнал / слот является одной из тех, в которых правила keep-it-simple действительно действуют, и ваш шаблон reconnect , кажется, делает многоесложнее, чем они должны быть.Как я уже упоминал выше, когда соединение установлено, объект соединения добавляется в список.Когда сигнал испускается, все подключенные слоты будут вызываться так или иначе, один за другим.Итак, вместо отключения / повторного подключения / генерации на каждом цикле в вашем цикле, почему бы просто не сначала подключить все элементы, а затем подать сигнал, а затем отключить их все?

Надеюсь, мой (длинный и, может быть, tldr) ответ помог.Приятного чтения.

...