信號和槽
信號槽和機制
情景帶人:
我們都知道鴻門宴,其中項羽想要殺劉邦,就在洪門設宴,並和手下兄弟約定只要項羽摔杯,就從進去綁了劉邦;
建立:信號和槽函數的關係使用connect
connect(信號的發起者,信號,接受者,操作);
案例:
widget的構造函數中:
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//設置窗口標題
this->setWindowTitle("信號");
//設置窗口大小
this->resize(800,600);
//創建一個按鈕
QPushButton *btn1=new QPushButton("關閉",this);
//需求:單擊btn1 關閉主窗口
//信號的發起者btn1 發出信號 主窗口this 關閉(槽函數)
connect(btn1, &QPushButton::clicked, this, &QWidget::close);
//lambda表達式
QPushButton *btn2 =new QPushButton("戳我呀",this);
btn2->move(400,300);
connect(btn2, &QPushButton::clicked, [=](){
//獲取按鈕上的文本
QString text = btn2->text();
qDebug()<<text <<endl;
//設置按鈕的文本
btn2->setText("戳你咋地?");
} );
}
運行結果:
自定義信號和槽(瞭解)
老師—>餓了信號 學生—>請老師喫飯
設計兩個類:老師類 學生類
注意:
1、定義信號的規則:在signals下方返回值類型爲void 只需聲明 不用實現 可以有參數 可以重載
2、定義槽函數的規則:public slots:返回值類型爲void 需要聲明 需要實現 可以有參數 可以重載
3、用戶可以使用emit 發出信號
emit tea->hungry();
案例:
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = 0);
signals:
public slots:
//返回值類型爲void 需要聲明 需要實現 可以有參數 可以重載
void treat();
void treat(QString foodName);
};
#endif // STUDENT_H
student.cpp
#include "student.h"
#include<QDebug>
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::treat()
{
qDebug()<<"請老師喫飯了"<<endl;
}
void Student::treat(QString foodName)
{
qDebug()<<"請老師喫飯了"<<foodName<<endl;
}
teacher.h
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
#include<QString>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = 0);
signals://自定義信號函數
//定義信號的規則:返回值類型void 只需聲明 不用實現 可以有參數 可以重載
void hungry();
void hungry(QString foodName);
public slots://自定義槽函數
};
#endif // TEACHER_H
teacher.cpp
#include "teacher.h"
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
widget構造函數:
#include "widget.h"
#include"teacher.h"
#include"student.h"
#include<QPushButton>
#define N 0
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//設置主窗口大小
this->resize(800,600);
//實例化一個老師
Teacher *tea = new Teacher(this);
//實例化一個學生
Student *stu = new Student(this);
#if N
//connect建立老師和學生的關係
void (Teacher:: *p1)() = &Teacher::hungry;
void (Student:: *p2)() = &Student::treat;
connect(tea,p1, stu, p2);
#else
//報錯的原因:hungry信號被重載了
//通過函數指針 明確那個信號
void (Teacher:: *p1)(QString foodName) = &Teacher::hungry;
void (Student:: *p2)(QString foodName) = &Student::treat;
connect(tea,p1, stu, p2);
#endif
//下課了 老師餓了
QPushButton *btn = new QPushButton("下課", this);
connect(btn,&QPushButton::clicked,[=](){
#if N
//下課函數:讓老師發出餓的信號
emit tea->hungry();
#else
//下課函數:讓老師發出餓的信號
emit tea->hungry("鍋包肉");
#endif
});
}
Widget::~Widget()
{
}
總結:
1、一個信號可以和多個槽相連
如果是這種情況,這些槽會一個接一個的被調用,但是它們的調用順序是不確定的。
2、多個信號可以連接到一個槽
只要任意一個信號發出,這個槽就會被調用。
3、一個信號可以連接到另外的一個信號
當第一個信號發出時,第二個信號被髮出。除此之外,這種信號-信號的形式和信號-槽的形式沒有什麼區別。
4、槽可以被取消鏈接
這種情況並不經常出現,因爲當一個對象delete之後,Qt自動取消所有連接到這個對象上面的槽。
5、Qt4版本的信號槽寫法
connect(tea,SIGNAL(hungry()), stu, SLOT(treat()));
6、Qt5版本的信號槽寫法
connect(tea, &Teacher::hungry, stu, &Student::treat);
綜合案例(窗口切換)
創建一個窗口類:
類名爲:swidget
swidget.h
#ifndef SWIDGET_H
#define SWIDGET_H
#include <QWidget>
class SWidget : public QWidget
{
Q_OBJECT
public:
explicit SWidget(QWidget *parent = 0);
signals:
void back();//回退信號
public slots:
};
#endif // SWIDGET_H
swidget.cpp
#include "swidget.h"
#include<QPushButton>
SWidget::SWidget(QWidget *parent) : QWidget(parent)
{
//設置查詢窗口的大小
this->resize(800,600);
this->setWindowTitle("查詢窗口");
//定義一個回退按鈕
QPushButton *btn = new QPushButton("back",this);
//當按下back 就發出一個back信號
connect(btn,&QPushButton::clicked,[=](){
emit this->back();
});
}
widget.cpp
#include "widget.h"
#include <QPushButton>
#include"swidget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->resize(800,600);
this->setWindowTitle("登錄");
//定義一個查詢窗口
SWidget *s = new SWidget();
//創建一個下一頁的按鈕
QPushButton *btn = new QPushButton("下一頁",this);
connect(btn,&QPushButton::clicked,[=](){
//當前窗口隱藏
this->hide();
//查詢窗口顯示
s->show();
});
//監測查詢窗口s的回退信號
connect(s,&SWidget::back,[=](){
//隱藏查詢窗口
s->hide();
//顯示當前窗口
this->show();
});
}
Widget::~Widget()
{
}
運行結果: