/*******************************************************************************************/

一、指定父对象

/*如果不指定父对象,对象和对象(窗口和窗口)没有关系,独立

* a指定b为它的父对象,a放在b的上面

* 指定父对象,有2种方式:

*            1)setParent

*            2)通过构造函数传参

* 指定父对象,只需要父对象显示,上面的子对象自动显示,不需要再去手动去show子对象了

*/

1)setParent

QPushButton b;

b.setText("^_^"); //给按钮设置内容,

b.setParent(&w); //指定父对象,如果不指定父对象,这里直接show,那么显示的是两个独立的窗口

b.move(100, 100); //移动坐标,以像素点为单位,以左上角为基准点,如果没有移动,默认位置是在左上角

2)通过构造函数传参

QPushButton b1(&w); //通过构造函数传参

b1.setText("abc");

w.show();

//窗口也是一种控件,按钮也是一种控件,所以这种继承关系就导致了一种叫法,窗口是父对象,同时也是父控件,父对象,

//对应,按钮是子对象,同时也是子控件,子窗口

/*******************************************************************************************/

二、标准信号和槽

正常新建工程都是选择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是标准的槽函数。

/*******************************************************************************************/

三、自定义槽函数

/* 自定义槽,就是普通函数的用法

* Qt5中,自定义槽可以是:任意的成员函数,普通全局函数,静态函数

* 槽函数需要和信号一致(指的是参数,返回值一致),所以

* 由于信号都是没有返回值,所以,槽函数一定没有返回值

*/

connect(b2, &QPushButton::released, this, &MainWidget::mySlot);

//一个信号可以有多个处理 /* 可以打比喻,信号:短信 槽函数:接收短信的手机,一条短信可以发给多个手机*/

connect(b2, &QPushButton::released, &b1, &QPushButton::hide);

/*******************************************************************************************/

四、两个独立的窗口

添加新的窗口,就需要添加一个新的类,添加的方法是选择添加c++ class 具体见图1:

/*******************************************************************************************/

五、自定义信号

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对象之间通信的接口

/*******************************************************************************************/

六、带参数的信号

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

/*******************************************************************************************/

七、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》:

 #ifndef MAINWIDGET_H
#define MAINWIDGET_H #include <QWidget>
#include <QPushButton>
#include "subwidget.h" //子窗口头文件 class MainWidget : public QWidget
{
Q_OBJECT public:
MainWidget(QWidget *parent = );
~MainWidget(); public slots:
void mySlot();
void changeWin();
void dealSub();
void dealSlot(int, QString); private:
QPushButton b1;
QPushButton *b2;
QPushButton b3; SubWidget subWin;
}; #endif // MAINWIDGET_H

mainwidget.h

 #include "mainwidget.h"
#include <QPushButton>
#include <QDebug> //打印 MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
b1.setParent(this);
b1.setText("close");
b1.move(, ); b2 = new QPushButton(this);
b2->setText("abc"); connect(&b1, &QPushButton::pressed, this, &MainWidget::close);
/* &b1: 信号发出者,指针类型
* &QPushButton::pressed:处理的信号, &发送者的类名::信号名字
* this: 信号接收者
* &MainWidget::close: 槽函数,信号处理函数 &接收的类名::槽函数名字
*/ /* 自定义槽,普通函数的用法
* Qt5:任意的成员函数,普通全局函数,静态函数
* 槽函数需要和信号一致(参数,返回值)
* 由于信号都是没有返回值,所以,槽函数一定没有返回值
*/
connect(b2, &QPushButton::released, this, &MainWidget::mySlot); connect(b2, &QPushButton::released, &b1, &QPushButton::hide); /* 信号:短信
* 槽函数:接收短信的手机
*/ setWindowTitle("老大");
//this->setWindowTitle("老大"); b3.setParent(this);
b3.setText("切换到子窗口");
b3.move(, ); //显示子窗口
//subWin.show(); connect(&b3, &QPushButton::released, this, &MainWidget::changeWin); //处理子窗口的信号
// void (SubWidget::*funSignal)() = &SubWidget::mySignal;
// connect(&subWin, funSignal, this, &MainWidget::dealSub); // void (SubWidget::*testSignal)(int, QString) = &SubWidget::mySignal;
// connect(&subWin, testSignal, this, &MainWidget::dealSlot); //Qt4信号连接
//Qt4槽函数必须有slots关键字来修饰
connect(&subWin, SIGNAL(mySignal()), this, SLOT(dealSub()) ); connect(&subWin, SIGNAL(mySignal(int,QString)),
this, SLOT(dealSlot(int,QString)) );
// SIGNAL SLOT 将函数名字 -> 字符串 不进行错误检查 //Lambda表达式, 匿名函数对象
//C++11增加的新特性, 项目文件: CONFIG += C++11
//Qt配合信号一起使用,非常方便 QPushButton *b4 = new QPushButton(this);
b4->setText("Lambda表达式");
b4->move(, );
int a = , b = ;
connect(b4, &QPushButton::clicked,
// = :把外部所有局部变量、类中所有成员以值传递方式
// this: 类中所有成员以值传递方式
// & : 把外部所有局部变量, 引用符号
[=](bool isCheck)
{
qDebug() << isCheck;
} ); resize(, );
} void MainWidget::dealSlot(int a, QString str)
{
// str.toUtf8() -> 字节数组QByteArray
// ……data() -> QByteArray -> char *
qDebug() << a << str.toUtf8().data();
} void MainWidget::mySlot()
{
b2->setText("");
} void MainWidget::changeWin()
{
//子窗口显示
subWin.show();
//本窗口隐藏
this->hide();
} void MainWidget::dealSub()
{
//子窗口隐藏
subWin.hide();
//本窗口显示
show();
} MainWidget::~MainWidget()
{ }

mainwidget.cpp

 #ifndef SUBWIDGET_H
#define SUBWIDGET_H #include <QWidget>
#include <QPushButton> class SubWidget : public QWidget
{
Q_OBJECT
public:
explicit SubWidget(QWidget *parent = ); void sendSlot(); signals:
/* 信号必须有signals关键字来声明
* 信号没有返回值,但可以有参数
* 信号就是函数的声明,只需声明,无需定义
* 使用:emit mySignal();
* 信号可以重载
*/ void mySignal();
void mySignal(int, QString); public slots: private:
QPushButton b;
}; #endif // SUBWIDGET_H

subwidget.h

 #include "subwidget.h"

 SubWidget::SubWidget(QWidget *parent) : QWidget(parent)
{
this->setWindowTitle("小弟");
b.setParent(this);
b.setText("切换到主窗口"); connect(&b, &QPushButton::clicked, this, &SubWidget::sendSlot); resize(, );
} void SubWidget::sendSlot()
{
emit mySignal();
emit mySignal(, "我是子窗口");
}

subwidget.cpp

界面编程之QT的信号与槽20180725的更多相关文章

  1. 界面编程之QT的线程20180731

    /*******************************************************************************************/ 一.为什么需 ...

  2. 界面编程之QT窗口系统20180726

    /*******************************************************************************************/ 一.坐标系统 ...

  3. 界面编程之QT的基本介绍与使用20180722

    /*******************************************************************************************/ 一.qt介绍 ...

  4. 界面编程之QT的Socket通信20180730

    /*******************************************************************************************/ 一.linu ...

  5. 界面编程之QT的事件20180727

    /*******************************************************************************************/ 一.事件 1 ...

  6. 界面编程之QT的数据库操作20180801

    /*******************************************************************************************/ 一.数据库连 ...

  7. 界面编程之QT的文件操作20180729

    /*******************************************************************************************/ 一.QT文件 ...

  8. 界面编程之QT绘图和绘图设备20180728

    /*******************************************************************************************/ 一.绘图 整 ...

  9. QT核心编程之Qt线程 (c)

    QT核心编程之Qt线程是本节要介绍的内容,QT核心编程我们要分几个部分来介绍,想参考更多内容,请看末尾的编辑推荐进行详细阅读,先来看本篇内容. Qt对线程提供了支持,它引入了一些基本与平台无关的线程类 ...

随机推荐

  1. #20155232《网络对抗》Exp9 Web安全基础

    20155232<网络对抗>Exp9 Web安全基础 本实践的目标理解常用网络攻击技术的基本原理.Webgoat实践下相关实验. 实验过程 WebGoat Webgoat是OWASP组织研 ...

  2. 20155339 Exp5 MSF基础应用

    20155339 Exp5 MSF基础应用 基础问题回答 用自己的话解释什么是exploit,payload,encode. 答: exploit是通过自己选择的漏洞和载荷进行攻击的一个过程. pay ...

  3. 一、InnoDB引擎

    一.InnoDB的历史 MYSQL的5.1版本的时候还是使用旧的innoDB,当时orale公司推出的新的innoDB引擎, 但是需要以插件的形式编译,叫innoDB plugin : 知道MYSQL ...

  4. CodeForces-1155D Beautiful Array

    Description You are given an array \(a\) consisting of \(n\) integers. Beauty of array is the maximu ...

  5. Arcgis安装要素

    1. ArcGIS安装过程中需将用户名改为计算机名,该计算机名称时需要新建对话框. 2. ArcGIS Server安装过程中要设置ArcGISWebServices用户的读写权限,即设置ASP.NE ...

  6. shell变量常用方法

    变量之数组操作: 参考网址:http://www.jb51.net/article/55253.htm #直接赋值 [root@local-]=chengd [root@local-]=xrd [ro ...

  7. JQuery快速入门-简介

    一.什么是JQuery? jQuery是一个JavaScript库,它通过封装原生的JavaScript函数得到一整套定义好的方法.它的作者是John Resig,于2006年创建的一个开源项目,随着 ...

  8. C语言中指针占据内存空间问题

    以前一直有个疑问,指向不同类型的指针到底占用的内存空间是多大呢? 这个问题我多次问过老师,老师的答案是"指向不同类型的指针占据的内存空间大小不同",我一直很之一这个答案,今天我就做 ...

  9. ESLint 规则详解(二)

    接上篇 ESLint 规则详解(一) 前端界大神 Nicholas C. Zakas 在 2013 年开发的 ESLint,极大地方便了大家对 Javascript 代码进行代码规范检查.这个工具包含 ...

  10. (功能篇)回顾Bug管理系统Mantis优化改造经历

    共分为两篇,功能篇和技术篇. 时间大约是2016年冬天. 考虑搭一个用于Bug管理和追踪的系统. 综合比较下,选择了小巧的开源工具,Mantis. 在源码基础上,做代码修改,完成了定制版的优化改造. ...