|
|
Строка 1: |
Строка 1: |
| [[Файл:Qt-logo.png|right|150px]]
| | Несложная работа, высокая зарплата! |
| | | |
| Сигналы и слоты - это то, как в Qt взаимодействуют между собой объекты разных классов.
| | Вы работаете дома! Полностью честно и прозрачно; |
| | | Доступно для всех - неважно кто вы и какой у вас опыт работы в интернете! |
| == Как это работает в теории ==
| | Вы будете зарабатывать: свыше четырёх тысяч рублей в день! |
| | | Сложность: Несложно! |
| Связь между объектами устанавливается следующим образом: у одного объекта должен быть сигнал, а у второго - слот. Сигнал объявляется однажды и на этом всё, ему не нужна реализация. Слот же, в общем-то, представляет собой функцию, и потому кроме объявления должен иметь реализацию, как и обычная функция.
| | Оплата: - уже на следующий деньги у вас на счету! |
| | | |
| Потому, соединив сигнал первого объекта и слот второго, мы получаем следующее: каждый раз, когда первый объект посылает свой сигнал, второй объект принимает его в свой слот и выполняет его функцию.
| | Ознакомтесь с условиями у нас на сайте. > www.pisma.exrabota.ru < Скопируйте и вставьте в адресную строку Вашего браузера. |
| | |
| Таким образом, чтобы соединить два объекта, нужно:
| |
| # создать у одного сигнал, а у второго слот;
| |
| # соединить сигнал первого и слот второго.
| |
| | |
| Это можно изобразить вот так:
| |
| | |
| [[Файл:Qt signls.and.slots pic1.png|800px]]
| |
| | |
| На рисунке:
| |
| :а) два изначальных объекта, ничем ни с кем не соединены;
| |
| :б) у первого объекта появился сигнал, а у второго - слот. Теперь им есть чем соединяться, но они всё ещё ни с кем не соединены;
| |
| :в) сигнал первого объекта соединён со слотом второго. | |
| | |
| Каждый объект может иметь больше одного сигнала и больше одного слота. Соединяться могут также более двух объектов:
| |
| | |
| [[Файл:Qt signls.and.slots pic2.png|500px]]
| |
| | |
| Как видно, кроме очевидных соединений, при отправке Объектом 4 сигнала выполнятся слот Объекта 3 и слот Объекта 1.
| |
| | |
| === Примеры ===
| |
| | |
| Немного поясняющих картинок:
| |
| <gallery widths="400px" heights="250">
| |
| Файл:Signals.and.slots.start.jpg|Один сигнал соединён с одинаковыми слотами разных объектов (наследников одного класса)
| |
| Файл:Signals.and.slots.abe.jpg|Один сигнал соединён с разными слотами разных объектов
| |
| </gallery>
| |
| | |
| Картинка с мудакенами может внести некоторую путаницу, потому её следует сопроводить разъяснением.
| |
| | |
| Каждый мудакен (из пяти слева) имеет набор слотов, будем считать, что у всех одинаковый (потому что все они унаследованы от одного класса <code>Мудакен</code>). То есть, у каждого из них есть следующие:
| |
| * <code>здарова()</code>;
| |
| * <code>сам_привет()</code>;
| |
| * <code>ну_привет()</code>;
| |
| * <code>хай()</code>;
| |
| * <code>пошёл_ты()</code>.
| |
| | |
| Эйб может подать сигнал <code>привет()</code>.
| |
| | |
| Можно было бы соединить его сигнал с каким-то одним слотом, одинаковым для всех пяти остальных мудакенов, к которым он обращается, но такая ситуация уже показана на картинке со стометровкой. Потому мы соединили сигнал Эйба с различными слотами ответов мудакенов.
| |
| | |
| Путаница могла возникнуть такая, что можно было подумать, что <code>пошёл_ты()</code> (ну и остальные) - это уже реакция на приветствие Эйба. Но это не так, это лишь ''имя реакции'' (имя слота), а реализация у неё может быть какой угодно.
| |
| | |
| Например, очевидный:
| |
| <syntaxhighlight lang="cpp">
| |
| QString MudakenAngry::пошёл_ты()
| |
| {
| |
| QString answer = "Да пошёл ты. Пива не принёс, ничего не принёс, ещё хочет чего-то. Вообще охренеть.";
| |
| return answer;
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| или не очень:
| |
| <syntaxhighlight lang="cpp">
| |
| QString MudakenAngry::пошёл_ты()
| |
| {
| |
| QString answer = "Ну наконец-то! Где тебя носило? Пошли за пивом уже!";
| |
| return answer;
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| Конечно, при написании кода лучше делать так, чтобы название и функционал совпадали по смыслу, потому второй вариант приведён лишь в качестве примера.
| |
| | |
| == Как это сделать в Qt ==
| |
| | |
| === QObject ===
| |
| | |
| Необходимое условие - при описании класса должен быть использован макрос <code>Q_OBJECT</code>, а сами классы должны так или иначе происходить от класса <code>QObject</code>:
| |
| | |
| <syntaxhighlight lang="cpp" line highlight="3">
| |
| class MeClass : public QObject
| |
| {
| |
| Q_OBJECT
| |
| | |
| public:
| |
| MeClass();
| |
| | |
| ...
| |
| | |
| };
| |
| </syntaxhighlight>
| |
| | |
| === Сигналы ===
| |
| | |
| Создать сигнал можно так:
| |
| | |
| <syntaxhighlight lang="cpp" line highlight="9">
| |
| class MeClass : public QObject
| |
| {
| |
| Q_OBJECT
| |
| | |
| public:
| |
| MeClass();
| |
| | |
| signals:
| |
| void someSignal();
| |
| | |
| ...
| |
| | |
| };
| |
| </syntaxhighlight>
| |
| | |
| Теперь сигнал можно отправить в любом месте:
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| emit someSignal();
| |
| </syntaxhighlight>
| |
| | |
| === Слоты ===
| |
| | |
| Создать слот можно так:
| |
| | |
| <syntaxhighlight lang="cpp" line highlight="12">
| |
| class MeClass : public QObject
| |
| {
| |
| Q_OBJECT
| |
| | |
| public:
| |
| MeClass();
| |
| | |
| signals:
| |
| void someSignal();
| |
| | |
| public slots:
| |
| void someSlot();
| |
| | |
| ...
| |
| | |
| };
| |
| </syntaxhighlight>
| |
| | |
| === Сигналы и слоты с параметрами ===
| |
| | |
| Кроме простого соединения, сигналы и слоты позволяют передавать между объектами переменные. Для этого соединяемые сигнал и слот должны иметь параметр одного типа:
| |
| | |
| <syntaxhighlight lang="cpp" line highlight="11, 27">
| |
| // первый класс, отправитель
| |
| class MeClass : public QObject
| |
| {
| |
| Q_OBJECT
| |
| | |
| public:
| |
| MeClass();
| |
| | |
| signals:
| |
| // сигнал будет передавать переменную типа int
| |
| void someSignal(int value2send);
| |
| | |
| ...
| |
| | |
| };
| |
| | |
| // второй класс, получатель
| |
| class YaClass : public QObject
| |
| {
| |
| Q_OBJECT
| |
| | |
| public:
| |
| YaClass();
| |
| | |
| public slots:
| |
| // слот будет принимать переменную типа int
| |
| void someSlot(int value2get);
| |
| | |
| ...
| |
| | |
| };
| |
| </syntaxhighlight> | |
| | |
| === Соединение ===
| |
| | |
| Функция соединения сигнала первого объекта и слота второго объекта имеет четыре параметра:
| |
| # отправитель сигнала;
| |
| # его сигнал;
| |
| # получатель сигнала;
| |
| # его слот.
| |
| | |
| Соединение сигнала <code>meClass</code> и слота <code>yaClass</code>:
| |
| | |
| <syntaxhighlight lang="cpp" line highlight="4">
| |
| MeClass meClass();
| |
| YaClass yaClass();
| |
| | |
| connect(meClass, SIGNAL(someSignal(int)), yaClass, SLOT(someSlot(int)));
| |
| </syntaxhighlight>
| |
| | |
| Теперь при каждой отправке сигнала <code>someSignal(int)</code> объекта <code>meClass</code> будет выполняться слот <code>someSlot(int)</code> объекта <code>yaClass</code>.
| |
| | |
| == Демонстрационный пример ==
| |
| | |
| Приложение состоит из главного окна Сигналы и слоты, Первого окна и Второго окна.
| |
| | |
| [[Файл:Qt signls.and.slots pic3.png]]
| |
| | |
| Первое и Второе окно (точнее, объекты их классов) соединяются посредством сигналов и слотов для обмена строкой из своих полей ввода (каждый из двух классов содержит как сигнал, так и слот). Полученная строка будет отображаться в соответствующей надписи окна-получателя.
| |
| | |
| Главное окно также соединяется сигналом своего закрытия (уничтожения) со слотами закрытия Первого и Второго окон.
| |
| | |
| Проект приложения можно загрузить [http://yadi.sk/d/Csajnu040IX5Z здесь].
| |
| | |
| === Главное окно ===
| |
| | |
| <code>mainwindow.h:</code>
| |
| <syntaxhighlight lang="cpp" line>
| |
| ...
| |
| | |
| protected:
| |
| // событие закрытия главного окна, будет посылать всем сигнал закрытия
| |
| /// это стандартная виртуальная функция класса, поэтому мы её лишь переопределяем
| |
| virtual void closeEvent(QCloseEvent *event);
| |
|
| |
| ...
| |
| | |
| </syntaxhighlight>
| |
| | |
| <code>mainwindow.cpp:</code>
| |
| <syntaxhighlight lang="cpp" line>
| |
| ...
| |
| | |
| // реализация переопределённой функции
| |
| void MainWindow::closeEvent(QCloseEvent *event)
| |
| {
| |
| emit destroyed(); // отправить сигнал о закрытии (уничтожении) окна
| |
| }
| |
|
| |
| ...
| |
| | |
| // соединение сигнала от главного окна со слотом первого окна
| |
| connect(this, SIGNAL(destroyed()), frst, SLOT(close()));
| |
| // соединение сигнала от главного окна со слотом второго окна
| |
| connect(this, SIGNAL(destroyed()), scnd, SLOT(close()));
| |
| // слоты close() являются стандартными, потому объявлять в классах окон их не нужно
| |
| | |
| ...
| |
| | |
| // соединение сигнала от первого окна со слотом второго окна
| |
| connect(frst, SIGNAL(sendMessage(QString)),
| |
| scnd, SLOT(receiveMessage(QString)));
| |
| | |
| // соединение сигнала от второго окна со слотом первого окна
| |
| connect(scnd, SIGNAL(sendMessage(QString)),
| |
| frst, SLOT(receiveMessage(QString)));
| |
| </syntaxhighlight>
| |
| | |
| === Первое окно ===
| |
| | |
| <code>frst.h:</code>
| |
| <syntaxhighlight lang="cpp" line>
| |
| ...
| |
| | |
| signals:
| |
| /// @brief сигнал отправки сообщения второму окну
| |
| /// @param msg2send - отправляемая в сигнале строка
| |
| void sendMessage(QString msg2send);
| |
| | |
| public slots:
| |
| /// @brief слот, в которой будет приходить сигнал от второго окна
| |
| /// @param msg2recieve - получаемая из сигнала второго окна строка
| |
| void receiveMessage(QString msg2recieve);
| |
|
| |
| ...
| |
| | |
| </syntaxhighlight>
| |
| | |
| <code>frst.cpp:</code>
| |
| <syntaxhighlight lang="cpp" line>
| |
| ...
| |
| | |
| // обработчик нажатия кнопки отправки
| |
| void Frst::on_btn_sendToSecond_clicked()
| |
| {
| |
| // посылает сигнал, содержащий строку из поля ввода
| |
| emit sendMessage(ui->lineEdit_first->text());
| |
| }
| |
| | |
| // слот получения сигнала
| |
| void Frst::receiveMessage(QString msg2recieve)
| |
| {
| |
| // принимает строку из сигнала и вставляет её в надпись
| |
| ui->label_received_first->setText(msg2recieve);
| |
| }
| |
| | |
| ...
| |
| </syntaxhighlight>
| |
| | |
| === Второе окно ===
| |
| | |
| <code>scnd.h:</code>
| |
| <syntaxhighlight lang="cpp" line>
| |
| ...
| |
| | |
| signals:
| |
| /// @brief сигнал отправки сообщения первому окну
| |
| /// @param msg2send - отправляемая в сигнале строка
| |
| void sendMessage(QString msg2send);
| |
| | |
| public slots:
| |
| /// @brief слот, в которой будет приходить сигнал от первого окна
| |
| /// @param msg2recieve - получаемая из сигнала первого окна строка
| |
| void receiveMessage(QString msg2recieve);
| |
|
| |
| ...
| |
| | |
| </syntaxhighlight>
| |
| | |
| <code>scnd.cpp:</code>
| |
| <syntaxhighlight lang="cpp" line>
| |
| ...
| |
| | |
| // обработчик нажатия кнопки отправки
| |
| void Scnd::on_btn_sendToFirst_clicked()
| |
| {
| |
| // посылает сигнал, содержащий строку из поля ввода
| |
| emit sendMessage(ui->lineEdit_second->text());
| |
| }
| |
| | |
| // слот получения сигнала
| |
| void Scnd::receiveMessage(QString msg2recieve)
| |
| {
| |
| // принимает строку из сигнала и вставляет её в надпись
| |
| ui->label_received_second->setText(msg2recieve);
| |
| }
| |
| | |
| ...
| |
| </syntaxhighlight>
| |
| | |
| == Дополнительно ==
| |
| | |
| Более подробно про механизм сигналов и слотов можно прочитать [[Qt#Книги | в книгах по Qt]] и в следующих статьях:
| |
| * [http://doc.crossplatform.ru/qt/4.3.2/signalsandslots.html CrossPlatform.RU - Сигналы и слоты];
| |
| * [http://www.developer.nokia.com/Community/Wiki/%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC_%D1%81%D0%B8%D0%B3%D0%BD%D0%B0%D0%BB%D0%BE%D0%B2_%D0%B8_%D1%81%D0%BB%D0%BE%D1%82%D0%BE%D0%B2_%D0%B2_Qt NOKIA Developer - Механизм сигналов и слотов в Qt].
| |
| | |
| Видео:
| |
| * [http://www.youtube.com/watch?v=JtyCM4BTbYo C++ Qt 04 - Signals and Slots] (на английском языке).
| |
| | |
| [[Категория:Погроммирование]]
| |