Qt中的消息处理
1 Qt中的消息處理簡單介紹
1.1Qt消息模型
Qt消息模型:
- Qt封裝了具體操作系統的消息機制。
- Qt遵循經典的GUI消息驅動事件模型。
思考如下幾個問題:
- Qt中如何表示用戶消息?
- Qt中如何映射用戶消息到消息處理函數?
- Qt中消息映射需要遵循什么規則?
1.2 信號與槽
Qt中定義了與系統消息相關的概念:
- 信號(Signal):
- 由操作系統產生的消息。
- 槽(Slot):
- 程序中的消息處理函數。
- 連接(Connect):
- 將系統消息綁定到消息處理函數。
Qt中的消息處理機制:
Qt的核心–QObject::connect函數:
Qt中的“新”關鍵字:
- SIGNAL:
- 用于指定消息名。
- SLOT:
- 用于指定消息處理函數名。
- Q_OBJECT:
- 所有自定義槽的類必須在類聲明的開始處加上Q_OBJECT。
- slots:
- 用于在類中聲明消息處理函數。
自定義槽:
- 只有QObject的子類才能自定義槽。
- 定義槽的類必須在聲明的最開始使用Q_OBJECT。
- 類中聲明槽時需要使用slots關鍵字。
- 槽與所處理的信號在函數簽名上必須一致。
- SIGNAL和SLOT所指定的名稱中:
- 可以包含參數類型。
- 不能包含具體的參數名。
解決經典問題:Object::connect:No such slot …
編程實驗:信號與槽初步使用
#include <QtGui/QApplication> #include <QPushButton>int main(int argc, char *argv[]) {QApplication a(argc, argv);QPushButton b;b.setText("Click me to quit!");b.show();QObject::connect(&b, SIGNAL(clicked()), &a, SLOT(quit()));return a.exec(); }編程實例:自定義槽
QCalculator.h:
#ifndef _QCALCULATORUI_H_ #define _QCALCULATORUI_H_#include <QWidget> #include <QLineEdit> #include <QPushButton>class QCalculatorUI : public QWidget {Q_OBJECT private:QLineEdit* m_edit;QPushButton* m_buttons[20];QCalculatorUI();bool construct(); private slots:void onButtonClicked(); public:static QCalculatorUI* NewInstance();void show();~QCalculatorUI(); };#endifQCalculator.cpp:
#include "QCalculatorUI.h" #include <QDebug>QCalculatorUI::QCalculatorUI() : QWidget(NULL, Qt::WindowCloseButtonHint) {}bool QCalculatorUI::construct() {bool ret = true;const char* btnText[20] ={"7", "8", "9", "+", "(","4", "5", "6", "-", ")","1", "2", "3", "*", "<-","0", ".", "=", "/", "C",};m_edit = new QLineEdit(this);if( m_edit != NULL ){m_edit->move(10, 10);m_edit->resize(240, 30);m_edit->setReadOnly(true);}else{ret = false;}for(int i=0; (i<4) && ret; i++){for(int j=0; (j<5) && ret; j++){m_buttons[i*5 + j] = new QPushButton(this);if( m_buttons[i*5 + j] != NULL ){m_buttons[i*5 + j]->resize(40, 40);m_buttons[i*5 + j]->move(10 + (10 + 40)*j, 50 + (10 + 40)*i);m_buttons[i*5 + j]->setText(btnText[i*5 + j]);connect(m_buttons[i*5 + j], SIGNAL(clicked()), this, SLOT(onButtonClicked()));}else{ret = false;}}}return ret; }QCalculatorUI* QCalculatorUI::NewInstance() {QCalculatorUI* ret = new QCalculatorUI();if( (ret == NULL) || !ret->construct() ){delete ret;ret = NULL;}return ret; }void QCalculatorUI::show() {QWidget::show();setFixedSize(width(), height()); }void QCalculatorUI::onButtonClicked() {QPushButton* btn = (QPushButton*)sender();qDebug() << "onButtonClicked()";qDebug() << btn->text(); }QCalculatorUI::~QCalculatorUI() {}2 深入理解信號與槽
一個事實:
- 在實際的項目開發中,大多數時候是直接將組件中預定義的信號連接到槽函數;信號發射的時候槽函數被調用。
深度的思考:
- 信號是怎么來的?又是如何發射的?
Qt中信號(SIGNAL)的本質:
-
信號只是一個特殊的成員函數聲明:
- 函數的返回值是void類型。
- 函數只能聲明不能定義。
-
信號必須使用signals關鍵字進行聲明:
- 函數的訪問屬性自動被設置為protected。
- 只能通過emit關鍵字調用函數(發射信號)。
信號定義示例:
信號與槽的對應關系:
信號與槽的關系:
- 一個信號可以連接到多個槽(一對多)。
- 多個信號可以連接到一個槽(多對一)。
- 一個信號可以連接到另一個信號(轉嫁)。
- 連接可以被disconnect函數刪除(移除)。
對于信號與槽我們必須注意如下:
信號與槽的意義:
- 最大限度的弱化了類之間的耦合關系。
- 在設計階段,可以減少不必要的接口類(抽象類)。
- 在開發階段,對象間的交互通過信號與槽動態綁定。
示例代碼:
RxClass.h:
#ifndef RXCLASS_H #define RXCLASS_H#include <QObject> #include <QDebug>class RxClass : public QObject {Q_OBJECT public:protected slots:void mySlot(int v){qDebug() << "void mySlot(int v)";qDebug() << "Sender: " << sender()->objectName();qDebug() << "Receiver: " << this->objectName();qDebug() << "Value: " << v;qDebug() << endl;} };#endif // RXCLASS_HTestSignal.h:
#ifndef TESTSIGNAL_H #define TESTSIGNAL_H#include <QObject>class TestSignal : public QObject {Q_OBJECTpublic:void send(int i){emit testSignal(i);}signals:void testSignal(int v);};#endif // TESTSIGNAL_Hmain.cpp:
#include <QtCore/QCoreApplication> #include <QDebug> #include "TestSignal.h" #include "RxClass.h"void emit_signal() {qDebug() << "emit_signal()" << endl;TestSignal t;RxClass r;t.setObjectName("t");r.setObjectName("r");QObject::connect(&t, SIGNAL(testSignal(int)), &r, SLOT(mySlot(int)));for(int i=0; i<3; i++){t.send(i);} }void one_to_multi() {qDebug() << "one_to_multi()" << endl;TestSignal t;RxClass r1;RxClass r2;t.setObjectName("t");r1.setObjectName("r1");r2.setObjectName("r2");QObject::connect(&t, SIGNAL(testSignal(int)), &r1, SLOT(mySlot(int)));QObject::connect(&t, SIGNAL(testSignal(int)), &r2, SLOT(mySlot(int)));t.send(100); }void multi_to_one() {qDebug() << "multi_to_one()" << endl;TestSignal t1;TestSignal t2;RxClass r;t1.setObjectName("t1");t2.setObjectName("t2");r.setObjectName("r");QObject::connect(&t1, SIGNAL(testSignal(int)), &r, SLOT(mySlot(int)));QObject::connect(&t2, SIGNAL(testSignal(int)), &r, SLOT(mySlot(int)));t1.send(101);t2.send(102); }void signal_to_signal() {qDebug() << "signal_to_signal()" << endl;TestSignal t1;TestSignal t2;RxClass r;t1.setObjectName("t1");t2.setObjectName("t2");r.setObjectName("r");QObject::connect(&t1, SIGNAL(testSignal(int)), &t2, SIGNAL(testSignal(int)));QObject::connect(&t2, SIGNAL(testSignal(int)), &r, SLOT(mySlot(int)));t1.send(101);t2.send(102); }int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// emit_signal();// one_to_multi();// multi_to_one();// signal_to_signal();return a.exec(); }參考資料:
總結
- 上一篇: Qt中的QLineEdit、QTextE
- 下一篇: 坑字怎么读?