События Qt и сигнал / слоты - PullRequest
       4

События Qt и сигнал / слоты

81 голосов
/ 25 сентября 2010

Какая разница между событиями и сигналом / слотами в мире Qt?

Один заменяет другой?Являются ли события абстракцией сигнала / слотов?

Ответы [ 10 ]

137 голосов
/ 25 сентября 2010

В Qt сигналы и события являются реализациями шаблона Observer .Они используются в разных ситуациях, потому что имеют разные сильные и слабые стороны.

Прежде всего, давайте определим, что именно мы подразумеваем под «событием Qt»: виртуальная функция в классе Qt, которую вы, как ожидается, будете переопределять.в вашем базовом классе, если вы хотите обработать событие.Это связано с шаблоном Template Method .

Обратите внимание, как я использовал слово " handle ".Действительно, вот основное различие между намерением сигналов и событий:

  • Вы " обрабатывает " события
  • Вы " получаете уведомление о"эмиссия сигнала

Разница в том, что когда вы" обрабатываете "событие, вы берете на себя ответственность" реагировать "поведением, которое полезно вне класса.Например, рассмотрим приложение, в котором есть кнопка с номером.Приложение должно позволить пользователю сфокусировать кнопку и изменить номер, нажимая клавиши «вверх» и «вниз» на клавиатуре.В противном случае кнопка должна работать как обычный QPushButton (ее можно нажать и т. Д.).В Qt это делается созданием собственного небольшого многократно используемого «компонента» (подкласс QPushButton), который переопределяет QWidget::keyPressEvent.Псевдокод:

class NumericButton extends QPushButton
    private void addToNumber(int value):
        // ...

    reimplement base.keyPressEvent(QKeyEvent event):
        if(event.key == up)
            this.addToNumber(1)
        else if(event.key == down)
            this.addToNumber(-1)
        else
            base.keyPressEvent(event)

Видите?Этот код представляет новую абстракцию: виджет, который действует как кнопка, но с некоторыми дополнительными функциями.Мы добавили эту функциональность очень удобно:

  • Поскольку мы повторно реализовали виртуальную, наша реализация автоматически стала инкапсулированной в нашем классе.Если бы разработчики Qt сделали keyPressEvent сигнал, нам нужно было бы решить, наследовать ли QPushButton или просто подключиться к сигналу извне.Но это было бы глупо, поскольку в Qt вы всегда ожидаете наследовать при написании виджета с пользовательским поведением (по уважительной причине - возможность повторного использования / модульность).Таким образом, делая keyPressEvent событием, они выражают свое намерение, что keyPressEvent - это просто основной строительный блок функциональности.Если бы это был сигнал, он был бы похож на пользовательский объект, когда он не предназначен для этого.
  • Так как реализация функции базового класса доступна, мы легко реализуем Образец цепочки ответственности , обрабатывая наши особые случаи (клавиши вверх и вниз) и оставляя остальное базовому классу.Вы можете видеть, что это было бы почти невозможно, если бы keyPressEvent был сигналом.

Дизайн Qt хорошо продуман - они заставили нас упасть в пропасть успеха упростить выполнение правильных и неправильных действий (сделав keyPressEvent событием).

С другой стороны, рассмотрим простейшее использование QPushButton - , просто его создание иполучать уведомление при нажатии :

