Урок №9. Слоты, Сигналы и События в Qt5

  Дмитрий Бушуев  | 

  Обновл. 7 Дек 2019  | 

 5867

 ǀ   6 

В этом уроке мы поговорим о слотах, сигналах и событиях в Qt5.

Модель событий в программах Qt5

Механизм сигналов и слотов является расширением языка программирования С++, который используется для установления связи между объектами. Если происходит какое-либо определённое событие, то при этом может генерироваться сигнал. Данный сигнал попадает в связанный с ним слот. В свою очередь, слот — это обычный метод в C++, который присоединяется к сигналу; он вызывается тогда, когда генерируется связанный с ним сигнал. Как видите, ничего сложного здесь нет.

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

В модели событий есть три участника:

   источник события — это объект, состояние которого изменяется;

   объект события — это отслеживаемый параметр источника события (например, нажатие клавиши на клавиатуре или изменение размеров виджета);

   цель события — это объект, который должен быть уведомлен о произошедшем событии.

Не нужно путать сигналы с событиями. Сигналы необходимы для организации взаимодействия между виджетами, тогда как события необходимы для организации взаимодействия между виджетом и системой.

Щелчок мыши


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

Заголовочный файл — click.h:

Файл реализации — click.cpp:

Метод connect() соединяет сигнал со слотом. Когда мы нажимаем на кнопку Quit, генерируется сигнал щелчка кнопки мыши. qApp — это глобальный указатель на объект нашего приложения. Он определяется в заголовочном файле QApplication. Метод quit() вызывается при появлении сигнала щелчка мышкой:

Главный файл программы — main.cpp:

Результат:

Нажатие кнопки клавиатуры

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

Заголовочный файл — keypress.h:

Файл реализации — keypress.cpp:

Одним из способов работы с событиями в Qt5 является переопределение обработчика событий. QKeyEvent — это класс, который содержит информацию о произошедшем событии. В нашем случае, мы используем объект данного класса, чтобы определить, какая именно клавиша была нажата:

Главный файл программы — main.cpp:

Класс QMoveEvent


Класс QMoveEvent содержит параметры событий, возникающих при перемещении виджета. В следующем примере мы реагируем на событие перемещения, затем определяем текущие координаты x и y верхнего левого угла клиентской области окна и устанавливаем эти значения в заголовок окна.

Заголовочный файл — move.h:

Файл реализации — move.cpp:

Мы используем объект класса QMoveEvent для определения значений x и y:

Затем мы конвертируем целочисленные значения в строки:

И с помощью метода setWindowTitle() устанавливаем текст в заголовок окна:

Главный файл программы — main.cpp:

Результат:


Отключение сигналов

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

В заголовочном файле мы объявили два слота. Следует отметить, что slot не является ключевым словом в C++, а лишь расширение Qt5. Подобные расширения обрабатываются препроцессором фреймворка до выполнения компиляции кода. Когда в наших классах мы используем сигналы и слоты, то обязательно должны предоставить макрос Q_OBJECT в начало определения класса. В противном случае препроцессор будет выдавать сообщения об ошибках.

В следующем примере у нас есть кнопка и флажок. Флажок подключает и отключает слот от сигнала нажатия кнопок.

Заголовочный файл — disconnect.h:

Файл реализации — disconnect.cpp:

Подключаем сигналы к нашим пользовательским слотам:

Если мы делаем щелчок мышкой, то в окно терминала будет отправляться текст Button clicked:

Внутри слота onCheck() мы подключаем или отключаем слот onClick() от кнопки, в зависимости от полученного параметра состояния:

Главный файл программы — main.cpp:

Результат:


Таймер


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

В следующем примере мы попробуем отобразить в окне текущее местное время.

Заголовочный файл — timer.h:

Файл реализации — timer.cpp:

Для отображения времени мы используем виджет-метку:

Затем мы определяем текущее местное время и устанавливаем его в виджет-метку:

Запускаем таймер (при этом каждые 1000 мс генерируется событие таймера):

Для работы с событиями таймера необходимо переопределить метод timerEvent():

Главный файл программы — main.cpp:

Результат:


Заключение

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


Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (14 оценок, среднее: 4,71 из 5)
Загрузка...

Комментариев: 6

  1. Аватар Jane:

    Скажите, пожалуйста, как правильно в "Отключение сигналов" задать QTextStream out(stdout), чтобы при запуске через консоль печатало "Button clicked" в эту же консоль? Ожидалось, что будет печатать. Приложение запускается, чек-бокс работает, а при нажатии на кнопку не выводит ничего(

    1. Дмитрий Бушуев Дмитрий Бушуев:

      Честно говоря — без понятия, никогда таким вопросом не задавался 🙂

  2. Аватар Александр:

    Подскажите по нескольким базовым вопросам:
    1. В файле keypress.h что значит class KeyPress : public QWidget {?
    2. В файле keypress.cpp что значит void KeyPress::keyPressEvent(QKeyEvent *event) {?
    3. Тут же откуда взялась qApp что она означает? в выражении qApp->quit();

    1. Дмитрий Бушуев Дмитрий Бушуев:

      1. Это значит, что мы берем класс QWidget и создаем от него потомка (класс KeyPress). Такой приём носит название "Наследование". Благодаря ему класс потомок наделяется всеми свойствами, которые есть у предка. Подробнее об этом можно почитать здесь:
      https://ravesli.com/urok-153-nasledovanie-vvedenie/
      https://ravesli.com/urok-154-bazovoe-nasledovanie-v-c/

      2. void KeyPress::keyPressEvent(QKeyEvent *event) — это функция-обработчик события нажатия кнопки.

      3. Практически в самом начале статье есть ответ на ваш вопрос:
      "[…] qApp — это глобальный указатель на объект нашего приложения. Он определяется в заголовочном файле QApplication[…]".

      Взялось оно вот отсюда:

      1. Аватар Александр:

        1. А в файле "keypress.cpp"

        это просто конструктор, со списком инициализации членов?
        Как раз сейчас повторяю основы ООП 120 урок, до 153 еще не дошел! =)

        2. keyPressEvent — она описана в QT, в каком-нибудь QMoveEvent?
        Как туда перейти, чтобы посмотреть? Раньше вроде можно было F12 нажать и перейти к определению функции? Или я что-то путаю?

        1. Дмитрий Бушуев Дмитрий Бушуев:

          1. Да, он самый 🙂
          2. https://imgur.com/a/nVejnzz

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *