Qt Сигналы и слоты. Виджеты. Qt Designer

Следующая статейка про Qt. Сигналы и слоты, виджеты, Qt Designer, создание классов потомков от QWidget, QDialog, QMainWindow etc.

Сигналы и слоты. (стырено с crossplatform.ru)
Введение

«При программировании графического интерфейса пользователя мы часто хотим сообщать одним элементам об изменении других элементов управления. Более обобщенно можно сказать, что мы хотим обеспечить связь между объектами любых видов. Например, если пользователь нажимает кнопку Close мы, вероятно, хотим, чтобы была вызвана функция окна close().

Более старые инструментарии обеспечивают подобную связь с помощью функций обратного вызова. Обратный вызов — это указатель на функцию. Если вы хотите, чтобы функция обработки уведомила вас о некотором событии, вы передаете ей указатель на другую функцию (отзыв). Функция обработки вызовет функцию обратного вызова, когда это будет уместно. Но данный подход имеет два фундаментальных недостатка: во-первых, он не типобезопасен. Мы некогда не сможем проверить, что функция обработки вызывает отзыв с правильными аргументами. Во-вторых, этот метод жестко связан с функцией обработки, так как она должна знать, какой отзыв вызывать.

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



Этот механизм типобезопасен: сигнатура сигнала должна соответствовать сигнатуре принимающего слота. (Фактически, слот может иметь более короткую сигнатуру, чем сигнал, который он получает, поскольку может игнорировать лишние аргументы.) Сигналы и слоты связаны без нежёстко: Класс, испускающий сигналы, не знает и не интересуется, который из слотов получит сигнал. Механизм сигналов и слотов Qt гарантирует, что, если Вы соединили сигнал со слотом, слот будет вызываться с параметрами сигнала в нужный момент. Сигналы и слоты могут иметь любое количество аргументов любых типов. Они полностью типобезопасны.

Все классы, наследуемые от QObject или одного из его подклассов (например, QWidget) могут содержать сигналы и слоты. Сигналы испускаются при изменении объектом своего состояния, если это изменение может быть интересно другим объектам. Все объекты делают это для связи с другими объектами. Их не заботит, получает ли кто-нибудь испускаемые ими сигналы. Это является истинной инкапсуляцией информации, и она гарантирует, что объекты могут использоваться как отдельные компоненты программного обеспечения.

Слоты могут получать сигнал, но они также являются обыкновенными функциями-членами. Также, как объект не знает, получает ли кто-нибудь сигналы, испускаемые им, слоты не знают, существуют ли сигналы, с ними связанные. Это гарантирует, что можно создать полностью независимые Qt компоненты.

Вы можете присоединять к одному слоту столько сигналов, сколько вам будет нужно, и один сигнал может быть соединен со столькими слотами, сколько вам требуется. Даже возможно соединять сигнал непосредственно с другим сигналом. (Второй сигнал будет испускаться немедленно всякий раз, когда испускается первый.)

Вместе сигналы и слоты представляют собой мощный механизм компонентного программирования.
»

Виджет — визуальный элемент в Qt. Практически любой графический элемент в qt является производным классом от QWidget. Виджет получает события мыши, клавиатуры и другие события от оконной системы, а также отрисовывает себя на экране. Каждый виджет имеет прямоугольную форму. Виджет может быть потомком другого виджета и иметь своих потомков. Пример:


Вот некоторые полехные функции QWidget:

int height() const; // высота
int width() const; // ширина

void move(const QPoint &) // QPoint - координаты точки (x, y)
void move(int x, int y); // сдвинуть виджет
QPoint pos() const; // текущая позиция виджета относительно родительского виджета

void resize(const QSize &) // QSize - размер (width, height)
void resize(int w, int h) // Изменить размер виджета

void setCursor(const QCursor &) // сменить курсор над виджетом


И слоты:

void setWindowTitle(const QString &); // Изменить заголовок
void hide(); // скрыть виджет
void show(); // показать
void showMaximized(); // показать на весь экран
void update(); // перерисовать
void setStyleSheet(const QString & styleSheet); // установить таблицу стилей (CSS)


Создание своего виджета, диалога, окна и т.д.
1. Создаём два файла: MyClass.h и MyClass.cpp
H:

#ifndef MY_CLASS_H
#define MY_CLASS_H

//#include <smth>
// Если создавать форму в designer'e:
// #include <ui_MyClass.h>

class MyClass : public QMainWindow // QDialog, QWidget, etc
{
	Q_OBJECT // если используются сигналы и слоты

public:
	MyClass(QWidget *parent = 0); // QObject
	~MyClass();

private:
// форма
	Ui::MyClass *ui;

public slots: // публичные слоты
private slots: // приватные

signals: // сигналы

protected: // переопределенные ...Event() и др.
};

#endif // MY_CLASS_H

Макрос Q_OBJECT лучше вписать сразу, до первой компиляции, иначе потом могут появится непонятные ошибки.

CPP:
#include "MyClass.h"

MyClass::MyClass(QWidget *parent)
	: QMainWindow(parent), // QDialog, QObject, etc
        ui(new Ui::MyClass) // для форм
{
	ui.setupUi(this); // для форм
}

MyClass::~MyClass()
{
       delete ui; // для форм
}


Создание форм
Для того чтобы создать форму достаточно открыть Qt Designer и выбрать форму какого типы вы хотите создать:


Выберите например QWidget:

Справа, в редакторе свойств сразу впишите имя своего класса.

Перетягиваем какиенибудь виджеты слева:


Потом создаём производный класс от QWidget класс как описано выше, и в main.cpp:
MyClass my;
my.showMaximized();

Ну и давайте скомпилируем это под Win Mobile:


Теперь сделаем чтонибудь с использованием сигналов и слотов, перетягиваем следующие виджеты:


Теперь переходим в редактор сигналов и слотов:

(Кстати эти кнопки в меню — QAction, их обычно используют в QMainWindow)

Кликаем по dial и тянем стрелочку на spin box, слева выбираем сигнал valueChanged(int) а справа слот setValue(int):

Делаем тоже самое только теперь тянем стрелочку с spin box на dial, с calendar (clicked(QDate) ) на date edit (setDate(QDate) ) и наоборот (dateChanged(QDate) -> setSelectedDate(QDate) ):


Также в меню нажмите скомпоновать по сетке и авто размер.

Нажимаем CTRL+R для пред просмотра, и крутим dial в результате значение spin box так же изменяется, тоже будет и с календарём.

На сегодня всё.
  • +3
  • 18 ноября 2011, 20:01
  • RomiX

Комментарии (24)

RSS свернуть / развернуть
Киркоров, залогиньтесь.
0
Вам лучше определиться сразу – для какой аудитории вы пишете статью.
<ИмяКласса>::<ИмяКласса>(QWidget *parent)
Люди, знакомые с С++ знают, что такое «конструктор» :) Если человек не знает С++ — у него к Вам будет ОЧЕНЬ много вопросов помимо декларирования конструктора.
0
ок
0
В любом случае, спасибо за статью.
0
Рекомендую почитать Шлее, так понимаю что автор перепечатывает его, просто помпилируя под Embedded
0
Спасибо за совет, но с Qt я и так знаком достаточно близко (несколько лет писал приложения под Qt) Просто мне нравиться идея популяризации Qt/C++ среди членов сообщества, поэтому хочу указать автору на возможные (IMHO) недочеты.
0
Вот собственно с этой статьи «новичкам» открывается истинная личина Qt. Никакая это не «самая лучшая GUI библиотека», а типичный гуевый монстрик. Да, ему далеко до MFC, но все же. Все «новички» испугались и разбежались обратно паскакали.

