一、建立一個基于 QWidget 的項目,不帶有界面設計器:
Qt學習筆記(二):信号和槽 二、在主視窗下添加兩個按鈕對象,連接配接按鈕發出的信号和槽函數:
mywidget.h:
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
// 引入按鈕頭檔案
#include <QPushButton>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0);
~MyWidget();
private:
// 聲明兩個按鈕對象
QPushButton b1; // 普通對象
QPushButton *b2; // 指針對象
};
#endif // MYWIDGET_H
mywidget.cpp:
#include "mywidget.h"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
// 通過 setParent 方法指定父對象
b1.setParent(this);
b1.setText("Button1");
b1.resize(80, 40);
b1.move(200, 100);
// 通過構造函數方法指定父對象
b2 = new QPushButton(this);
b2->setText("Button2");
b2->resize(80, 40);
b2->move(30, 20);
/*
* 連接配接信号和槽:點選按鈕的時候,關閉目前視窗
* 參數1:信号的發送者(指針類型)
* 參數2:發送的信号;&發送者的名字::信号名稱
* 參數3:信号的接收者(指針類型)
* 參數4:處理信号的函數(叫做槽函數);&接收者的名字::槽函數名稱
*/
connect(&b1, &QPushButton::clicked, this, &MyWidget::close);
// 連接配接信号和槽:按下按鈕的時候,目前視窗最大化顯示
connect(b2, &QPushButton::pressed, this, &MyWidget::showMaximized);
// 重置主視窗的大小
this->resize(600, 400);
}
MyWidget::~MyWidget()
{
}
其中信号 &QPushButton::clicked、&QPushButton::pressed,
和槽函數 &MyWidget::close、&MyWidget::showMaximized 都是 Qt 定義好的;
可以在 Qt 幫助文檔裡查找:
Qt學習筆記(二):信号和槽
Qt學習筆記(二):信号和槽 三、我們也可以自定義槽函數:
自定義槽函數的特點:槽函數的本質就是一個普通函數,在 Qt5 裡面,自定義槽函數可以是成員函數、普通全局函數、或者靜态函數都行;槽函數的傳回值和參數需要和信号一緻;
注意:信号和槽函數都沒有傳回值,但是可以帶參數;
在 mywidget.h 中聲明一個自定義的槽函數:
Qt學習筆記(二):信号和槽 在 mywidget.cpp 中連接配接信号和自定義槽函數:
注意:一個信号可以連接配接多個槽函數;
Qt學習筆記(二):信号和槽 四、自定義信号:
案例:添加一個子視窗,在主視窗上點選按鈕的時候,主視窗隐藏,子視窗顯示;
點選子視窗上的按鈕的時候,子視窗隐藏,主視窗顯示;
1、在 Qt 項目上添加子視窗:
Qt學習筆記(二):信号和槽
Qt學習筆記(二):信号和槽
Qt學習筆記(二):信号和槽 2、在子視窗頭檔案中添加自定義信号:
childwidget.h 檔案為:
#ifndef CHILDWIDGET_H
#define CHILDWIDGET_H
#include <QWidget>
#include <QPushButton>
class ChildWidget : public QWidget
{
Q_OBJECT
public:
explicit ChildWidget(QWidget *parent = 0);
signals:
// 自定義信号必須由 signals 關鍵字聲明;
// 自定義信号沒有傳回值,但可以有參數;
// 自定義信号就是函數的聲明,隻需聲明,無需定義;
// 發送資訊使用關鍵字 emit;
void mySignal();
public slots:
// Qt5 裡面自定義槽函數不是必須由 public slots 聲明;
// 但是 Qt4 裡面槽函數必須由 public slots 聲明;
void sendSignal();
private:
// 建立一個按鈕對象
QPushButton btn;
};
#endif // CHILDWIDGET_H
3、在子視窗中點選按鈕時,發送自定義信号:
childwidget.cpp 檔案為:
#include "childwidget.h"
ChildWidget::ChildWidget(QWidget *parent) :
QWidget(parent)
{
this->resize(400, 300); // 設定視窗大小
this->setWindowTitle("子視窗"); // 設定視窗标題
btn.setParent(this);
btn.setText("切換到主視窗");
btn.move(200, 100);
// 點選按鈕,調用自定義槽函數(sendSignal),發送自定義信号(mySignal)
connect(&btn, &QPushButton::clicked, this, &ChildWidget::sendSignal);
}
// 自定義槽函數
void ChildWidget::sendSignal()
{
// 發送自定義信号
emit mySignal();
}
4、在主視窗中添加子視窗對象,并自定義槽函數處理子視窗發出的信号:
修改 mywidget.h 檔案為:
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QPushButton>
// 在主視窗中引入子視窗的頭檔案
#include "childwidget.h"
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0);
~MyWidget();
// 自定義槽函數
void mySlot();
// 處理自定義信号的槽函數
void dealSignal();
private:
QPushButton b1;
// 在主視窗中聲明子視窗對象
ChildWidget child;
};
#endif // MYWIDGET_H
5、點選主視窗上的按鈕,隐藏主視窗,并顯示子視窗;
同時連接配接子視窗發出的信号和槽函數,當接收到信号時,顯示主視窗,隐藏子視窗:
修改 mywidget.cpp 檔案為:
#include "mywidget.h"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
this->resize(400, 300); // 設定視窗大小
this->setWindowTitle("主視窗"); // 設定視窗标題
b1.setParent(this);
b1.setText("切換到子視窗");
b1.move(200, 100);
// 點選按鈕,調用自定義槽函數(mySlot),隐藏主視窗,顯示子視窗
connect(&b1, &QPushButton::clicked, this, &MyWidget::mySlot);
// 連接配接子視窗的自定義信号和主視窗中的自定義槽函數
// 參數1:信号的發送者(子視窗)
// 參數2:發送的信号(子視窗自定義的信号)
// 參數3:信号的接收者(主視窗)
// 參數4:處理信号的自定義槽函數
connect(&child, &ChildWidget::mySignal, this, &MyWidget::dealSignal);
}
// 自定義槽函數
void MyWidget::mySlot()
{
// 隐藏主視窗
this->hide();
// 顯示子視窗
child.show();
}
// 處理信号的自定義槽函數
void MyWidget::dealSignal()
{
// 顯示主視窗
this->show();
// 隐藏子視窗
child.hide();
}
MyWidget::~MyWidget()
{
}
五、帶參數的自定義信号和自定義槽函數:
在上面案例的子視窗頭檔案(childwidget.h)中自定義一個帶參信号:
Qt學習筆記(二):信号和槽 并在子視窗上點選按鈕的時候,發送帶參信号:
Qt學習筆記(二):信号和槽 在主視窗頭檔案(mywidget.h)中自定義一個相對應的帶參槽函數:
Qt學習筆記(二):信号和槽 在主視窗中處理無參和有參的信号:
// 因為信号和槽函數都重載了,是以直接使用 connect 連接配接信号和槽的時候會報錯,
// 因為存在二義性,不确定調用的是無參的,還是有參的;
// 可以使用函數指針來解決:
// 無參數的信号和槽函數的函數指針:
void(ChildWidget::*noParamSignal)(void) = &ChildWidget::mySignal;
void(MyWidget::*noParamSlot)(void) = &MyWidget::dealSignal;
// 有參數的信号和槽函數的函數指針:
void(ChildWidget::*haveParamSignal)(int, QString) = &ChildWidget::mySignal;
void(MyWidget::*haveParamSlot)(int, QString) = &MyWidget::dealSignal;
// 連接配接無參數的自定義信号和無參數的槽函數
// 函數指針 noParamSignal 就表示無參的信号,
// 函數指針 noParamSlot 就表示無參的槽函數;
connect(&child, noParamSignal, this, noParamSlot);
// 連接配接帶參數的自定義信号和帶參數的槽函數
connect(&child, haveParamSignal, this, haveParamSlot);
測試結果如下:
Qt學習筆記(二):信号和槽 老師的視訊在示範的時候,qDebug() 輸出 QString 資料是中文時會出現亂碼,如下:
Qt學習筆記(二):信号和槽 但我的可以直接輸出中文;如果中文輸出亂碼,可以将 QString 類型轉換成 char* 類型:
Qt學習筆記(二):信号和槽 六、上面使用 函數指針 的方式差別無參和有參信号的方法是 Qt5 之後才有的,在 Qt4 的時候是另一種方法區分無參和有參的信号,如下:
// 連接配接無參的信号和無參的槽函數
connect(&child, SIGNAL(mySignal()), this, SLOT(dealSignal()));
// 連接配接有參的信号和有參的槽函數
connect(&child, SIGNAL(mySignal(int,QString)), this, SLOT(dealSignal(int,QString)));
Qt4 的這種方式用起來比較友善,但是有一個缺點:SIGNAL 和 SLOT 宏會将信号名稱和槽函數名稱轉換成字元串,在項目編譯的時候不進行錯誤檢查;也就是說信号名稱和槽函數名稱寫錯了,也可以編譯通過,但是程式會在運作的時候直接崩掉。