天天看點

qml 信号槽第二次才響應_2.3信号和槽(上)2.3.1 引子2.3.2 信号2.2.3 槽2.2.4連接配接信号和槽2.2.4.1 原型12.2.4.2 原型22.2.5 信号槽示例

如果面試官問你Qt最明顯差別于其它開發架構的特征是什麼,那麼你的回答一定是信号和槽,為此,小豆君将拿出三節的時間來講述信号和槽。

本節隻講解非線程間的信号槽,等後面學習的深入,再講解線程間信号槽通信。

第一節,信号槽的基本概念。

第二節,信号槽的擴充知識。

第三節,分析Qt的moc與編譯器生成的moc源檔案,幫助大家了解信号槽的來龍去脈。

2.3.1 引子

在面向對象的程式設計方法中,都會建立很多的執行個體,每個執行個體都是單獨的,要想每個執行個體能夠協同合作,那麼就會需要一種對象間傳遞消息的機制,在很多架構中都采用回調函數來進行對象間資訊傳遞。

回調是一個指向函數的指針,如果想要一個處理函數通知一些事件,你需要将這個指針傳遞給處理函數。處理函數在适當時間調用回調函數。MFC就是使用的回調函數,但回調可能是不直覺的,不易于了解的,并且也不能保證是類型安全的。

Qt為了消除回調函數等的弊端,進而開發了一種新的消息傳遞機制,即信号和槽。

例如,當我們要求滑鼠點選某個按鈕時,對應的視窗就需要關閉,那麼這個按鈕就會發出一個點選信号,而視窗接收到這個信号後執行關閉視窗。那麼,這個信号就是按鈕被點選,而槽就是視窗執行關閉函數。

可以将信号和槽了解成“指令-執行”,即信号就是指令,槽就是執行指令。

qml 信号槽第二次才響應_2.3信号和槽(上)2.3.1 引子2.3.2 信号2.2.3 槽2.2.4連接配接信号和槽2.2.4.1 原型12.2.4.2 原型22.2.5 信号槽示例

2.3.2 信号

當一個對象的内部狀态發生改變時,如果其它對象對它的狀态需要有所反應,這時就應該讓這個類發出狀态改變的信号。

聲明信号使用signals關鍵字

發送信号使用emit關鍵字

注意:

1.所有的信号聲明都是公共的,是以Qt規定不能在signals前面加public,private, protected。

2.所有的信号都沒有傳回值,是以傳回值都用void。

3.所有的信号都不需要定義。

4.必須直接或間接繼承自QOBject類,并且開頭私有聲明包含Q_OBJECT。

5.當一個信号發出時,會立即執行其槽函數,等待槽函數執行完畢後,才會執行後面的代碼,如果一個信号連結了多個槽,那麼會等所有的槽函數執行完畢後才執行後面的代碼,槽函數的執行順序是按照它們連結時的順序執行的。

6.在連結信号和槽時,可以設定連結方式為:在發出信号後,不需要等待槽函數執行完,而是直接執行後面的代碼。

7.發出信号使用emit關鍵字。

8.信号參數的個數不得少于槽參數的個數。

2.2.3 槽

槽其實就是普通的C++函數,它唯一特點就是能和信号連結。當和它連結的信号被發出時,這個槽就會被調用。

聲明槽可以使用:public/protected/private slots:

以上是Qt4的做法,在Qt5中你也不需要使用這些聲明,每個函數都可以被當作是槽函數,而且還可以使用Lambda表達式來作為槽。不過為了程式的可讀性,我還是推薦槽函數要聲明一下。

2.2.4連接配接信号和槽

使用connect函數連接配接信号和槽

2.2.4.1 原型1

static QMetaObject::Connection connect(    const QObject *sender, //信号發送對象指針    const char *signal,    //信号函數字元串,使用SIGNAL()    const QObject *receiver, //槽函數對象指針    const char *member, //槽函數字元串,使用SLOT()    Qt::ConnectionType = Qt::AutoConnection//連接配接類型,一般預設即可);//例如connect(pushButton, SIGNAL(clicked()), dialog,  SLOT(close()));
           

Qt4和Qt5都可以使用這種連接配接方式

2.2.4.2 原型2

static QMetaObject::Connection connect(    const QObject *sender, //信号發送對象指針    const QMetaMethod &signal,//信号函數位址    const QObject *receiver, //槽函數對象指針    const QMetaMethod &method,//槽函數位址    Qt::ConnectionType type = Qt::AutoConnection//連接配接類型,一般預設即可);//例如connect(pushButton, QPushButton::clicked, dialog,  QDialog::close);
           

Qt5新增這種連接配接方式,這使得在編譯期間就可以進行拼寫檢查,參數檢查,類型檢查,并且支援相容參數的相容性轉換。

2.2.5 信号槽示例

建立視窗項目SignalsAndSlotsWidget,類名同為SignalsAndSlotsWidget,基類選擇QWidget。

在ui中拖入1個QLineEdit,1個QLable,1個QSlider,如下圖

qml 信号槽第二次才響應_2.3信号和槽(上)2.3.1 引子2.3.2 信号2.2.3 槽2.2.4連接配接信号和槽2.2.4.1 原型12.2.4.2 原型22.2.5 信号槽示例

頭檔案

class SignalsAndSlotsWidget : public QWidget{    Q_OBJECTpublic:    explicit SignalsAndSlotsWidget(QWidget *parent = 0);    ~SignalsAndSlotsWidget();signals:    //自定義信号,發出此信号,使得QLabel顯示文字    void sigShowVal(const QString&);public slots:    //自定義槽,當LineEdit發出文字改變的信号時,執行這個槽    void sltLineEditChanged(const QString& text);private:    Ui::SignalsAndSlotsWidget *ui;};
           

源檔案

SignalsAndSlotsWidget::SignalsAndSlotsWidget(QWidget *parent) :    QWidget(parent),    ui(new Ui::SignalsAndSlotsWidget){    ui->setupUi(this);    int max = 100;    int min = 0;    ui->horizontalSlider->setMaximum(max);//設定最大最小值    ui->horizontalSlider->setMinimum(min);    //設定QLineEdit隻能輸入數字,且為0-100    QIntValidator* validator = new QIntValidator(min, max, this);    ui->lineEdit->setValidator(validator);    connect(ui->lineEdit,             &QLineEdit::textChanged,             this,              &SignalsAndSlotsWidget::sltLineEditChanged);    connect(this,            SIGNAL(sigShowVal(QString)),            ui->label,            SLOT(setText(QString)));}SignalsAndSlotsWidget::~SignalsAndSlotsWidget(){    delete ui;}void SignalsAndSlotsWidget::sltLineEditChanged(const QString &text){    int val = text.toInt();    ui->horizontalSlider->setValue(val);//設定slider目前值    emit sigShowVal(text);//通知label顯示文字}
           

運作程式,在輸入框中輸入0-100,看看有什麼變化。

好了,今天就到這裡,我們下期再見。