Qt实战
通过两个独立窗口的切换来学习信号和槽
创建项目
新建Qt Widgets应用,项目名称SingelAndSlot ,类名默认为mainWidget,基类默认为QWidget,不勾选创建界面。
先来认识SingelAndSlot.pro文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#添加模块
QT += core gui
#高于4版本,添加QT += widgets,为了兼容Qt4
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
#应用程序的名字
TARGET = SingelAndSlot
#指定SingelAndSlot的类型为app
TEMPLATE = app
#源文件 .cpp文件
SOURCES += main.cpp\
mainwidget.cpp
#头文件 .h文件
HEADERS += mainwidget.h创建两个按钮:
mainwidget.h中添加代码:1
2
3private:
QPushButton b1;
QPushButton *b2;
mainwidget.cpp中添加:1
2
3
4
5
6b1.setParent(this);
b1.setText(("close");
b1.move(100,100);
b2=new QPushButton(this);//b2是指针,要分配存储空间
b2->setText("abc");
connect函数
用法:
connect( 信号发出者, &发出者类型::信号名字,接受者(this),&接受者类名::槽函数名字)
说明:
- 信号发送者和接受者均为指针类型(非指针类型添加“&”符号)
- 槽函数,即信号处理函数
如果是自定义的槽函数,需要注意以下几点:
- 可以是任意的成员函数,普通全局函数,静态函数;
- 槽函数需要和信号一致(返回值,参数);
- 由于信号都是没有返回值的,所以,槽函数一定没有返回值;
添加b1的槽函数
MainWidget.cpp中的构造函数中继续添加:1
connect(&b1,&QPushButton::pressed,this,&MainWidget::close);
代码实现点击b1按钮,主窗口关闭。
添加b2的槽函数
在mainwidget.h中添加自定义公有槽函数成员:
1 | void myslot(); |
MainWidget.cpp中的构造函数中添加:1
2
3//b2本来就是指针(地址),不需添加地址符
connect(b2,&QPushButton::released,this,&MainWidget::myslot);
connect(b2,&QPushButton::released,&b1,&QPushButton::hide);
MainWidget.cpp中添加函数定义:1
2
3void MainWidget::myslot(){
b2->setText("123");
}
以上代码实现释放b2按钮,主窗口实现自定义槽函数,修改按钮b2的内容,b1按钮实现按钮隐藏。
创建新窗口
头文件右击添加新文件,选择c++ class,类名为subwidget,基类为Widget。
- 在主窗口的头文件中添加按钮a3,源文件中添加代码:
1 | b3.setParent(this); |
- 在子窗口文件头文件添加按钮成员b,源文件中添加代码:
1
2
3
4
5this->setWindowTitle("我是小弟");
b.setParent(this);
b.setText("切换到主窗口");
resize(300,400);
切换槽函数
- 主窗口切换为子窗口。
① 头文件中添加公有函数成员:1
void changeWin();//切换窗口
② 添加槽函数连接和定义:1
2
3
4
5
6
7
8
9
10
11//构造函数中添加
connect(&b3,&QPushButton::released,this,&MainWidget::changeWin);
//函数定义
void MainWidget::changeWin(){
//子窗口显示
w.show();
//主窗口隐藏
this->hide();
}
- 子窗口切换为主窗口
子窗口发送信号
- 信号必须有signals关键字
- 信号没有返回值,但可以有参数
- 信号就是函数的声明,只需声明,无需定义
- 使用 emit mysignel();
- 信号可以重载
① 在子窗口头文件中添加公有信号处理函数和信号成员
1 | void sendSlot(); |
② 在子窗口源文件中添加连接及其信号处理函数:1
2
3
4
5
6
7//子窗口构造函数中添加
connect(&b,&QPushButton::clicked,this,&subWidget::sendSlot);
void subWidget::sendSlot(){
emit mysignal();//发送信号
}
③ 在主窗口中添加处理信号函数:
1 | void dealsubSignal(); |
④ 在主窗口的源文件中创建信号和槽函数的连接 和处理函数的定义1
2
3
4
5
6
7
8
9 //处理主窗口信号
connect(&w,&subWidget::mysignal,this,&MainWidget::dealsubSignal);
void MainWidget::dealsubSignal(){
//子窗口隐藏
w.hide();
//主窗口显示
this->show();
}
这里解释一下:其实这里不是在子窗口中响应子窗口按钮发出的信号,而是通过主窗口来处理信号,只是他的信号发送方是子窗口,但要通过按钮实现,所以按下子窗口的按钮后的调用函数,函数执行的事件是发送一个信号给主窗口,这个信号属于子窗口。主窗口在对信号进行处理。
带参数的信号
在子窗口继续添加一个带参信号:
1
2
3signals:
void mysignal();
void mysignal(int,QString);在前面按钮按下而发送信号的函数里继续添加发送信号:
1 | void subWidget::sendSlot(){ |
- 在主窗口里添加信号处理函数
1 | void dealSlot(int,QString); |
- 信号连接和处理函数定义:
1 | connect(&w,&subWidget::mysignal,this,&MainWidget::dealSlot); |
运行程序,发现报错,这是为什么呢?
因为connect里的参数&subWidget::mysignal不知道是含参信号函数还是不含参信号函数啊
解决办法有两种:
① 函数指针
1 | void (subWidget::*withnotcansignal)()=&subWidget::mysignal; |
注意: 加上作用域
② SIGNAL和SLOT(这是qt4的信号连接,安全性不好)
1 | //Qt4 |
Lamda表达式直接处理信号
在.pro项目文件中添加
1
CONFIG +=C++11
在主窗口的源文件中继续添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15QPushButton *b4=new QPushButton(this);
b4->setText("lambda表达式");
b4->move(150,150);
//[]里面放你要对外部那些变量进行操作的变量,否则无法捕捉到,
//一般最好用“=”表示外面所有局部变量、类中所有成员以值传递方式(就像拷贝一样)
//()传参,如果这个函数要处理的信号有参数,那括号里需要包含所传参数
//mutable允许对传入的成员进行操作,否则只读
int a=2;
connect(b4,&QPushButton::released,
[=]()mutable
{
b4->setText("123");
a=11;
});
Lamda表达式可以创造一个对信号直接处理的函数,不需要重声明和定义一个函数
创建一个主窗口
创建项目
新建Qt Widgets应用,项目名称QWindow ,类名默认MainWindow,基类默认为QMainWindow,不勾选创建界面。
mainwindow.cpp代码如下,根据代码领会,不在解释:
1 |
|
运行结果如图: