QT - 窗口属性、信号槽机制
1. 设置窗口属性
窗口设置
1,标题
2,大小
3,固定大小
4,设置图标
在 widget.cpp
文件中:
//设置窗口大小,此时窗口是可以拉大拉小的
//1参:宽度
//2参:高度
this->resize(800, 600);
//设置窗口标题
this->setWindowTitle("QT第一个窗口界面");
//设置窗口大小不可改变
this->setFixedSize(800, 600);
//设置图标
//this->setWindowIcon();
2. 按钮 QPushButton
构造函数
QPushButton(父容器)
设置文本
setText
获取文本
text
设置大小
resize
移动
move
2.1 方式一:代码创建
在 widget.cpp
文件中:
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton> //1、引入按钮所需头文件
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
ui->setupUi(this);
//设置窗口大小,此时窗口是可以拉大拉小的
//1参:宽度
//2参:高度
this->resize(800, 600);
//设置窗口标题
this->setWindowTitle("QT第一个窗口界面");
//设置窗口大小不可改变
this->setFixedSize(800, 600);
//2、创建按钮对象
QPushButton *btn01 = new QPushButton;
//3、设置按钮父容器,此处是当前窗口
btn01->setParent(this);
//3.1 设置按钮大小
//btn01->setFixedSize(300,50);
//4、设置位置
btn01->move(100, 100);
//5、设置按钮文本
btn01->setText("按钮");
}
Widget::~Widget()
{
delete ui;
}
2.2 方式二:图形界面
3. 信号与槽机制
//Qt4:
connect(btn, SIGNAL(clicked(bool)), this, SLOT( close() ) );
//Qt5:
connect(btn, &QPushButton::clicked, this, &QWidget::close );
3.1 概述
信号槽是 Qt 框架引以为豪的机制之一。
所谓信号槽,实际就是 观察者模式
。
- 当某个事件发生之后,比如,按钮检测到自己被点击了一下, 它就会发出一个信号( signal) 。这种发出是没有目的的,类似广播。 如果有对象对这个信号感兴趣,它就会使用连接( connect)函数,意思是, 将想要处理的信号和自己的一个函数(称为槽( slot))绑定来处理这个信号。
- 也就是说, 当信号发出时, 被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。
注意:
- 核心在于 发送者 与 接受者
- 发送者 可以
发出多种信号
,被多个不同的接收者接收
- 接收者
有多个槽函数
,接收不同
的发送者发出的信号
3.2 信号与槽的链接
connect()
函数
connect(sender, signal, receiver, slot)
参数:
- sender:发送者
- signal:发出的信号
- receiver:接受者
- slot:槽函数
示例1:
//ui文件中名为btnclose的按钮发出点击信号
//被当前窗口接收,执行关闭窗口的操作
//qt5的写法
connect(ui->btnclose,&QPushButton::clicked,this,&Widget::close);
//qt4的写法
//connect(ui->btnclose,SIGNAL(clicked(bool)),this,SLOT(close()));
示例2:
//信号与槽函数有参数
//qt5的写法
//void (QPushButton:: *cli_p)(bool) = &QPushButton::clicked;
//void (Widget:: *myfun_p)(bool) = &Widget::myfun;
//connect(ui->btnclose,cli_p,this,myfun_p);
//qt4的写法
connect(ui->btnclose,SIGNAL(clicked(bool)),this,SLOT(myfun(bool)));
3.3 系统提供的信号与槽
3.3.1 QWidget提供
信号:
void customContextMenuRequested(const QPoint &pos) //请求上下文菜单时
void windowIconChanged(const QIcon &icon) //窗口图标改变时
void windowTitleChanged(const QString &title) //窗口标题改变时
槽:
bool close() // 关闭
void hide() // 隐藏
void lower()
void raise()
void repaint() // 重新加载
void setDisabled(bool disable)
void setEnabled(bool)
void setFocus()
void setHidden(bool hidden)
void setStyleSheet(const QString &styleSheet)
virtual void setVisible(bool visible)
void setWindowModified(bool)
void setWindowTitle(const QString &)
void show() // 显示
void showFullScreen() // 全屏显示
void showMaximized() // 最大化显示
void showMinimized() // 最小化显示
void showNormal()
void update()
3.3.2 QPushButton提供
继承于父类的 QAbstractButton的信号
信号:
void clicked(bool checked = false) //点击信号
void pressed() //按钮按下信号 (按下)
void released() //按钮释放信号(抬起)
void toggled(bool checked) //触发(开或关)
3.3.3 示例
如1: 当前窗口添加一个关闭按钮,点击之后关闭窗口(退出程序)
#include "widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(800, 640);
QPushButton *btn= new QPushButton("关闭", this);
btn->setFixedSize(120, 50);
btn->move(10, 10);
// 当前类对象对 QPushButton的点击事件感兴趣
// 使用connect()进行绑定到当前窗口的close()
// 发送者和接收者都是QObject类的对象的指针
// Qt5的信号绑定槽函数的方式
connect(btn, &QPushButton::clicked, this, &Widget::close);
}
如2:当前窗口中添加一个按钮,当按下时最大化显示窗口,再点时,恢复之前的状态
#include "widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(800, 640); // 窗口的初始大小
// setMaximumSize(1200, 960); // 设置窗口最大值
QPushButton *btn= new QPushButton("关闭", this);
btn->setFixedSize(120, 50);
btn->move(10, 10);
// 当前类对象对 QPushButton的点击事件感兴趣
// 使用connect()进行绑定到当前窗口的close()
// 发送者和接收者都是QObject类的对象的指针
// Qt5的信号绑定槽函数的方式
connect(btn, &QPushButton::clicked, this, &Widget::close);
QPushButton *maxBtn = new QPushButton("最大化", this);
maxBtn->setFixedSize(120, 50);
maxBtn->move(10, 70);
// 绑定的槽函数是自定义的成员函数
connect(maxBtn, &QPushButton::clicked, this, &Widget::toggleShow);
}
// 在public区域声明的函数 toggleShow()
void Widget::toggleShow(){
// qDebug()引入 <QDebug> 头
qDebug() << "show or hide:" << this->isMaximized() << endl;
if(isMaximized()){
showNormal(); // 槽函数可以作为成员函数使用
}else{
showMaximized();
}
}
3.4 自定义信号与槽
3.4.1 注意事项
- 发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外)
- 信号和槽函数
返回值类型是 void
信号
只需要声明,不需要实现槽函数
需要声明也需要实现- 槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected的影响;
- 使用
emit
在恰当的位置发送信号;- 使用
connect()
函数 连接信号和槽。- 任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数
- 信号槽要求信号和槽的
参数一致
,所谓一致,是 参数类型一致。- 如果信号和槽的参数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少)。
3.4.2 无参
下课了,老师饿了,学生请吃饭
widget.h
没变化
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "teacher.h"
#include "student.h"
#include <QPushButton>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->resize(800, 600);
this->setFixedSize(800, 600);
this->setWindowTitle("老师饿了,学生请吃饭");
QPushButton *btn = new QPushButton;
btn->setParent(this);
btn->move(100, 100);
btn->setText("下课");
//创建学生和老师对象
Teacher *tea = new Teacher();
Student *stu = new Student();
//关联1:按钮和老师对象,
//按钮:发送者; clicked:发出的信号; tea:接收者; down:槽函数
connect(btn, QPushButton::clicked, tea, Teacher::down);
//关联2:老师和学生对象,
//tea:发送者; hungry:发出的信号; stu:接收者; eat:槽函数
connect(tea, Teacher::hungry, stu, Student::eat);
}
Widget::~Widget()
{
delete ui;
}
新建 teacher.h
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = 0);
signals:
//信号
void hungry();
public slots:
//槽函数
void down();
};
#endif // TEACHER_H
新建 teacher.cpp
#include "teacher.h"
#include <QDebug>
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
void Teacher::down()
{
//发送信号
emit this->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 eat();
};
#endif // STUDENT_H
新建 student.cpp
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::eat()
{
qDebug() << endl << "请吃饭" << endl;
}
3.4.3 有参
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "teacher.h"
#include "student.h"
#include <QPushButton>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->resize(800, 600);
this->setFixedSize(800, 600);
this->setWindowTitle("老师饿了,学生请吃饭");
QPushButton *btn = new QPushButton;
btn->setParent(this);
btn->move(100, 100);
btn->setText("下课");
Teacher *tea = new Teacher();
Student *stu = new Student();
//关联1:按钮和老师对象,
//按钮:发送者; clicked:发出的信号; tea:接收者; down:槽函数
connect(btn, QPushButton::clicked, tea, Teacher::down);
//关联2:老师和学生对象,
//tea:发送者; hungry:发出的信号; stu:接收者; eat:槽函数
// connect(tea, Teacher::hungry, stu, Student::eat01);
connect(tea, Teacher::hungry, stu, Student::eat02);
//槽的参数只能小于等于信号的参数,eat03报错
connect(tea, Teacher::hungry, stu, Student::eat03);
}
Widget::~Widget()
{
delete ui;
}
新建 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 hungry(int num, QString foodName);
public slots:
void down();
};
#endif // TEACHER_H
新建 teacher.cpp
#include "teacher.h"
#include <QDebug>
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
void Teacher::down()
{
emit this->hungry(3, "油泼面");
}
新建 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 eat01();
//大于信号参数
void eat02(int num, QString foodName);
//大于信号参数
void eat03(int num, int x, QString foodName);
};
#endif // STUDENT_H
新建 student.cpp
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::eat01()
{
qDebug() << endl << "eat01" << endl;
}
void Student::eat02(int num, QString foodName)
{
qDebug() << endl << "eat02:\tnum:" << num << "\tfoodName:" << foodName << endl;
}
void Student::eat03(int num, int x, QString foodName)
{
qDebug() << endl << "eat03" << endl;
}
3.5 信号与槽拓展
3.5.1 一个信号可以和多个槽相连
槽会一个接一个的被调用,但是它们的调用顺序是不确定
3.5.2 多个信号可以连接到一个槽
只要任意一个信号发出,这个槽就会被调用
3.5.3 一个信号可以连接到另外的一个信号
当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。
3.5.4 信号槽可以断开
利用 disconnect 关键字是可以断开信号槽的
3.5.5 槽可以被取消链接
这种情况并不经常出现,因为当一个对象 delete 之后,Qt 自动取消所有连接到这个对象上面的槽
3.5.6 示例
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
public slots:
void myslot01();
void myslot02();
void myslot03();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
setWindowTitle("信号与槽的拓展");
setFixedSize(800,600);
QPushButton *btn01 = new QPushButton("一个信号连接多个槽",this);
btn01->resize(300,50);
connect(btn01,QPushButton::clicked,this,Widget::myslot01);
connect(btn01,QPushButton::clicked,this,Widget::myslot02);
connect(btn01,QPushButton::clicked,this,Widget::myslot03);
QPushButton *btn02 = new QPushButton("多个信号连接一个槽",this);
btn02->resize(300,50);
btn02->move(0,50);
connect(btn02,QPushButton::clicked,this,Widget::myslot01);
QPushButton *btn03 = new QPushButton("一个信号连接另一个信号",this);
btn03->resize(300,50);
btn03->move(0,100);
connect(btn03,QPushButton::clicked,btn01,QPushButton::clicked);
//槽可以被取消链接
//delete btn01;
//信号与槽可以断开
// btn03->disconnect(btn01);
}
Widget::~Widget()
{
delete ui;
}
void Widget::myslot01()
{
qDebug() << endl << "myslot01" << endl;
}
void Widget::myslot02()
{
qDebug() << endl << "myslot02" << endl;
}
void Widget::myslot03()
{
qDebug() << endl << "myslot03" << endl;
}
- 一个信号连接多个槽:
-
多个信号连接一个槽
-
一个信号连接另一个信号
-
信号与槽可以断开:断开后无响应
3.6 Lambda表达式
C++11 中的 Lambda 表达式用于定义并创建匿名的函数对象
作用:简化编程工作。
3.6.1 语法
[函数对象参数](操作符重载函数参数) mutable ->返回值{函数体}
解释:
- [ ]:lambda表达式符号,,可以啥都不写,不能省略
- 函数对象参数
- 空 没有使用任何函数对象参数
- = 可以访问外部变量只能读
- a,b 能对lambda外的a,b变量读操作
- & lambda外的变量读写操作
- a,&b 对外部的a读 b读写
- this 函数体内可以使用 Lambda 所在类中的成员变量
- ():形参列表
3.6.2 示例
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
int m;
int n;
public slots:
myslot01();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
setWindowTitle("QT4连接信号与槽的写法");
setFixedSize(800,600);
QPushButton *btn = new QPushButton("QT4",this);
btn->resize(300,50);
//QT4写法
//connect(btn, SIGNAL(clicked(bool)), this, SLOT(myslot01()));
//QT5的写法
//connect(btn,QPushButton::clicked,this,Widget::myslot01);
//lambda表达式
//语法:[...](形参列表){函数体};
// connect(btn,QPushButton::clicked,[](){
// qDebug() << "Lambda函数" << endl;
// });
// int num = 10;
// //=,可以访问外部变量,但是不能修改
// connect(btn,QPushButton::clicked,[=](){
// qDebug() << "Lambda函数" << num << endl;
// });
// int x = 11;
// int y = 22;
// //能对lambda外的x,y变量只读操作,修改会报错
// connect(btn,QPushButton::clicked, [x, y](){
// qDebug() << "Lambda函数" << x << endl;
// qDebug() << "Lambda函数" << y << endl;
// });
//局部变量,可以修改, 访问是随机值,因为这块代码结束局部变量会弹栈销毁,
//所以要声明成全局变量或者用static修饰
//此处为全局变量,访问全局变量用this,用static修饰时,[]中为[&m, &n]即可。
m = 11;
n = 22;
connect(btn,QPushButton::clicked,[this](){
qDebug() << "Lambda函数" << m << endl;
qDebug() << "Lambda函数" << n << endl;
m = 111;
n = 222;
qDebug() << "Lambda函数" << n << endl;
qDebug() << "Lambda函数" << n << endl;
});
}
Widget::~Widget()
{
delete ui;
}
Widget::myslot01()
{
qDebug() << "slot01" << endl;
}
结果: