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

一、指定父对象

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

* 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》:

  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 = );
  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

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(, );
  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(, );
  41.  
  42. //显示子窗口
  43. //subWin.show();
  44.  
  45. connect(&b3, &QPushButton::released, this, &MainWidget::changeWin);
  46.  
  47. //处理子窗口的信号
  48. // void (SubWidget::*funSignal)() = &SubWidget::mySignal;
  49. // connect(&subWin, funSignal, this, &MainWidget::dealSub);
  50.  
  51. // void (SubWidget::*testSignal)(int, QString) = &SubWidget::mySignal;
  52. // connect(&subWin, testSignal, this, &MainWidget::dealSlot);
  53.  
  54. //Qt4信号连接
  55. //Qt4槽函数必须有slots关键字来修饰
  56. connect(&subWin, SIGNAL(mySignal()), this, SLOT(dealSub()) );
  57.  
  58. connect(&subWin, SIGNAL(mySignal(int,QString)),
  59. this, SLOT(dealSlot(int,QString)) );
  60. // SIGNAL SLOT 将函数名字 -> 字符串 不进行错误检查
  61.  
  62. //Lambda表达式, 匿名函数对象
  63. //C++11增加的新特性, 项目文件: CONFIG += C++11
  64. //Qt配合信号一起使用,非常方便
  65.  
  66. QPushButton *b4 = new QPushButton(this);
  67. b4->setText("Lambda表达式");
  68. b4->move(, );
  69. int a = , b = ;
  70. connect(b4, &QPushButton::clicked,
  71. // = :把外部所有局部变量、类中所有成员以值传递方式
  72. // this: 类中所有成员以值传递方式
  73. // & : 把外部所有局部变量, 引用符号
  74. [=](bool isCheck)
  75. {
  76. qDebug() << isCheck;
  77. }
  78.  
  79. );
  80.  
  81. resize(, );
  82. }
  83.  
  84. void MainWidget::dealSlot(int a, QString str)
  85. {
  86. // str.toUtf8() -> 字节数组QByteArray
  87. // ……data() -> QByteArray -> char *
  88. qDebug() << a << str.toUtf8().data();
  89. }
  90.  
  91. void MainWidget::mySlot()
  92. {
  93. b2->setText("");
  94. }
  95.  
  96. void MainWidget::changeWin()
  97. {
  98. //子窗口显示
  99. subWin.show();
  100. //本窗口隐藏
  101. this->hide();
  102. }
  103.  
  104. void MainWidget::dealSub()
  105. {
  106. //子窗口隐藏
  107. subWin.hide();
  108. //本窗口显示
  109. show();
  110. }
  111.  
  112. MainWidget::~MainWidget()
  113. {
  114.  
  115. }

mainwidget.cpp

  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 = );
  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

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(, );
  12. }
  13.  
  14. void SubWidget::sendSlot()
  15. {
  16. emit mySignal();
  17. emit mySignal(, "我是子窗口");
  18. }

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. TMS320VC5509的MCBSP配置成SPI模式通信

    1. 首先是把MCBSP的配置 其次是时钟停止模式的配置,关闭大同小异 SPI有4中模式,怎么根据上面的寄存器选择哪种模式?下面展示了其中两种,CLKXP=1的时候有另外两种,暂时不整出来了 2. 代 ...

  2. 物理机通过http访问eNSP虚拟Server

    由于测试需要,本文主要通过一个简单的例子介绍通过物理机的浏览器访问华为eNSP虚拟Server,访问网页. 1.首先配置虚拟网卡的地址 2.通过华为的eNSP模拟软件,做出如下拓扑结构图,配置地址如图 ...

  3. shellcode 编码技术

    在很多漏洞利用场景中, shellcode 的内容将会受到限制. 例如你不能输入 \x00 这个字符,编辑框不能输入 \x0d \x0a这样的字符 所以需要完成 shellcode 的逻辑,然后使用编 ...

  4. 《Pro SQL Server Internals, 2nd edition》中CHAPTER 7 Designing and Tuning the Indexes中的Clustered Index Design Considerations一节(译)

    <Pro SQL Server Internals> 作者: Dmitri Korotkevitch 出版社: Apress出版年: 2016-12-29页数: 804定价: USD 59 ...

  5. yocto-sumo源码解析(二): oe-buildenv-internal

    1 首先,脚本先对运行方式进行了检测: if ! $(return >/dev/null 2>&1) ; then echo 'oe-buildenv-internal: erro ...

  6. BLE资料应用笔记 -- 持续更新(转载)

    简而言之,蓝牙无处不在,易于使用,低耗能和低使用成本.’让我们’更深入地探索这些方面吧. 蓝牙无处不在—,您可以在几乎每一台电话.笔记本电脑 .台式电脑和平板电脑中找到蓝牙.因此,您可以便利地连接键盘 ...

  7. 《linux内核分析》chapter3读书笔记

  8. Linux内核分析 读书笔记 (第一章、第二章)

    第一章 Linux内核简介 1.1 Unix的历史 Unix很简洁,仅仅提供几百个系统调用并且有一个非常明确的设计目的. 在Unix中,所有东西都被当做文件,这种抽象使对数据和对设备的操作是通过一套相 ...

  9. Linux内核分析第一周总结

    冯诺依曼体系结构 储存程序计算机工作模型 硬件 程序员 CPU当作for循环: IP: 16位计算机:IP 32位计算机:eIP 64位计算机:rIP X86汇编基础 X86的CPU寄存器 X86的C ...

  10. Jquery封装ajax

    Jquery封装ajax   Load方法     <!-- 将jquery.js导入进来 -->     <script type="text/javascript&qu ...