button = new QPushButton(this)
connect(button, SIGNAL(clicked()), SLOT(sayHello())

Это явно предназначено для пользователя класса:

  • , если бы у нас былоподкласс QPushButton каждый раз, когда мы хотим, чтобы какая-то кнопка уведомляла нас о щелчке, что потребовало бы большого количества подклассов без веской причины! Виджет, который всегда отображает «Hello world» messagebox, когдаclicked полезен только в одном случае, поэтому его нельзя использовать повторно.Опять же, у нас нет другого выбора, кроме как поступить правильно - подключившись к нему извне.
  • мы можем захотеть подключить несколько слотов к clicked() - или подключить несколько сигналов к sayHello().С сигналами нет суеты.С подклассами вам придется сесть и обдумать некоторые диаграммы классов, пока вы не определитесь с подходящим дизайном.

Обратите внимание, что одно из мест, QPushButton излучающих clicked(), находится в его реализации mousePressEvent(),Это не означает, что clicked() и mousePressEvent() являются взаимозаменяемыми - просто они связаны между собой.

Таким образом, сигналы и события имеют разные цели (но связаны с тем, что оба позволяют "подписаться" на уведомлениечто-то происходит).

38 голосов
/ 29 апреля 2012

Мне пока не нравятся ответы. - Позвольте мне сосредоточиться на этой части вопроса:

Являются ли события абстракцией сигнала / слотов?

Короткий ответ: нет. Длинный ответ поднимает «лучший» вопрос: как связаны сигналы и события?

Простой основной цикл (например, Qt) обычно «застревает» в вызове select () операционной системы. Этот вызов переводит приложение в спящий режим, в то время как оно передает ядру кучу сокетов или файлов или что-то еще, запрашивая: если что-то изменится, пусть вызов select () вернется. - А ядро, как повелитель мира, знает, когда это произойдет.

Результатом этого вызова select () может быть: новые данные в сокете, подключенном к X11, поступил пакет с портом UDP, который мы прослушиваем, и т. Д. - Этот материал не является ни сигналом Qt, ни событие Qt, и главный цикл Qt решает сам, превращает ли он свежие данные в одно, другое или игнорирует их.

Qt может вызывать метод (или несколько), например keyPressEvent (), эффективно превращая его в событие Qt. Или Qt испускает сигнал, который фактически просматривает все функции, зарегистрированные для этого сигнала, и вызывает их одну за другой.

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

Событие может сработать или полностью превратиться в сигнал (просто сгенерировать его и не вызывать «super ()»). Сигнал можно превратить в событие (вызвать обработчик события).

Что абстрагирует, что зависит от случая: сигнал clicked () абстрагирует события мыши (кнопка перемещается вниз и вверх, не слишком перемещаясь). События клавиатуры - это абстракции с более низких уровней (такие вещи, как 果 или é - несколько нажатий клавиш в моей системе).

Возможно, focusInEvent () является примером обратного: он может использовать (и, следовательно, абстрагировать) сигнал clicked (), но я не знаю, действительно ли он используется.

27 голосов
/ 25 сентября 2010

Документация Qt , вероятно, объясняет это лучше всего:

В Qt события - это объекты, производные от абстрактного класса QEvent, которые представляют вещи, которые произошли либо внутриприложение или в результате внешней деятельности, о которой приложение должно знать.События могут быть получены и обработаны любым экземпляром подкласса QObject, но они особенно актуальны для виджетов.Этот документ описывает, как события доставляются и обрабатываются в типичном приложении.

Таким образом, события и сигнал / слоты - это два параллельных механизма, выполняющих одни и те же вещи.В общем случае событие будет сгенерировано внешней сущностью (например, клавиатурой или колесом мыши) и будет доставлено через цикл обработки событий в QApplication.В общем случае, если вы не настроите код, вы не будете генерировать события.Вы можете фильтровать их через QObject::installEventFilter() или обрабатывать события в подклассе объекта, переопределяя соответствующие функции.

Сигналы и слоты гораздо проще генерировать и получать, и вы можете подключить любые два подкласса QObject.Они обрабатываются через метакласс (подробнее смотрите в файле moc_classname.cpp), но большая часть межклассовой связи, которую вы будете производить, вероятно, будет использовать сигналы и слоты.Сигналы могут быть доставлены немедленно или отложены через очередь (если вы используете потоки).

Может быть сгенерирован сигнал.

13 голосов
/ 25 сентября 2010

События отправляются циклом событий.Каждая программа с графическим интерфейсом нуждается в цикле обработки событий, независимо от того, пишете ли вы в Windows или Linux, используя Qt, Win32 или любую другую библиотеку графического интерфейса.Также каждый поток имеет свой собственный цикл обработки событий.В Qt «Цикл событий GUI» (который является основным циклом всех приложений Qt) скрыт, но вы начинаете его вызывать:

QApplication a(argc, argv);
return a.exec();

Сообщения ОС и другие приложения, отправляемые в вашу программу, отправляются как события.

Сигналы и слоты являются механизмами Qt.В процессе компиляции с использованием moc (мета-объектный компилятор) они заменяются функциями обратного вызова.

У события должен быть один получатель, который должен его отправлять.Никто другой не должен получить это событие.

Все слоты, подключенные к излучаемому сигналу, будут выполнены.

Вы не должны думать о сигналах как о событиях, потому что, как вы можете прочитать в документации Qt:

Когда излучается сигнал, слоты, подключенные к нему, обычно выполняются немедленно, как обычный вызов функции.Когда это происходит, механизм сигналов и слотов полностью независим от любого цикла событий графического интерфейса.

Когда вы отправляете событие, оно должно подождать некоторое время, пока цикл событий не отправит все события, которые произошли ранее.Из-за этого выполнение кода после отправки события или сигнала отличается.Код после отправки события будет запущен немедленно.С механизмами сигналов и слотов это зависит от типа соединения.Обычно это выполняется после всех слотов.Используя Qt :: QueuedConnection, он будет выполнен немедленно, как и события.Проверьте все типы соединений в документации Qt .

7 голосов
/ 09 июля 2014

Есть статья, в которой подробно обсуждается обработка событий: http://www.packtpub.com/article/events-and-signals

Здесь обсуждается разница между событиями и сигналами:

События и сигналы являются двумя параллельными механизмами, используемыми для достижения то же самое. Как общее отличие, сигналы полезны при использовании виджет, тогда как события полезны при реализации виджета. За Например, когда мы используем виджет, такой как QPushButton, мы более интересует его сигнал clicked (), чем при низкоуровневом нажатии мыши или события нажатия клавиши, которые вызвали испускание сигнала. Но если мы реализуют класс QPushButton, нас больше интересует реализация кода для мыши и ключевых событий. Также мы обычно обрабатывать события, но получать уведомления по сигналам.

Кажется, это обычный способ говорить об этом, поскольку в принятом ответе используются одни и те же фразы.


Обратите внимание, пожалуйста, смотрите полезные комментарии ниже на этот ответ от Кубы Обер, что заставляет меня задуматься, может ли это быть немного упрощенно.

5 голосов
/ 12 января 2016

TL; DR: сигналы и слоты являются косвенными вызовами методов.События - это структуры данных.Так что это совершенно разные животные.

Единственный раз, когда они собираются вместе, это когда слоты звонят через границы потоков.Аргументы вызова слота упакованы в структуру данных и отправляются как событие в очередь событий принимающего потока.В принимающем потоке метод QObject::event распаковывает аргументы, выполняет вызов и, возможно, возвращает результат, если это было блокирующее соединение.

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

3 голосов
/ 25 сентября 2010

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

QEvent и его подклассы в основном очень малыстандартизированные пакеты данных для платформы, чтобы общаться с вашим кодом.Если вы хотите обратить внимание на мышь каким-то образом, вам нужно только взглянуть на API QMouseEvent, и разработчикам библиотек не нужно изобретать колесо каждый раз, когда вам нужно выяснить, что мышь сделала в каком-то углу.API Qt.

Это правда, что если вы ожидаете каких-либо событий (опять же в общем случае), ваш слот почти наверняка примет подкласс QEvent в качестве аргумента.

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

1 голос
/ 16 октября 2013

Другое незначительное прагматическое соображение: для выдачи или получения сигналов требуется наследование QObject, тогда как объект любого наследования может публиковать или отправлять событие (поскольку вы вызываете QCoreApplication.sendEvent() или postEvent()). Обычно это не проблема, но: использование сигналов PyQt странным образом требует, чтобы QObject был первым суперклассом, и вы можете не захотеть изменить порядок наследования, просто чтобы иметь возможность отправлять сигналы.)

0 голосов
/ 12 июня 2019

Я нашел этот вопрос, читая 'Обработка событий' от Leow Wee Kheng.В нем также говорится:

enter image description here

0 голосов
/ 16 июня 2016

По моему мнению, события полностью избыточны и могут быть выброшены.Нет причины, по которой сигналы не могут быть заменены событиями или событиями сигналами, за исключением того, что Qt уже настроен как есть.Поставленные в очередь сигналы упаковываются в события, а события, возможно, могут быть упакованы в сигналы, например:

connect(this, &MyItem::mouseMove, [this](QMouseEvent*){});

Заменили бы удобную функцию mouseMoveEvent(), найденную в QWidget (но больше не в QQuickItem)будет обрабатывать mouseMove сигналов, которые диспетчер сцены будет излучать для элемента.Тот факт, что сигнал излучается от имени элемента какой-либо внешней сущностью, не имеет значения и встречается довольно часто в мире компонентов Qt, даже если это предположительно не разрешено (компоненты Qt часто обходят это правило).Но Qt - это конгломерат множества различных дизайнерских решений и в значительной степени брошен в камне из-за боязни взлома старого кода (что в любом случае случается достаточно часто).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...