И кстати, оцените стиль туториалов «хардистов» для «софтистов» — помините, каким кристально ясным был пример, как сделать PWM на Ардуине. И сравните туториал «софтистов» для «хардистов», полный псевдокритике обратных вызовов (хоть, то, что горячие скандинавские парни назвали идиотским словом «слот» и есть callback'ом), изображению мяса от Qt Designer'а и т.п.

Не обязательно было в начальном туториале скрещивать куй и губную гармошку, можно было просто показать, как в «буквах» (а не в картинках со стрелочками) можно засандалить 2 виджета и связать их сигналами, и все бы ахнули, мол надо учить Qt, как было в предыдущих заметках.
0
(хоть, то, что горячие скандинавские парни назвали идиотским словом «слот» и есть callback'ом)
Вообще-то, идеологически это делегаты. Хотя и их можно считать разновидностью коллбэков. Ну и по сравнению с коллбэками система сигналов куда мощнее. Во первых, они мультикастные, во вторых контроль типов, в третьих — можно привязывать сигнал к слоту с несколько другой сигнатурой.

Хотя с критикой самой статьи пожалуй и соглашусь.
А что за «помините, каким кристально ясным был пример, как сделать PWM на Ардуине»? Линк?
0
, во вторых контроль типов, в третьих — можно привязывать сигнал к слоту с несколько другой сигнатурой.
Взаимоисключающие утверждения детектед!
0
Ну это такая фишка Qt, некоторые сигнатуры, несмотря на различие, считаются совместимыми (в частности, если сигнатура слота имеет меньше параметров, чем сигнатура сигнала, причем имеющиеся совпадают с сигнатурой сигнала).
0
Хотя и их можно считать разновидностью коллбэков.

Да, callback'и с closure'ом, даже если в Qt closure ограничен bound method'ом.

Но суть не в этом, а в том, что в весьма краткой и поверхностной статье автору удалось показать многие «грязные кишки» Qt. И писать в таком духе туториалы считается нормальным для софта. Конечно же, не специально — оно само так выходит, «здесь так принято». Вывод — нужно специально писать по-другому.

А что за «помините, каким кристально ясным был пример, как сделать PWM на Ардуине»? Линк?

Да возьмите почти любую статью на Хабре по Ардуино. Куча каментов в духе «хачу», «почему я досе не делаю» и т.п. Потому что статьи (и проекты) сделаны так, чтобы показать, как что-то полезное или интересное можно легко и приятно сделать.

А для софта статьи пишутся с желанием пригрузить читателей buzzword'ами — мол какая мощная система. Вывод — нужен Arduino в мире софта.
0
Любая статья по Си++ будет выносить мозг новичку, если он никогда не программировал на этом самом Си++. Возьмите хоть статьи neiver'а который пишет очень лаконично и доходчиво, и все равно код, даже максимально закомментированый, мозг выносит напрочь.
А статья по организации PWM кстати тоже будет выносить мозг человеку неподготовленному и не представляющему что такое мк, как бы кристально чисто она не была написана…
0
Ну кончено, мы живем в лучшем из возможных миров, и ничего изменить нельзя. И очень трудно допереть, что сигналы подключаются к коннекторам, а не суются в щель. А если уж хочется щель, то в нее можно опускать, к примеру мессагу. Что, мелочи, да? «Как вы яхту назовете, так она и поплывет.» И если с такими мелочами людей путают, то дальше просто потоп.

Любая статья по Си++

Да ну?! Нет, Ардуинщики реально всколыхнули мир, и показали, что не обяхательно нудувать щеки изображая всю важность и сложность программирования и/или дизайна электронники, я фан. Посмотрите внимательно — у них C++, который не выносит мозг.

А статья по организации PWM кстати тоже будет выносить

Да ну? А вот у ардуинщиков — все кристально ясно. Вот включаем светодиод на промежуток времени, вот выключаем, вот повторяем с большой частотой. Меняем промежуток включения — и о чудо, меняется яркость! Те, кому для понимания недостаточно органов зрения, даже могут мацать светодиод и пробовать на зуб, пока не поймут.
0
И очень трудно допереть, что сигналы подключаются к коннекторам, а не суются в щель
А как тебе STL'евское «воткнуть сзади» (push_back)?)
0
Намана, потому что там не «воткнуть», а за'push'ить. Иными словами, мои претензии к Qt не на уровне «трудностей перевода», а на уровне раком выбранных метафор.
0
Сигнал в слот. Нормальная метафора, ничем не хуже. Даже лучше, т.к. я согласен с Боресковым насчет того, что push_back редкое уродство как по смыслу, так и по удобству (хотя сишники почему-то вообще любят знак _).
И push — именно «затолкать» в данном случае. Тогда как «slot» также означает гнездо, посадочное место. Не стоит забывать и о слове «слот», позаимствованном как раз в этом смысле.
Логично добавление в конец названо в Delphi RTL — Append.
0
Посмотрите внимательно — у них C++, который не выносит мозг.
помоему там просто обрезанный си. без плюсов…
Не все можно объяснить на уровне конструктора Лего. Такая информация обычно малоприменима.
0
помоему там просто обрезанный си. без плюсов…

Там C++, и чтоб не выносить мозг новичкам, используется его подмножество. Но если вам захочется подключить туда же STL, MFC или Qt, то пожалуйста. Просто — сюрприз — оно там не надо и его туда не тянут.

Не все можно объяснить на уровне конструктора Лего.

Да, но уровень Лего — неплохая основа для последующих уровней. Именно поэтому дети учат сначала лего, а потом синхрофазатроны. И лего учит прежде всего здравому структурному смыслу, и неплохо этот «лего-тест» применять время от времени.
0
Ну тут Вам виднее. Я начал программировать контроллеры проскочив мимо стадии Адруино (а может ее тогда еще и небыло). Просто получив задачу, книжку по описанию семейства AVR, книжку по программированию на си и имея некоторый опыт написания программ на бейсике, паскале и ассемблере для компа. Никаких спецзнаний по программированию и электронике у меня небыло. И никаких сложностей не возникло. А, еще мне дали макетную плату на которой был контроллер с кварцем и схемой сброса, стабилизатор на 5 В и все ноги выведенные на PLS…
0
Я начинал с цифровой электроникой когда никаких AVR и в проекте не было, до широких просторов советской родины еще не добрались Z80, и последним чудом техники были 8080 в исполнении K580ИК80. И я давно-давно из этого вырос, и никогда бы не подумал, что вернусь к таким маленьким глупеньким вещам, как микроконтроллеры и пайка. Благодаря Ардуино — возвращаюсь. И вижу, что софт-ленду с его [искусственной] переусложненностью есть чему поучиться…
0
Что-то в этом есть. Но Qt я бы не назвал сильно сложным снаружи. Та же система сигналов и слотов весьма легка для понимания — бросил кнопку, воткнул сигнал в форму, ура — закрывает! В этом плане оно похоже на VCL — достаточно сложно внутри, но легко осваивается и используется. А внутренняя сложность нужна именно для того, чтобы снаружи все было просто и удобно, но она касается только разработчиков библиотеки.
В статье это освещено неудачно, согласен.
0
Чет я не догнал. Кинул виджеты, соединил их стрелочками. Все работает, а где сам код то который при этом сгенерировался? В main.cpp и mainwindow.cpp его не появилось, хотя я ожидал там нечто вида:


void MainWindow::on_dial_sliderMoved(int position)
{
 ui->pushButton->setText(QString::number(ui->dial->value()));
}
0
они в *. ui

например

dial
dialMoved (int)
progressBar
setValue (int)
197
108

178
199



0
комментарий был удален
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.