В мире Qt в чем разница событий и сигналов / слотов?
Одно заменяет другое? События - это абстракция сигналов / слотов?
Документация Qt, вероятно, лучше всего объясняет это:
В Qt события - это объекты, производные от абстрактного
QEvent
класса, которые представляют вещи, которые произошли либо внутри приложения, либо в результате внешней активности, о которой приложению необходимо знать. События могут быть получены и обработаны любым экземпляромQObject
подкласса, но они особенно актуальны для виджетов. Этот документ описывает, как события доставляются и обрабатываются в типичном приложении.
Таким образом, события и сигналы / слоты - это два параллельных механизма, выполняющих одно и то же. Как правило, событие создается внешней сущностью (например, клавиатурой или колесом мыши) и доставляется через цикл событий в QApplication
. В общем, если вы не настроите код, вы не будете генерировать события. Вы можете фильтровать их QObject::installEventFilter()
или обрабатывать события в подклассе объекта, переопределив соответствующие функции.
Сигналы и слоты намного проще генерировать и получать, и вы можете соединить любые два QObject
подкласса. Они обрабатываются с помощью Metaclass (подробнее см. В файле moc_classname.cpp), но большая часть межклассового взаимодействия, которое вы будете производить, вероятно, будет использовать сигналы и слоты. Сигналы могут быть доставлены немедленно или отложены через очередь (если вы используете потоки).
Сигнал может быть сгенерирован.
В Qt сигналы и события являются реализациями паттерна Observer . Их используют в разных ситуациях, потому что у них разные сильные и слабые стороны.
Прежде всего, давайте определим, что мы подразумеваем под «событием Qt»: виртуальная функция в классе Qt, которую вы ожидаете переопределить в своем базовом классе, если вы хотите обработать событие. Это связано с шаблоном шаблонного метода .
Обратите внимание, как я использовал слово « ручка ». В самом деле, вот основная разница между назначением сигналов и событий:
Разница в том, что когда вы «обрабатываете» событие, вы берете на себя ответственность «ответить» поведением, которое полезно за пределами класса. Например, рассмотрим приложение, на котором есть кнопка с номером. Приложение должно позволить пользователю сфокусировать кнопку и изменить номер, нажимая клавиши «вверх» и «вниз». В противном случае кнопка должна работать как обычно
QPushButton
(ее можно нажимать и т. Д.). В Qt это делается путем создания вашего собственного маленького многоразового «компонента» (подклассаQPushButton
), который реализует зановоQWidget::keyPressEvent
. Псевдокод:Видеть? Этот код представляет новую абстракцию: виджет, который действует как кнопка, но с некоторыми дополнительными функциями. Мы очень удобно добавили этот функционал:
keyPressEvent
сигнал, нам нужно было бы решить, наследовать лиQPushButton
сигнал или просто подключаться к нему извне. Но это было бы глупо, поскольку в Qt от вас всегда ожидается наследование при написании виджета с настраиваемым поведением (не зря - возможность повторного использования / модульность). Таким образом, создаваяkeyPressEvent
событие, они передают свое намерение, котороеkeyPressEvent
является всего лишь базовым строительным блоком функциональности. Если бы это был сигнал, это выглядело бы как вещь, обращенная к пользователю, хотя этого не должно было быть.keyPressEvent
это сигнал.Дизайн Qt хорошо продуман - они заставили нас упасть в яму успеха , позволив легко делать правильные вещи и трудно делать неправильные (сделав keyPressEvent событием).
С другой стороны, рассмотрите простейшее использование
QPushButton
- просто создание его экземпляра и получение уведомлений при нажатии :Это явно должно быть сделано пользователем класса:
QPushButton
каждый раз, когда мы хотим, чтобы какая-то кнопка уведомляла нас о щелчке, для этого потребовалось бы много подклассов без уважительной причины! Виджет, который всегда показывает «Hello world»messagebox
при нажатии, полезен только в одном случае, поэтому его нельзя использовать повторно. Опять же, у нас нет выбора, кроме как поступать правильно - подключаться к нему извне.clicked()
- или подключить несколько сигналов кsayHello()
. С сигналами суеты нет. При создании подклассов вам придется сесть и поразмышлять над некоторыми диаграммами классов, пока вы не выберете подходящий дизайн.Обратите внимание, что одно из мест
QPushButton
испусканияclicked()
находится в егоmousePressEvent()
реализации. Это не значитclicked()
, что иmousePressEvent()
являются взаимозаменяемыми - только что они связаны между собой .Итак, сигналы и события имеют разные цели (но связаны между собой тем, что оба позволяют «подписаться» на уведомление о том, что что-то происходит).
источник
Мне пока не нравятся ответы. - Позвольте мне сосредоточиться на этой части вопроса:
События - это абстракция сигналов / слотов?
Короткий ответ: нет. Длинный ответ поднимает вопрос «лучше»: как связаны сигналы и события?
Простой основной цикл (например, Qt) обычно «застревает» в вызове select () операционной системы. Этот вызов переводит приложение в «спящий» режим, в то время как оно передает кучу сокетов, файлов или чего-либо еще ядру, запрашивая: если что-то в них изменится, позвольте вызову select () вернуться. - И ядро, как хозяин мира, знает, когда это произойдет.
Результатом этого вызова select () может быть: новые данные в сокете, подключенном к X11, пакет на порт UDP, который мы слушаем, и т. Д. - Этот материал не является ни сигналом Qt, ни событием Qt, а Основной цикл Qt сам решает, превращает ли он свежие данные в одни, в другие или игнорирует их.
Qt может вызывать метод (или несколько), например keyPressEvent (), эффективно превращая его в событие Qt. Или Qt испускает сигнал, который фактически ищет все функции, зарегистрированные для этого сигнала, и вызывает их одну за другой.
Здесь видно одно различие этих двух концепций: слот не имеет права голоса по поводу того, будут ли вызваны другие слоты, зарегистрированные для этого сигнала. - События больше похожи на цепочку, и обработчик событий решает, прерывает он эту цепочку или нет. В этом отношении сигналы похожи на звезду или дерево.
Событие может запускаться или полностью превращаться в сигнал (просто испустить один, а не вызывать «super ()»). Сигнал можно превратить в событие (вызвать обработчик события).
Что абстрагирует то, что зависит от случая: сигнал clicked () абстрагирует события мыши (кнопка опускается и поднимается снова без особого перемещения). События клавиатуры - это абстракции от более низких уровней (такие вещи, как 果 или é - это несколько нажатий клавиш в моей системе).
Возможно, focusInEvent () является примером противоположного: он может использовать (и, таким образом, абстрагировать) сигнал clicked (), но я не знаю, действительно ли это так.
источник
События отправляются циклом событий. Каждой программе с графическим интерфейсом требуется цикл событий, независимо от того, что вы пишете для Windows или Linux, используя Qt, Win32 или любую другую библиотеку графического интерфейса. Также каждый поток имеет свой собственный цикл событий. В Qt «GUI Event Loop» (который является основным циклом всех приложений Qt) скрыт, но вы запускаете его вызовом:
Сообщения, которые ОС и другие приложения отправляют вашей программе, отправляются как события.
Сигналы и слоты - это механизмы Qt. В процессе компиляции с использованием moc (компилятора метаобъектов) они меняются на функции обратного вызова.
У события должен быть один получатель, который должен его отправить. Никто другой не должен получить это событие.
Все слоты, связанные с излучаемым сигналом, будут выполнены.
Вы не должны думать о сигналах как о событиях, потому что, как вы можете прочитать в документации Qt:
Когда вы отправляете событие, оно должно подождать некоторое время, пока цикл событий не отправит все события, которые произошли ранее. Из-за этого выполнение кода после отправки события или сигнала отличается. Код после отправки события будет запущен немедленно. С механизмами сигналов и слотов это зависит от типа подключения. Обычно он выполняется после всех слотов. Используя Qt :: QueuedConnection, он будет выполнен немедленно, как и события. Проверьте все типы подключения в документации Qt .
источник
When you send an event, it must wait for time when event loop dispatch all events that came earlier. Because of this, execution of the cod after sending event or signal is different
Есть статья, в которой более подробно обсуждается обработка событий: http://www.packtpub.com/article/events-and-signals
Здесь обсуждается разница между событиями и сигналами:
Кажется, это обычный способ говорить об этом, поскольку в принятом ответе используются некоторые из тех же фраз.
Обратите внимание, пожалуйста, ознакомьтесь с полезными комментариями ниже к этому ответу Кубы Обера, которые заставляют меня задаться вопросом, может ли он быть немного упрощенным.
источник
event
. Сигналы и слоты, являются, конкретно , методы, в то время как соединительный механизм представляет собой структуру данных , которая позволяет сигнал вызова одной или нескольких слотов , перечисленных в подключенных к нему. Я надеюсь, вы понимаете, что говорить о сигнале / слотах как о некотором «подмножестве» или «варианте» событий - это чепуха, и наоборот. Они действительно разные вещи , которые происходят , которые будут использоваться для аналогичных целей в контексте некоторых виджетов. Вот и все. ИМХО, чем больше вы обобщаете, тем менее полезным вы становитесь.TL; DR: сигналы и слоты являются косвенными вызовами методов. События - это структуры данных. Так что это совершенно разные животные.
Единственный раз, когда они объединяются, - это когда вызовы слотов выполняются через границы потоков. Аргументы вызова слота упаковываются в структуру данных и отправляются как событие в очередь событий принимающего потока. В принимающем потоке
QObject::event
метод распаковывает аргументы, выполняет вызов и, возможно, возвращает результат, если это было блокирующее соединение.Если мы хотим обобщить до забвения, можно думать о событиях как о способе вызова
event
метода целевого объекта . Это в некотором роде косвенный вызов метода, но я не думаю, что это полезный способ думать об этом, даже если это истинное утверждение.источник
События (в общем смысле взаимодействия пользователя / сети) обычно обрабатываются в Qt с помощью сигналов / слотов, но сигналы / слоты могут делать множество других вещей.
QEvent и его подклассы в основном представляют собой небольшие стандартизованные пакеты данных, используемые фреймворком для взаимодействия с вашим кодом. Если вы хотите каким-то образом обратить внимание на мышь, вам нужно только взглянуть на API QMouseEvent, и разработчикам библиотеки не нужно изобретать колесо каждый раз, когда вам нужно выяснить, что мышь сделала в каком-то углу. Qt API.
Это правда, что если вы ждете каких-либо событий (опять же в общем случае), ваш слот почти наверняка примет подкласс QEvent в качестве аргумента.
С учетом сказанного, сигналы и слоты, безусловно, можно использовать без QEvents, хотя вы обнаружите, что исходным стимулом для активации сигнала часто будет какое-то взаимодействие с пользователем или другая асинхронная активность. Однако иногда ваш код просто достигает точки, когда запуск определенного сигнала будет правильным решением. Например, запуск сигнала, связанного с индикатором выполнения во время длительного процесса, до этого момента не требует QEvent.
источник
Я нашел этот вопрос, читая «Обработка событий» Леоу Ви Кхенга. В нем также говорится:
Жасмин Бланшетт говорит:
источник
Еще одно незначительное прагматическое соображение: для испускания или приема сигналов требуется наследование,
QObject
тогда как объект любого наследования может публиковать или отправлять событие (поскольку вы вызываетеQCoreApplication.sendEvent()
илиpostEvent()
). Обычно это не проблема, но: для использования сигналов PyQt странным образом требует,QObject
чтобы он был первым суперклассом, и вы, возможно, не захотите изменять порядок наследования только для того, чтобы иметь возможность отправлять сигналы.)источник
На мой взгляд, события полностью повторяются и их можно выбросить. Нет никаких причин, по которым сигналы нельзя было бы заменить событиями или событиями сигналами, за исключением того, что Qt уже настроен как есть. Сигналы в очереди обертываются событиями, а события могут быть обернуты сигналами, например:
Заменил бы удобную
mouseMoveEvent()
функцию, найденную вQWidget
(ноQQuickItem
больше не в ), и будет обрабатыватьmouseMove
сигналы, которые менеджер сцены будет выдавать для элемента. Тот факт, что сигнал испускается от имени элемента какой-либо внешней сущностью, не важен и довольно часто случается в мире компонентов Qt, даже если это предположительно не разрешено (компоненты Qt часто обходят это правило). Но Qt представляет собой конгломерат множества различных дизайнерских решений и в значительной степени высечен из камня из-за страха сломать старый код (что в любом случае случается достаточно часто).источник
QObject
иерархии родитель-потомок. Соединения сигнал / слот - это просто обещание вызвать функцию, прямо или косвенно, при выполнении определенного условия. Нет связанной иерархии обработки с сигналами и слотами.accepted
ссылочный параметр к сигналу и обрабатывающим его слотам, или у вас может быть структура в качестве ссылочного параметра сaccepted
полем. Но Qt сделала выбор дизайна, который он сделал, и теперь они высечены в камне.