2010年9月13日 星期一

Qt4 學習筆記(四):Custom Signal & Slot

  • Custom Signal & Slot
    • 除了使用Qt現有元件預先定義好的Signal與Slot之外,也可以定義自己物件的Signal與Slot,方式是繼承QObject或它的子類別(例如QWidget)。
    • 現在改以定義一個物件,當拉桿拉動時,必須通知該物件儲存拉桿的游標值,而物件儲存的游標值有變動時,LCD數字顯示也必須更新,這樣的一個物件不是圖形元件,它是個資料模型,用以儲存與圖形介面無關的資料。

定義一個Model Class如下:
Model.h
#ifndef MODEL_H
#define MODEL_H
#include <QObject>

class Model : public QObject {
     Q_OBJECT

 public:
     Model() { m_value = 0; }
     int value() const { return m_value; }

 public slots:
     void setValue(int);

 signals:
     void valueChanged(int);

 private:
     int m_value;
 };

#endif

  • 簡介Qt的Meta-Object System,它基於以下三個部份:
    • QObject類別
    • Q_OBJECT巨集
    • Meta-Object Compiler(moc)

Qt管理的物件必須繼承QObject類別,以提供Qt物件的Meta訊息,若要實作Signal與Slot機制,則必須包括Q_OBJECT巨集,moc會處理Qt的C++擴充(Meta-Object System),使用moc讀取C++標頭檔案,若發現類別定義中包括Q_OBJECT巨集,就會產生Qt meta-object相關的C++程式碼。
若使用qmake來產生Makefile,若必要時,檔案中就會包括moc的使用,程式完成建置之後,會在release或debug目錄中,找到moc_Model.cpp,即為moc所提供的C++程式碼。


public slots:
void setValue(int);

signals:
void valueChanged(int);

在Model中,自訂了Signal與Slot,slots與signals關鍵字其實是巨集,將被展開為相關的程式碼。
Slot:定義setValue(int),將接收Signal傳來的整數資料,如果不想接受資料的話,int可以省去。
Signal:定義valueChanged(int),表示將發出的Signal會帶有一個整數。

Model.cpp
#include "Model.h"

void Model::setValue(int value) {
     if (value != m_value) {
         m_value = value;
         emit valueChanged(m_value);
     }
}

Slot只是一般的函式,可以由程式的其它部份直接呼叫,也可以連接至Signal,若有呼叫setValue(),程式執行到emit時,就會發出valueChanged()的Signal。

main.cpp
#include <QApplication>
#include <QWidget>
#include <QSlider>
#include <QLCDNumber>
#include "Model.h"

int main(int argc, char *argv[]) {
     QApplication app(argc, argv);

     QWidget *parent = new QWidget;
     parent->setWindowTitle("Signal & Slot");
     parent->setMinimumSize(240, 140);
     parent->setMaximumSize(240, 140);
          
     QLCDNumber *lcd = new QLCDNumber(parent);
     lcd->setGeometry(70, 20, 100, 30);
     
     QSlider *slider = new QSlider(Qt::Horizontal, parent);
     slider->setRange(0, 99);
     slider->setValue(0);
     slider->setGeometry(70, 70, 100, 30);
     
     Model model;
     
     QObject::connect(slider, SIGNAL(valueChanged(int)),
                      &model, SLOT(setValue(int)));
     QObject::connect(&model, SIGNAL(valueChanged(int)),
                      lcd, SLOT(display(int)));
     
     parent->show();
     
     return app.exec();
}

QObject::connect(slider, SIGNAL(valueChanged(int)), &model, SLOT(setValue(int)));

QObject::connect(&model, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)));

這邊使用connect()連接QSlider SIGNAL:valueChanged()及Model SLOT:setValue(),當拉動拉桿時,Model的m_value就會被設定為QSlider的游標值,Model在執行setValue()過程中會emit valueChanged() signal,由於Model SIGNAL:valueChanged()連接至QLCDNumber SLOT:display(),所以LCD顯示數字也會改變。


Signal與Slot的簽名(參數)基本上要相同,但若Signal的參數多於Slot的參數,則額外的參數會被Slot忽略。
如果要斷開Signal與Slot的連接,則使用disconnect(),例如:
QObject::disconnect(slider, SIGNAL(valueChanged(int)), &model, SLOT(setValue(int)));

本文參考自"良葛格:Qt4學習筆記"

0 意見: