• QT学习笔记——06-Day14_C++_QT


    在学习QT总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

    06-Day14_C++_QT

    目录:
    一、QT课程安排
    二、QT简介以及优点、成功案例
    三、创建QT项目
    1、Qt Creator简介
    2、main.cpp函数介绍
    3、pro文件介绍
    4、命名规范和常用快捷键
    5、QPushButton简单使用以及窗口简单设置
    6、对象树概念
    7、Qt中的坐标系
    8、信号槽的基本使用-点击按钮关闭窗口
    9、自定义的信号和槽函数
    10、自定义信号槽发送重载的问题以及解决
    11、信号和槽的扩展
    12、Qt4版本的信号和槽写法
    13、Lambda表达式
    四、总结

    一、QT课程安排

    第一天:
        1、Qt的介绍、优点、成功案例
        2、创建第一个Qt程序
        3、熟悉按钮控件常用API
        4、对象树的基本概念
        5、Qt中的坐标系统
        6、信号和槽的基本使用以及拓展
        
    第二天:
        1、带菜单栏的窗口
        2、资源文件
        3、对话框
        4、界面布局
        5、常用控件
        6、自定义控件
        
    第三天:
        1、事件处理
        2、定时器
        3、Event事件分发器
        4、事件过滤器
        5、QPainter绘图
        6、绘图设备的使用
        7、Qfile文件读写操作
        

    第四天:
        QQ群聊软件

    二、QT简介以及优点、成功案例

    1、什么是Qt

    Qt是一个跨平台的C++图形用户界面应用程序框架。它为应用程序开发者提供建立艺术级图形界面所需的所有功能。它是完全面向对象的,很容易扩展,并且允许真正的组件编程。

    2、Qt的发展史

    1991年 Qt最早由奇趣科技开发

    3、支持的平台
    Windows – XP、Vista、Win7、Win8、Win2008、Win10
    Uinux/X11 – Linux、Sun Solaris、HP-UX、Compaq Tru64 UNIX、IBM AIX、SGI IRIX、FreeBSD、BSD/OS、和其他很多X11平台
    Macintosh – Mac OS X
    Embedded – 有帧缓冲支持的嵌入式Linux平台,Windows CE

    4、Qt版本
    Qt按照不同的版本发行,分为商业版和开源版
    商业版
    为商业软件提供开发,他们提供传统商业软件发行版,并且提供在商业有效期内的免费升级和技术支持服务。
    开源的LGPL版本:
    为了开发自有而设计的开放源码软件,它提供了和商业版本同样的功能,在GNU通用公共许可下,它是免费的。

    5、Qt的下载与安装

    官网下载地址:http://www.qt.io/download-open-source/

    QT下载:

    1)Digitser:http://dts.digitser.cn/zh-CN/download/qt.html#qt5

    2)filehorse:https://www.filehorse.com/download-qt/

    2)QTCN:http://www.qtcn.org/bbs/read-htm-tid-1075.html

    QT安装:

    1)Qt 5.5.0 for Windows 32-bit (MinGW 4.9.2, 959 MB)    (info)(qt-opensource-windows-x86-mingw492-5.5.0.exe)下载及安装参看::https://blog.csdn.net/weixin_30675247/article/details/99885242

    2)本人博客:OpenCV+Qt+CMake安装+十种踩坑 ——https://www.cnblogs.com/Alliswell-WP/p/OpenCV_Qt_CMake.html

    添加系统环境变量(我的默认安装,是“C:QtQt5.5.05.5mingw492_32in”和“C:QtQt5.5.0Toolsmingw492_32in”)

    6、Qt的优点
    1)跨平台,几乎支持所有的平台
    2)接口简单,容易上手,学习QT框架对学习其他框架有参考意义。
    3)一定程度上简化了内存回收机制
    4)开发效率高,能够快速的构建应用程序。
    5)有很好的社区氛围,市场份额在缓慢上升。
    6)可以进行嵌入式开发。

    7、成功案例

    Linux桌面环境KDE
    WPS Office 办公软件
    Skype 网络电话
    Google Earth 谷歌地图
    VLC多媒体播放器
    VirtualBox虚拟机软件

    三、创建QT项目

    1、Qt Creator简介

    1)打开Qt Creator 界面选择 New Project或者选择菜单栏 【文件】-【新建文件或项目】菜单项,
    2)弹出New Project对话框,选择Qt Widgets Application,
    3)选择【Choose】按钮,弹出如下对话框,
    4)设置项目名称和路径,按照向导进行下一步,(注意:名称和路径不能有中文和空格!
    5)选择编译套件
    6)向导会默认添加一个继承自CMainWindow的类,可以在此修改类的名字和基类。默认的基类有QMainWindow、QWidget以及QDialog三个,我们可以选择QWidget(类似于空窗口),这里我们可以先创建一个不带UI的界面,继续下一步
    7)系统会默认给我们添加main.cpp、mywidget.cpp、 mywidget.h和一个.pro项目文件,点击完成,即可创建出一个Qt桌面程序。

    向导会默认添加一个继承自CMainWindow的类,可以在此修改类的名字和基类。默认的基类有QMainWindow、QWidget以及QDialog三个。三个的关系?如下(QWidget为基类(大空窗口),QMainWindow(菜单栏,工具栏,动态栏)和QDialog(对话框,有“退出”“取消”等按钮)为子类)。

    2、main.cpp函数介绍

     1 #include "widget.h"
     2 #include <QApplication>//包含头文件 应用程序头文件
     3 
     4 //程序入口argc命令行变量数量,argv命令行变量数组
     5 int main(int argc, char *argv[])
     6 {
     7     //应用程序对象a,Qt中有且仅有一个应用程序对象
     8     QApplication a(argc, argv);
     9     //窗口对象w,创建Widget对象w, Widget基类QWidget
    10     Widget w;
    11     //窗口默认是不会弹出的,如果想弹出,调用show方法
    12     w.show();
    13 
    14     //a.exec()进入消息循环机制,相当于VS中system("pausse")
    15     return a.exec();
    16 
    17 //    while(1)
    18 //    {
    19 //        if(点击叉子)
    20 //        {
    21 //            break;
    22 //        }
    23 //    }
    24 }

    3、pro文件介绍

    在使用Qt向导生成的应用程序.pro文件格式如下:

    1 QT       += core gui  //包含的模块
    2 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets //大于Qt4版本 才包含widget模块
    3 TARGET = QtFirst  //应用程序名  生成的.exe程序名称
    4 TEMPLATE = app    //模板类型    应用程序模板
    5 SOURCES += main.cpp   //源文件
    6         widget.cpp
    7 HEADERS  += widget.h   //头文件

    .pro就是工程文件(project),它是qmake自动生成的用于生产makefile的配置文件.pro文件的写法如下:

    》注释

    》从“#”开始,到这一行结束。

    模板变量告诉qmake为这个应用程序生成哪种makefile。下面是可供使用的选择:TEMPLATE = app

      > app -建立一个应用程序的makefile。这是默认值,所以如果模板没有被指定,这个将被使用。

      > lib - 建立一个库的makefile。

      > vcapp - 建立一个应用程序的VisualStudio项目文件。

      > vclib - 建立一个库的VisualStudio项目文件。

      > subdirs -这是一个特殊的模板,它可以创建一个能够进入特定目录并且为一个项目文件生成makefile并且为它调用make的makefile。

    》#指定生成的应用程序名:

    TARGET = QtDemo

    》#工程中包含的头文件

    HEADERS += include/painter.h

    》#工程中包含的.ui设计文件

    FORMS += forms/painter.ui

    》#工程中包含的源文件

    SOURCES += sources/main.cpp sources

    》#工程中包含的资源文件

    RESOURCES += qrc/painter.qrc

    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

    这条语句的含义是,如果QT_MAJOR_VERSION大于4(也就是当前使用的Qt5及更高版本)需要增加widgets模块。如果项目仅需支持Qt5,也可以直接添加“QT += widgets”一句。不过为了保持代码兼容,最好还是按照QtCreator生成的语句编写。

    》#配置信息

    CONFIG用来告诉qmake关于应用程序的配置信息。

    CONFIG += c++11   //使用c++11的特性

    在这里使用“+=”,是因为我们添加我们的配置选项到任何一个已经存在中。这样做比使用“=”那样替换已经指定的所有选项更安全。


    4、命名规范和常用快捷键

    widget.h

     1 #ifndef WIDGET_H
     2 #define WIDGET_H
     3 
     4 #include <QWidget>
     5 
     6 class Widget : public QWidget //MyWidget继承QWidget
     7 {
     8     Q_OBJECT //Q_OBJECT宏,写了这个宏,就支持了Qt中的信号和槽机制
     9 
    10 public:
    11     Widget(QWidget *parent = 0); //构造函数
    12     ~Widget(); //析构函数
    13 };
    14 
    15 #endif // WIDGET_H

    widget.cpp

     1 #include "widget.h"
     2 
     3 //命名规范 以及 快捷键
     4 //类名:首字母大写,单词与单词之间首字母大写
     5 //函数、变量:首字母小写,单词与单词之间,首字母大写
     6 //快捷键
     7 //运行 Ctrl + R
     8 //编译 Ctrl + B
     9 //查找 Ctrl + F
    10 //帮助文档 F1
    11 //字体缩放 Ctrl + 鼠标滚轮
    12 //自动对齐 Ctrl + i
    13 //整行移动 Ctrl + Shift + 上箭头/下箭头
    14 //同名之间的.h/.cpp切换 F4
    15 //帮助文档:第一种:F1;第二种:左侧按钮“帮助”;第三种:C:QtQt5.5.05.5mingw492_32in
    16 
    17 
    18 
    19 Widget::Widget(QWidget *parent)
    20     : QWidget(parent) //初始化列表
    21 {
    22 }
    23 
    24 Widget::~Widget()
    25 {
    26 
    27 }

    5、QPushButton简单使用以及窗口简单设置

     1 #include "widget.h"
     2 #include <QPushButton>
     3 
     4 //命名规范 以及 快捷键
     5 //类名:首字母大写,单词与单词之间首字母大写
     6 //函数、变量:首字母小写,单词与单词之间,首字母大写
     7 //快捷键
     8 //运行 Ctrl + R
     9 //编译 Ctrl + B
    10 //查找 Ctrl + F
    11 //帮助文档 F1
    12 //字体缩放 Ctrl + 鼠标滚轮
    13 //自动对齐 Ctrl + i
    14 //整行移动 Ctrl + Shift + 上箭头/下箭头
    15 //同名之间的.h/.cpp切换 F4
    16 //帮助文档:第一种:F1;第二种:左侧按钮“帮助”;第三种:C:QtQt5.5.05.5mingw492_32in
    17 //注释快捷键 Ctrl + /
    18 
    19 Widget::Widget(QWidget *parent)
    20     : QWidget(parent) //初始化列表
    21 {
    22     //按钮
    23     QPushButton * btn = new QPushButton;
    24     //btn->show();//show用顶层方式弹出,如果想在Widget窗口中显示,就需要依赖Widget窗口
    25     //设置父亲
    26     btn->setParent(this);
    27 
    28     //设置文字
    29     btn->setText("德玛西亚");//将char*隐式类型转为QString
    30     //如果文字乱码,去“工具”——“选项”——“文本编辑器”——“行为”——“UTF-8”,但是项目要重新构建
    31 
    32     //创建按钮第二种方式,窗口会按照btn2大小进行显示
    33     QPushButton* btn2 = new QPushButton("第二按钮", this);
    34     //重置窗口大小
    35     this->resize(600, 400);
    36 
    37     //移动第二个按钮
    38     btn2->move(100, 100);
    39 
    40     //按钮是否可以重置大小resize? 可以
    41     btn2->resize(50, 50);
    42 
    43     //重置窗口标题,可以不打this
    44     setWindowTitle("Qt第一个窗口");
    45 
    46     //设置固定窗口大小
    47     setFixedSize(600, 400);
    48 
    49 }
    50 
    51 Widget::~Widget()
    52 {
    53 
    54 }

    6、对象树概念

    所有new出来的对象 不用管释放,原因 children表中的对象会在窗口关闭后进行自动释放。

    为什么在Widget中析构写了“Widget析构了”,子类析构中写了“MyButton析构了”却显示:Widget析构了MyButton析构了(父类先析构,然后析构子类)

    因为虽然显示Widget父类析构了,但其实并未析构,而是找其孩子,打印其析构,孩子没有孙子了,所以孩子MyButton析构了,然后析构了Widget.


    在Qt中创建对象的时候会提供一个Parent对象指针,下面来解释这个parent到底是干什么的。
    》QObject是以对象树的形式组织起来的。
      >>当你创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针。
    这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children()列表。
      >>当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!)
    这种机制在 GUI 程序设计中相当有用。例如,一个按钮有一个QShortcut(快捷键)对象作为其子对象。当我们删除按钮的时候,这个快捷键理应被删除。这是合理的。
    》QWidget是能够在屏幕上显示的一切组件的父类。
      >>QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。
      >>当然,我们也可以自己删除子对象,它们会自动从其父对象列表中删除。比如,当我们删除了一个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,并且自动调整屏幕显示。
    Qt 引入对象树的概念,在一定程度上解决了内存问题。
    》当一个QObject对象在堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
    》任何对象树中的 QObject对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。



    7、Qt中的坐标系

    坐标体系:

    以左上角为原点(0,0),X向右增加,Y向下增加。

    对于嵌套窗口,其坐标是相对于父窗口来说的。

    8、信号槽的基本使用-点击按钮关闭窗口

    需求:点击按钮 关闭窗口
    connect(  信号发送者,发送的信号,信号接受者,处理槽函数 )
    优点  松散耦合

     1 #include "widget.h"
     2 #include <QPushButton>
     3 #include "mybutton.h"
     4 #include<QDebug>
     5 
     6 //命名规范 以及 快捷键
     7 //类名:首字母大写,单词与单词之间首字母大写
     8 //函数、变量:首字母小写,单词与单词之间,首字母大写
     9 //快捷键
    10 //运行 Ctrl + R
    11 //编译 Ctrl + B
    12 //查找 Ctrl + F
    13 //帮助文档 F1
    14 //字体缩放 Ctrl + 鼠标滚轮
    15 //自动对齐 Ctrl + i
    16 //整行移动 Ctrl + Shift + 上箭头/下箭头
    17 //同名之间的.h/.cpp切换 F4
    18 //帮助文档:第一种:F1;第二种:左侧按钮“帮助”;第三种:C:QtQt5.5.05.5mingw492_32in
    19 //注释快捷键 Ctrl + /
    20 
    21 Widget::Widget(QWidget *parent)
    22     : QWidget(parent) //初始化列表
    23 {
    24     //按钮
    25     QPushButton * btn = new QPushButton;
    26     //btn->show();//show用顶层方式弹出,如果想在Widget窗口中显示,就需要依赖Widget窗口
    27     //设置父亲
    28     btn->setParent(this);
    29 
    30     //设置文字
    31     btn->setText("德玛西亚");//将char*隐式类型转为QString
    32     //如果文字乱码,去“工具”——“选项”——“文本编辑器”——“行为”——“UTF-8”,但是项目要重新构建
    33 
    34     //创建按钮第二种方式,窗口会按照btn2大小进行显示
    35     QPushButton* btn2 = new QPushButton("第二按钮", this);
    36     //重置窗口大小
    37     this->resize(600, 400);
    38 
    39     //移动第二个按钮
    40     btn2->move(100, 100);
    41 
    42     //按钮是否可以重置大小resize? 可以
    43     btn2->resize(50, 50);
    44 
    45     //重置窗口标题,可以不打this
    46     setWindowTitle("Qt第一个窗口");
    47 
    48     //设置固定窗口大小
    49     setFixedSize(600, 400);
    50 
    51     //一定程度上简化了内存的回收机制
    52     MyButton* myBtn = new MyButton;
    53     myBtn->setText("我的按钮");
    54     myBtn->move(200, 200);
    55     myBtn->setParent(this);
    56 
    57     //Qt坐标系
    58     //x为右侧正向,y以下侧正向
    59 
    60     //点击myBtn关闭窗口
    61     //connect(信号的发送者,发送的信号(信号的地址),信号的接收者,处理的函数(槽函数的地址))
    62     //connect(myBtn, &MyButton::clicked, this, &Widget::close);
    63     connect(myBtn, &QPushButton::clicked, this, &QWidget::close);
    64 }
    65 
    66 Widget::~Widget()
    67 {
    68     qDebug() << "MyWidget的析构";
    69 }

    9、自定义的信号和槽函数

    //需求:创建两个类,Teacher类,Student类
    //下课后,老师Teacher wp 会发出一个信号 饿了
    //学生响应引号 Student st,处理信号的槽函数,请客吃饭

    新建Teacher(QObject)产生了teacher.cpp和teacher.h,Student(QObject)产生了student.cpp和student.h

    编程:

    teacher.h

     1 #ifndef TEACHER_H
     2 #define TEACHER_H
     3 
     4 #include <QObject>
     5 
     6 class Teacher : public QObject
     7 {
     8     Q_OBJECT
     9 public:
    10     explicit Teacher(QObject *parent = 0);
    11 
    12 signals:
    13     //自定义信号,需要写到signals下
    14     //返回类型,必须是void
    15     //信号只需要声明,不需要实现
    16     //信号可以有参数,可以重载
    17     void hungry();
    18 
    19 public slots:
    20 };
    21 
    22 #endif // TEACHER_H

    teacher.cpp(不需要实现)

    1 #include "teacher.h"
    2 
    3 Teacher::Teacher(QObject *parent) : QObject(parent)
    4 {
    5 
    6 }

    student.h

     1 #ifndef STUDENT_H
     2 #define STUDENT_H
     3 
     4 #include <QObject>
     5 
     6 class Student : public QObject
     7 {
     8     Q_OBJECT
     9 public:
    10     explicit Student(QObject *parent = 0);
    11 
    12 signals:
    13 
    14 public slots:
    15     //自定义槽函数
    16     //高版本可以写到:public下,或者全局函数
    17     //槽函数返回值void
    18     //槽函数需要声明,也需要实现
    19     //槽函数也可以有参数,可以发生重载
    20     void treat();
    21 
    22 };
    23 
    24 #endif // STUDENT_H

    student.cpp

     1 #include "student.h"
     2 #include<QDebug>
     3 
     4 Student::Student(QObject *parent) : QObject(parent)
     5 {
     6 
     7 }
     8 
     9 void Student::treat()
    10 {
    11     qDebug() << "请老师吃饭";
    12 
    13 }

    widget.h

     1 #ifndef WIDGET_H
     2 #define WIDGET_H
     3 
     4 #include <QWidget>
     5 #include "teacher.h"
     6 #include "student.h"
     7 
     8 class Widget : public QWidget
     9 {
    10     Q_OBJECT
    11 
    12 public:
    13     Widget(QWidget *parent = 0);
    14     ~Widget();
    15 
    16     Teacher* wp;//写在这里保证widget.cpp中其他函数也可以访问
    17     Student* st;
    18 
    19     void classIsOver();
    20 
    21 };
    22 
    23 #endif // WIDGET_H

    widget.cpp

     1 #include "widget.h"
     2 
     3 //需求:创建两个类,Teacher类,Student类
     4 //下课后,老师Teacher wp 会发出一个信号 饿了
     5 //学生响应引号 Student st,处理信号的槽函数,请客吃饭
     6 
     7 Widget::Widget(QWidget *parent)
     8     : QWidget(parent)
     9 {
    10     wp = new Teacher(this);//放入Widget对象树中,可以不用管释放
    11     st = new Student(this);
    12 
    13     //连接老师和学生
    14     connect(wp, &Teacher::hungry, st, &Student::treat);
    15 
    16     //下课
    17     classIsOver();
    18 }
    19 
    20 Widget::~Widget()
    21 {
    22 
    23 }
    24 
    25 void Widget::classIsOver()
    26 {
    27     //触发老师饿了的信号
    28     //老师饿了的信号属于自定义信号,触发自定义信号关键字emit
    29     emit wp->hungry();
    30 }

    10、自定义信号槽发送重载的问题以及解决

    当自定义信号和槽 出现重载时候,原先写法失效,因为执行的函数地址不明确
    解决方法: 利用函数指针 来明确指向哪个函数的地址

    QString转char*:先转成QByteArray类型,再转char*——QString.toUtf8().data()

    teacher.h

     1 #ifndef TEACHER_H
     2 #define TEACHER_H
     3 
     4 #include <QObject>
     5 
     6 class Teacher : public QObject
     7 {
     8     Q_OBJECT
     9 public:
    10     explicit Teacher(QObject *parent = 0);
    11 
    12 signals:
    13     //自定义信号,需要写到signals下
    14     //返回类型,必须是void
    15     //信号只需要声明,不需要实现
    16     //信号可以有参数,可以重载
    17     void hungry();
    18 
    19     void hungry(QString foodName);
    20 
    21 public slots:
    22 };
    23 
    24 #endif // TEACHER_H

    teacher.cpp(不需要实现)

    student.h

     1 #ifndef STUDENT_H
     2 #define STUDENT_H
     3 
     4 #include <QObject>
     5 
     6 class Student : public QObject
     7 {
     8     Q_OBJECT
     9 public:
    10     explicit Student(QObject *parent = 0);
    11 
    12 signals:
    13 
    14 public slots:
    15     //自定义槽函数
    16     //高版本可以写到:public下,或者全局函数
    17     //槽函数返回值void
    18     //槽函数需要声明,也需要实现
    19     //槽函数也可以有参数,可以发生重载
    20     void treat();
    21 
    22     void treat(QString foodName);
    23 
    24 };
    25 
    26 #endif // STUDENT_H

    student.cpp

     1 #include "student.h"
     2 #include<QDebug>
     3 
     4 Student::Student(QObject *parent) : QObject(parent)
     5 {
     6 
     7 }
     8 
     9 void Student::treat()
    10 {
    11     qDebug() << "请老师吃饭";
    12 
    13 }
    14 
    15 void Student::treat(QString foodName)
    16 {
    17     //qDebug() << "请老师吃饭,老师要吃:" << foodName;
    18 
    19     //QString转char*:先转成QByteArray类型,再转char*
    20     qDebug() << "请老师吃饭,老师要吃:" << foodName.toUtf8().data();
    21 }

    widget.h(不用改)

    widget.cpp

     1 #include "widget.h"
     2 
     3 //需求:创建两个类,Teacher类,Student类
     4 //下课后,老师Teacher wp 会发出一个信号 饿了
     5 //学生响应引号 Student st,处理信号的槽函数,请客吃饭
     6 
     7 Widget::Widget(QWidget *parent)
     8     : QWidget(parent)
     9 {
    10     wp = new Teacher(this);
    11     st = new Student(this);
    12 
    13     //无参 连接老师和学生
    14     //connect(wp, &Teacher::hungry, st, &Student::treat);
    15 
    16     //有参 信号和槽连接
    17     //函数指针,指向函数地址
    18     void(Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
    19     void(Student:: *stSlot)(QString)= &Student::treat;
    20     connect(wp, teacherSignal, st, stSlot);
    21 
    22     //下课
    23     classIsOver();
    24 }
    25 
    26 Widget::~Widget()
    27 {
    28 
    29 }
    30 
    31 void Widget::classIsOver()
    32 {
    33     //触发老师饿了的信号
    34     //老师饿了的信号属于自定义信号,触发自定义信号关键字emit
    35     emit wp->hungry();//触发无参信号
    36     emit wp->hungry("宫保鸡丁");
    37 
    38 }

    11、信号和槽的扩展

     1 #include "widget.h"
     2 #include<QPushButton>
     3 //需求:创建两个类,Teacher类,Student类
     4 //下课后,老师Teacher wp 会发出一个信号 饿了
     5 //学生响应引号 Student st,处理信号的槽函数,请客吃饭
     6 
     7 Widget::Widget(QWidget *parent)
     8     : QWidget(parent)
     9 {
    10     wp = new Teacher(this);
    11     st = new Student(this);
    12 
    13     //无参 连接老师和学生
    14     //connect(wp, &Teacher::hungry, st, &Student::treat);
    15 
    16     //有参 信号和槽连接
    17     //函数指针,指向函数地址
    18     //void(Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
    19     //void(Student:: *stSlot)(QString)= &Student::treat;
    20     //connect(wp, teacherSignal, st, stSlot);
    21 
    22     //下课
    23     //classIsOver();
    24 
    25     //点击按钮,才下课
    26     QPushButton* btn = new QPushButton("下课", this);
    27     //触发无参,信号和槽
    28     //信号连接信号
    29     void(Teacher:: *noTeacherSignal)(void) =&Teacher::hungry;
    30     void(Student:: *noStSlot)(void) = &Student::treat;
    31 
    32     connect(btn, &QPushButton::clicked, wp, noTeacherSignal);
    33     connect(wp, noTeacherSignal, st, noStSlot);
    34     //connect(wp, noTeacherSignal, this, &Widget::close);//一个信号可以触发多个槽函数
    35     //断开信号和槽
    36     //disconnect(wp, noTeacherSignal, st, noStSlot);
    37 
    38     //信号和槽的扩展
    39     //1.信号可以连接信号
    40     //2.信号和槽可以断开,disconnect
    41     //3.一个信号可以触发多个槽函数
    42     //4.多个信号可以连接同一个槽函数
    43     //5.信号和槽的参数必须一一对应,参数个数必须一一对应吗?不一定
    44         //信号的参数个数可以多余槽函数的参数个数,反之不可以,但是必须类型一一对应
    45 
    46 
    47     //重置大小
    48     resize(600, 400);
    49 
    50 }
    51 
    52 Widget::~Widget()
    53 {
    54 
    55 }
    56 
    57 void Widget::classIsOver()
    58 {
    59     //触发老师饿了的信号
    60     //老师饿了的信号属于自定义信号,触发自定义信号关键字emit
    61     emit wp->hungry();//触发无参信号
    62     emit wp->hungry("宫保鸡丁");
    63 
    64 }

    12、Qt4版本的信号和槽写法

     1 #include "widget.h"
     2 #include<QPushButton>
     3 //需求:创建两个类,Teacher类,Student类
     4 //下课后,老师Teacher wp 会发出一个信号 饿了
     5 //学生响应引号 Student st,处理信号的槽函数,请客吃饭
     6 
     7 Widget::Widget(QWidget *parent)
     8     : QWidget(parent)
     9 {
    10     wp = new Teacher(this);
    11     st = new Student(this);
    12 
    13     //无参 连接老师和学生
    14     //connect(wp, &Teacher::hungry, st, &Student::treat);
    15 
    16     //有参 信号和槽连接
    17     //函数指针,指向函数地址
    18     //void(Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
    19     //void(Student:: *stSlot)(QString)= &Student::treat;
    20     //connect(wp, teacherSignal, st, stSlot);
    21 
    22     //下课
    23     //classIsOver();
    24 
    25     //点击按钮,才下课
    26     QPushButton* btn = new QPushButton("下课", this);
    27     //触发无参,信号和槽
    28     //信号连接信号
    29     void(Teacher:: *noTeacherSignal)(void) =&Teacher::hungry;
    30     void(Student:: *noStSlot)(void) = &Student::treat;
    31 
    32     connect(btn, &QPushButton::clicked, wp, noTeacherSignal);
    33     connect(wp, noTeacherSignal, st, noStSlot);
    34     //connect(wp, noTeacherSignal, this, &Widget::close);//一个信号可以触发多个槽函数
    35     //断开信号和槽
    36     //disconnect(wp, noTeacherSignal, st, noStSlot);
    37 
    38     //信号和槽的扩展
    39     //1.信号可以连接信号
    40     //2.信号和槽可以断开,disconnect
    41     //3.一个信号可以触发多个槽函数
    42     //4.多个信号可以连接同一个槽函数
    43     //5.信号和槽的参数必须一一对应,参数个数必须一一对应吗?不一定
    44         //信号的参数个数可以多余槽函数的参数个数,反之不可以,但是必须类型一一对应
    45 
    46     //Qt4版本——信号和槽写法
    47     connect(wp, SIGNAL(hungry(QString)), st, SLOT(treat(QString)));
    48     //不推荐Qt4版本信号槽写法,原因:类型匹配不检测
    49     //优点:参数类型比较直观,发生了重载也不用写函数指针
    50     //不检测原因:SIGNAL和SLOT下,会把里面代码作为字符串处理
    51     //SIGNAL("hungry(QString)") SLOT("treat(QString)")
    52 
    53 
    54     //下课
    55     classIsOver();
    56 
    57 
    58     //重置大小
    59     resize(600, 400);
    60 
    61 }
    62 
    63 Widget::~Widget()
    64 {
    65 
    66 }
    67 
    68 void Widget::classIsOver()
    69 {
    70     //触发老师饿了的信号
    71     //老师饿了的信号属于自定义信号,触发自定义信号关键字emit
    72     //emit wp->hungry();//触发无参信号
    73     emit wp->hungry("宫保鸡丁");
    74 
    75 }

    13、Lambda表达式

    在Qt低版本(如:Qt5.5)需要在(.pro文件最后添加:CONFIG += c++11)!!!


    C++11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。首先看一下Lambda表达式的基本构成:

    1 [capture](parameters) mutable ->return-type
    2 {
    3 statement
    4 }

    [函数对象参数](操作符重载函数参数)mutable ->返回值{函数体}

    ① 函数对象参数;
    [],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:
      》空。没有使用任何函数对象参数。
      》=。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
      》&。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
      》this。函数体内可以使用Lambda所在类中的成员变量。
      》a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
      》&a。将a按引用进行传递。
      》a, &b。将a按值进行传递,b按引用进行传递。
      》=,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
      》&, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。
    ② 操作符重载函数参数;
    标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。
    ③ 可修改标示符;
    mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。
    ④ 函数返回值;
    ->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
    ⑤ 是函数体;
    {},标识函数的实现,这部分不能省略,但函数体可以为空


    练习:

      1 #include "widget.h"
      2 #include<QPushButton>
      3 #include<QDebug>
      4 
      5 //需求:创建两个类,Teacher类,Student类
      6 //下课后,老师Teacher wp 会发出一个信号 饿了
      7 //学生响应引号 Student st,处理信号的槽函数,请客吃饭
      8 
      9 Widget::Widget(QWidget *parent)
     10     : QWidget(parent)
     11 {
     12     wp = new Teacher(this);
     13     st = new Student(this);
     14 
     15     //无参 连接老师和学生
     16     //connect(wp, &Teacher::hungry, st, &Student::treat);
     17 
     18     //有参 信号和槽连接
     19     //函数指针,指向函数地址
     20     //void(Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
     21     //void(Student:: *stSlot)(QString)= &Student::treat;
     22     //connect(wp, teacherSignal, st, stSlot);
     23 
     24     //下课
     25     //classIsOver();
     26 
     27     //点击按钮,才下课
     28     QPushButton* btn = new QPushButton("下课", this);
     29     //触发无参,信号和槽
     30     //信号连接信号
     31     void(Teacher:: *noTeacherSignal)(void) =&Teacher::hungry;
     32     void(Student:: *noStSlot)(void) = &Student::treat;
     33 
     34     connect(btn, &QPushButton::clicked, wp, noTeacherSignal);
     35     connect(wp, noTeacherSignal, st, noStSlot);
     36     //connect(wp, noTeacherSignal, this, &Widget::close);//一个信号可以触发多个槽函数
     37     //断开信号和槽
     38     //disconnect(wp, noTeacherSignal, st, noStSlot);
     39 
     40     //信号和槽的扩展
     41     //1.信号可以连接信号
     42     //2.信号和槽可以断开,disconnect
     43     //3.一个信号可以触发多个槽函数
     44     //4.多个信号可以连接同一个槽函数
     45     //5.信号和槽的参数必须一一对应,参数个数必须一一对应吗?不一定
     46         //信号的参数个数可以多余槽函数的参数个数,反之不可以,但是必须类型一一对应
     47 
     48     //Qt4版本——信号和槽写法
     49     connect(wp, SIGNAL(hungry(QString)), st, SLOT(treat(QString)));
     50     //不推荐Qt4版本信号槽写法,原因:类型匹配不检测
     51     //优点:参数类型比较直观,发生了重载也不用写函数指针
     52     //不检测原因:SIGNAL和SLOT下,会把里面代码作为字符串处理
     53     //SIGNAL("hungry(QString)") SLOT("treat(QString)")
     54 
     55 
     56     //下课
     57     classIsOver();
     58 
     59 
     60     //重置大小
     61     resize(600, 400);
     62 
     63 
     64     QPushButton* btn2 = new QPushButton("aaaa", this);
     65 
     66     //[](){}()调用
     67     [=](){
     68         btn2->setText("bbbb");
     69     }();
     70 
     71     //mutable关键字,用于修改值传递的变量,进行修改
     72     QPushButton * myBtn = new QPushButton (this);
     73     QPushButton * myBtn2 = new QPushButton (this);
     74     myBtn2->move(100,100);
     75     int m = 10;
     76 
     77     connect(myBtn,&QPushButton::clicked,this,[m] ()mutable { m = 100 + 10; qDebug() << m; });
     78 
     79     connect(myBtn2,&QPushButton::clicked,this,[=] ()  { qDebug() << m; });
     80 
     81     qDebug() << m;
     82 
     83     //返回值
     84     int ret = []()->int{return 10000;}();
     85     qDebug() << "ret = " << ret;
     86 
     87     //用到最频繁的[=](){}
     88     QPushButton* btn3 = new QPushButton("btn3", this);
     89     btn3->move(200, 0);
     90     //做信号槽连接,默认内部变量会进行锁状态,只读状态,如果进行写操作,就会挂掉。
     91     //[=]改为[&]就挂掉
     92     connect(btn3, &QPushButton::clicked, this, [=]()
     93     {
     94         btn3->setText("DDDDDD");
     95     });
     96 
     97     //无参按钮调用有参(请客吃饭)
     98     connect(btn3, &QPushButton::clicked, this, [=]()
     99     {
    100         wp->hungry("宫保鸡丁11111");
    101     });
    102     //点击按钮,关闭窗口
    103     //当信号的接收者是this时,可以省略第3个参数this为:
    104     //connect(btn3, &QPushButton::clicked, [=]({this->close()});
    105     connect(btn3, &QPushButton::clicked, this, [=]()
    106     {
    107         this->close();
    108     });
    109 
    110 
    111 }
    112 
    113 Widget::~Widget()
    114 {
    115 
    116 }
    117 
    118 void Widget::classIsOver()
    119 {
    120     //触发老师饿了的信号
    121     //老师饿了的信号属于自定义信号,触发自定义信号关键字emit
    122     //emit wp->hungry();//触发无参信号
    123     emit wp->hungry("宫保鸡丁");
    124 
    125 }

    四、总结

    1    历史
    1.1    1991 奇趣科技
    2    优点
    2.1    跨平台
    2.2    效率高
    2.3    嵌入式
    2.4    市场份额好
    3    成功案例
    3.1    Linux桌面环境 KDE
    3.2    wps
    3.3    谷歌地图
    3.4    屏幕共享
    3.5    VLC
    4    .Pro文件
    4.1    QT +=  所属模块  widget 4 版本以上
    4.2    TARGET  生成exe程序名称
    4.3    TEMPLATE app 应用程序模板
    4.4    SOURCE  HEADER  源文件 头文件
    5    Main函数
    5.1    QApplication a  应用程序对象  有且仅有一个
    5.2    a.exec() 进行消息循环  阻塞
    5.3    MyWidget w  窗口对象
    5.4    默认不会弹出窗口 想要显示窗口 需要调用 show
    6    QPushButton
    6.1    QPushButton * btn  = new QPushButton;
    6.2    btn->setParent(this) 设置父亲
    6.3    btn->setText (“aaa”)
    6.4    btn->move( x, y)
    6.5    重置窗口大小  resize(w,h)
    6.6    重置窗口标题  setWindowTitle(“aaaa”)
    6.7    设置固定窗口大小  setFixedSize(w,h)
    7    对象树
    7.1    所有new出来的对象 不用管释放
    7.2    原因 children表中的对象会在窗口关闭后进行自动释放
    8    Qt中的坐标系
    8.1    x正向 →
    8.2    y正向 ↓
    9    Qt中的信号和槽
    9.1    需求 点击按钮 关闭窗口
    9.2    connect(  信号发送者,发送的信号,信号接受者,处理槽函数 )
    9.3    优点  松散耦合
    10    Qt中的自定义信号和槽
    10.1    自定义信号
    10.1.1     返回值 void
    10.1.2     需要声明 不需要实现
    10.1.3     可以有参数
    10.2    自定义槽函数
    10.2.1    返回值void
    10.2.2    需要声明 需要实现
    10.2.3    可以有参数
    10.3    触发自定义的信号
    10.3.1     emit
    10.4    当自定义信号和槽 出现重载时候,原先写法失效,因为执行的函数地址不明确
    10.5    解决方法: 利用函数指针 来明确指向哪个函数的地址
    10.6    QString转char*    toUtf8 转 QBtyeArray 类型  在利用data 转成char*
    11    信号和槽的拓展
    11.1    信号是可以连接信号的
    11.2    信号和槽可以断开  disconnect
    11.3    一个信号可以连接多个槽函数
    11.4    多个信号可以连接同一个槽函数
    11.5    信号和槽函数的个数必须一一对应
    11.6    信号的参数个数 可以大于槽函数的参数个数 ,反之不可以
    12    Qt4版本信号槽写法
    12.1     信号: SIGNAL下
    12.2     槽: SLOT下
    12.3     优点: 参数直观 不用写函数指针
    12.4     缺点:不会做类型检测
    13    Lambda表达式
    13.1    [](){}
    13.2    []内部 = 值传递 推荐  &引用传递 不推荐
    13.3    ()参数
    13.4    {} 函数实现体
    13.5    mutable改变值传递的内部变量
    13.6    返回值  []() -> type {  };

    在学习QT总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

  • 相关阅读:
    09.安装Collabora Online服务
    08.nextcloud搭建
    07.安装及使用gitlub
    winmerge vs2010
    C#中时间计算汇总
    JS正则表达式大全 转
    js 验证正则
    js验证大全
    CSC 命令编译cs文件
    网站PV、UV以及查看方法(转)
  • 原文地址:https://www.cnblogs.com/Alliswell-WP/p/CPlusPlus_QT_01.html
Copyright © 2020-2023  润新知