/*******************************************************************************************/c++
1、指定父對象數組
/*若是不指定父對象,對象和對象(窗口和窗口)沒有關係,獨立app
* a指定b爲它的父對象,a放在b的上面框架
* 指定父對象,有2種方式:ide
* 1)setParent函數
* 2)經過構造函數傳參this
* 指定父對象,只須要父對象顯示,上面的子對象自動顯示,不須要再去手動去show子對象了spa
*/指針
1)setParentcode
QPushButton b;
b.setText("^_^"); //給按鈕設置內容,
b.setParent(&w); //指定父對象,若是不指定父對象,這裏直接show,那麼顯示的是兩個獨立的窗口
b.move(100, 100); //移動座標,以像素點爲單位,以左上角爲基準點,若是沒有移動,默認位置是在左上角
2)經過構造函數傳參
QPushButton b1(&w); //經過構造函數傳參
b1.setText("abc");
w.show();
//窗口也是一種控件,按鈕也是一種控件,因此這種繼承關係就致使了一種叫法,窗口是父對象,同時也是父控件,父對象,
//對應,按鈕是子對象,同時也是子控件,子窗口
/*******************************************************************************************/
2、標準信號和槽
正常新建工程都是選擇application模版中的qt widgets application
一樣須要去掉建立界面的勾選框,繼承Qwidget類
1.信號和槽的介紹
信號槽是 Qt 框架引覺得豪的機制之一。所謂信號槽,實際就是觀察者模式。當某個事件發生以後,好比,
按鈕檢測到本身被點擊了一下,它就會發出一個信號(signal)。這種發出是沒有目的的,相似廣播。
若是有對象對這個信號感興趣,它就會使用鏈接(connect)函數,意思是,
將想要處理的信號和本身的一個函數(稱爲槽(slot))綁定來處理這個信號。也就是說,當信號發出時,被鏈接的槽函數會自動被回調。
這就相似觀察者模式:當發生了感興趣的事件,某一個操做就會被自動觸發。(這裏提一句,Qt 的信號槽使用了額外的處理來實現,
並非 GoF 經典的觀察者模式的實現方式。)
2.信號的含義
所謂信號,就是點擊按鈕或其餘控件後,會產生軟中斷,產生後會廣播發送出信號,若是有誰感興趣的就會去處理這個信號,
那麼如何才能表示感興趣,就是要創建鏈接關係,那麼這個信號發生的時候,就會自動的調用所鏈接的函數
也就是說若是對某信號感興趣,就要有函數和這個信號創建聯繫,那麼這個信號發生的時候,這個函數就會被調用
3.信號相關的函數
創建鏈接關係函數:
connect(&b1, &QPushButton::pressed, this, &MainWidget::close);
第一個參數是發出信號的控件地址,
第二參數表示的是這個控件發出的是哪一個信號,具體這個信號填什麼須要看幫助文檔,
即光標放在按鈕類名上按f1就能夠出現幫助文檔,再f1全屏,在其中找是否有signal或者再到其父類中找signal
第三個參數是信號的接收者,表示的是誰來接收這個信號,也就是誰感興趣,即信號的處理函數所屬於的類的對象,
當接收者接收到對應的信號(第二個參數)就會自動去調用信號的處理函數,即第四個參數
第四個參數是該信號的處理函數(槽函數),也就是接收到信號要調用的函數,這個函數是第三個參數的成員函數
/* &b1: 信號發出者,指針類型
* &QPushButton::pressed:處理的信號, &發送者的類名::信號名字
* this: 信號接收者
* &MainWidget::close: 槽函數,信號處理函數 &接收的類名::槽函數名字
*/
在成員函數上按f1也會有對應的幫助文檔,在幫助文檔中能夠看到MainWidget::close函數標註了是槽函數,也就是
QPushButton::pressed是標準的信號,MainWidget::close是標準的槽函數。
/*******************************************************************************************/
3、自定義槽函數
/* 自定義槽,就是普通函數的用法
* Qt5中,自定義槽能夠是:任意的成員函數,普通全局函數,靜態函數
* 槽函數須要和信號一致(指的是參數,返回值一致),因此
* 因爲信號都是沒有返回值,因此,槽函數必定沒有返回值
*/
connect(b2, &QPushButton::released, this, &MainWidget::mySlot);
//一個信號能夠有多個處理 /* 能夠打比喻,信號:短信 槽函數:接收短信的手機,一條短信能夠發給多個手機*/
connect(b2, &QPushButton::released, &b1, &QPushButton::hide);
/*******************************************************************************************/
4、兩個獨立的窗口
添加新的窗口,就須要添加一個新的類,添加的方法是選擇添加c++ class 具體見圖1:
/*******************************************************************************************/
5、自定義信號
1.自定義信號
//(自)定義信號要在signals關鍵字後面,signals是qt特有的關鍵字,編譯的時候qt會把它轉換到g++能夠編譯的
signals:
/* 信號必須有signals關鍵字來聲明
* 信號沒有返回值,但能夠有參數
* 信號就是函數的聲明,只需聲明,無需定義
* 使用:emit mySignal();,即發送信號使用emit關鍵字
* 信號能夠重載
*/
void mySignal();
void mySignal(int, QString);
2.發送信號
//發送信號使用emit關鍵字
connect(&b, &QPushButton::clicked, this, &SubWidget::sendSlot);//把信號與信號對應的處理函數(槽函數)創建起鏈接關係
resize(400, 300);//若是不resize,則每次切換的時候窗口大小會變
void SubWidget::sendSlot()
{
emit mySignal();
emit mySignal(250, "我是子窗口");
}
//處理子窗口的信號
connect(&w, &SubWidget::mySignal, this, &MainWidget::dealSub);
resize(400, 300);//若是不resize,則每次切換的時候窗口大小會變
3.注意
qt中用別人的代碼時候,注意要去掉.user文件,不然可能編譯不過
對話框的特色是不能伸縮的,只有一個x按鈕
信號與槽:是qt對象之間通訊的接口
/*******************************************************************************************/
6、帶參數的信號
1.定義帶參數的信號
signals:
/* 信號必須有signals關鍵字來聲明
* 信號沒有返回值,但能夠有參數
* 信號就是函數的聲明,只需聲明,無需定義
* 使用:emit mySignal();
* 信號能夠重載
*/
void mySignal();
void mySignal(int, QString);
2.發送帶參數的信號
void SubWidget::sendSlot()
{
emit mySignal();
emit mySignal(250, "我是子窗口");
}
3.信號的重載
1).qt5的處理方法
//當信號出現重載,爲了區分具體是屬於哪個,就須要用到函數指針,定義函數指針等於具體哪個信號。一樣若是槽函數重載也得這麼轉換
void (SubWidget::*funSignal)() = &SubWidget::mySignal;
connect(&subWin, funSignal, this, &MainWidget::dealSub);
void (SubWidget::*testSignal)(int, QString) = &SubWidget::mySignal;
connect(&subWin, testSignal, this, &MainWidget::dealSlot);
2).qt4的處理方法
//還有另一種更方便的方法,只不過容易出問題,也就是接下來要說的:Qt4信號鏈接。實現功能是同樣的
//Qt4信號鏈接使用宏:SIGNAL。Qt4槽函數必須有slots關鍵字來修飾,而後再使用宏SLOT
connect(&subWin, SIGNAL(mySignal()), this, SLOT(dealSub()) );
connect(&subWin, SIGNAL(mySignal(int,QString)),
this, SLOT(dealSlot(int,QString)) );
// 容易出錯的地方:SIGNAL SLOT 將函數名字 -> 字符串 不進行錯誤檢查。即寫錯了信號名字等,編譯的時候不報錯。因此儘量不用這種qt4的方式
//Qt4槽函數必需要有的關鍵字
public slots:
void mySlot();
void changeWin();
void dealSub();
void dealSlot(int, QString);
void MainWidget::dealSlot(int a, QString str)
{
// str.toUtf8() -> 字節數組QByteArray
// ……data() -> QByteArray -> char *
qDebug() << a << str.toUtf8().data();//qDebug qt中的打印,相似cout,必須#include <QDebug>
}
4.信號槽的更多用法
1).一個信號能夠和多個槽相連
若是是這種狀況,這些槽會一個接一個的被調用,可是它們的調用順序是不肯定的。
2).多個信號能夠鏈接到一個槽
只要任意一個信號發出,這個槽就會被調用。
3).一個信號能夠鏈接到另外的一個信號
當第一個信號發出時,第二個信號被髮出。除此以外,這種信號-信號的形式和信號-槽的形式沒有什麼區別。
4).槽能夠被取消連接
這種狀況並不常常出現,由於當一個對象delete以後,Qt自動取消全部鏈接到這個對象上面的槽。
具體見圖2,3
/*******************************************************************************************/
7、LamDa表達式和再說信號的功能
//Lambda表達式(匿名函數對象)
//C++11增長的新特性, 由於是新增長的因此須要在項目文件(.pro文件): CONFIG += C++11
//在Qt中,配合信號一塊兒使用,很是方便。方便在不用定義槽函數,不用指定接收者
1.Lambda表達式(匿名函數對象)
Lambda表達式:
[]()
{
}
//相似於函數只不過沒有函數名與返回值,而後多了個[],表示函數的開始
//其中[]內部能夠放Lambda表達式外面的變量,這樣Lambda表達式裏的函數體內纔可使用,例如:
QPushButton *b4 = new QPushButton(this);
int a = 10, b = 100;
[b4,a,b]()
{//這樣內部纔可使用b4,a,b,不過對於{}內部來講是隻讀的,{}內部不能修改這些變量
}
//若是要把外部全部局部變量、類中全部成員都以值傳遞方式(傳遞進來是隻讀的,表達式內不能修改,除非
在()後面加關鍵字mutable : [=]() mutable{})傳遞到Lambda表達式裏的函數體內,則在[]中加入等號=
//若是要把類中全部成員以值傳遞方式傳遞到Lambda表達式裏的函數體內,則在[]中加入this
//若是要把外部全部局部變量傳遞到Lambda表達式裏的函數體內,則在[]中加入引用符號& 。
注意&儘可能少用,以下:
int a = 10, b = 100;
connect(b4, &QPushButton::clicked,
[&]()
{
qDebug() << a<< b;//內存還沒釋放(a,b,b4之類的內存還在使用,可能相互影響),引用的內存不是局部變量的,就會出錯
a=11;
}
);
2.Lambda表達式在信號中的使用
Lambda表達式直接代替掉接收者和槽函數,信號產生後,直接執行Lambda表達式
若是信號有參數的情形:
//clicked 信號有參數 bool checked =false,即點擊後值變爲false
connect(b4, &QPushButton::clicked,
// = :把外部全部局部變量、類中全部成員以值傳遞方式
// this: 類中全部成員以值傳遞方式
// & : 把外部全部局部變量, 引用符號
[=](bool isCheck)
{
qDebug() << isCheck;//這樣就接收到了信號發出的參數
}
);
根據前面信號與槽的實現,點擊按鈕後窗口發生變化,窗口發生變化是按鈕觸發的,可是實質上
按鈕只是發送了信號,而後槽函數被調用,真正引發的變化是槽函數作的,也就是成員函數作的。
一樣點擊按鈕切換窗口時,按鈕只是觸發了軟中斷讓槽函數被調用,而後是槽函數裏面發出了信號。
也就是說具體作什麼事情由槽函數決定
信號與槽相關的代碼,具體見《SignalAndSlot》:
1 #ifndef MAINWIDGET_H 2 #define MAINWIDGET_H 3 4 #include <QWidget> 5 #include <QPushButton> 6 #include "subwidget.h" //子窗口頭文件 7 8 class MainWidget : public QWidget 9 { 10 Q_OBJECT 11 12 public: 13 MainWidget(QWidget *parent = 0); 14 ~MainWidget(); 15 16 public slots: 17 void mySlot(); 18 void changeWin(); 19 void dealSub(); 20 void dealSlot(int, QString); 21 22 private: 23 QPushButton b1; 24 QPushButton *b2; 25 QPushButton b3; 26 27 SubWidget subWin; 28 }; 29 30 #endif // MAINWIDGET_H
1 #include "mainwidget.h" 2 #include <QPushButton> 3 #include <QDebug> //打印 4 5 MainWidget::MainWidget(QWidget *parent) 6 : QWidget(parent) 7 { 8 b1.setParent(this); 9 b1.setText("close"); 10 b1.move(100, 100); 11 12 b2 = new QPushButton(this); 13 b2->setText("abc"); 14 15 connect(&b1, &QPushButton::pressed, this, &MainWidget::close); 16 /* &b1: 信號發出者,指針類型 17 * &QPushButton::pressed:處理的信號, &發送者的類名::信號名字 18 * this: 信號接收者 19 * &MainWidget::close: 槽函數,信號處理函數 &接收的類名::槽函數名字 20 */ 21 22 /* 自定義槽,普通函數的用法 23 * Qt5:任意的成員函數,普通全局函數,靜態函數 24 * 槽函數須要和信號一致(參數,返回值) 25 * 因爲信號都是沒有返回值,因此,槽函數必定沒有返回值 26 */ 27 connect(b2, &QPushButton::released, this, &MainWidget::mySlot); 28 29 connect(b2, &QPushButton::released, &b1, &QPushButton::hide); 30 31 /* 信號:短信 32 * 槽函數:接收短信的手機 33 */ 34 35 setWindowTitle("老大"); 36 //this->setWindowTitle("老大"); 37 38 b3.setParent(this); 39 b3.setText("切換到子窗口"); 40 b3.move(50, 50); 41 42 //顯示子窗口 43 //subWin.show(); 44 45 connect(&b3, &QPushButton::released, this, &MainWidget::changeWin); 46 47 48 //處理子窗口的信號 49 // void (SubWidget::*funSignal)() = &SubWidget::mySignal; 50 // connect(&subWin, funSignal, this, &MainWidget::dealSub); 51 52 // void (SubWidget::*testSignal)(int, QString) = &SubWidget::mySignal; 53 // connect(&subWin, testSignal, this, &MainWidget::dealSlot); 54 55 //Qt4信號鏈接 56 //Qt4槽函數必須有slots關鍵字來修飾 57 connect(&subWin, SIGNAL(mySignal()), this, SLOT(dealSub()) ); 58 59 connect(&subWin, SIGNAL(mySignal(int,QString)), 60 this, SLOT(dealSlot(int,QString)) ); 61 // SIGNAL SLOT 將函數名字 -> 字符串 不進行錯誤檢查 62 63 //Lambda表達式, 匿名函數對象 64 //C++11增長的新特性, 項目文件: CONFIG += C++11 65 //Qt配合信號一塊兒使用,很是方便 66 67 QPushButton *b4 = new QPushButton(this); 68 b4->setText("Lambda表達式"); 69 b4->move(150, 150); 70 int a = 10, b = 100; 71 connect(b4, &QPushButton::clicked, 72 // = :把外部全部局部變量、類中全部成員以值傳遞方式 73 // this: 類中全部成員以值傳遞方式 74 // & : 把外部全部局部變量, 引用符號 75 [=](bool isCheck) 76 { 77 qDebug() << isCheck; 78 } 79 80 81 ); 82 83 84 resize(400, 300); 85 } 86 87 void MainWidget::dealSlot(int a, QString str) 88 { 89 // str.toUtf8() -> 字節數組QByteArray 90 // ……data() -> QByteArray -> char * 91 qDebug() << a << str.toUtf8().data(); 92 } 93 94 void MainWidget::mySlot() 95 { 96 b2->setText("123"); 97 } 98 99 void MainWidget::changeWin() 100 { 101 //子窗口顯示 102 subWin.show(); 103 //本窗口隱藏 104 this->hide(); 105 } 106 107 108 void MainWidget::dealSub() 109 { 110 //子窗口隱藏 111 subWin.hide(); 112 //本窗口顯示 113 show(); 114 } 115 116 MainWidget::~MainWidget() 117 { 118 119 }
1 #ifndef SUBWIDGET_H 2 #define SUBWIDGET_H 3 4 #include <QWidget> 5 #include <QPushButton> 6 7 class SubWidget : public QWidget 8 { 9 Q_OBJECT 10 public: 11 explicit SubWidget(QWidget *parent = 0); 12 13 void sendSlot(); 14 15 signals: 16 /* 信號必須有signals關鍵字來聲明 17 * 信號沒有返回值,但能夠有參數 18 * 信號就是函數的聲明,只需聲明,無需定義 19 * 使用:emit mySignal(); 20 * 信號能夠重載 21 */ 22 23 void mySignal(); 24 void mySignal(int, QString); 25 26 public slots: 27 28 private: 29 QPushButton b; 30 }; 31 32 #endif // SUBWIDGET_H
1 #include "subwidget.h" 2 3 SubWidget::SubWidget(QWidget *parent) : QWidget(parent) 4 { 5 this->setWindowTitle("小弟"); 6 b.setParent(this); 7 b.setText("切換到主窗口"); 8 9 connect(&b, &QPushButton::clicked, this, &SubWidget::sendSlot); 10 11 resize(400, 300); 12 } 13 14 void SubWidget::sendSlot() 15 { 16 emit mySignal(); 17 emit mySignal(250, "我是子窗口"); 18 }