dbgcode 发表于 2022-2-27 13:11

从C++ GUI Qt4编程示例看Qt5的信号槽演变

本帖最后由 dbgcode 于 2022-2-27 14:15 编辑

从C++ GUI Qt4编程示例看Qt5的信号槽演变
本示例是在Qt5.6.3中演示

该书是Qt入门经典书籍,可谓信息量详多,不适合零基础人士。
一、第一章三个小示例引入常用概念。
二、关于信号槽函数重载。


一、示例1带你熟悉Qt编程基本框架和编译步骤
#include <QApplication>   //要在项目PRO文件中添加 QT += widgets,否则编译失败。
#include <QLabel>         //1、是窗口程序必须包含的类,2、是输出helloQt的标签类

int main(int argc, char *argv[])    //所有基于C++的程序必有的入口函数
{
    QApplication app (argc,argv);   //初始化窗口必须的实例,必须在Q_OBJECT宏前定义。
    /*         QLabel *lebel=new QLabel("Hello Qt");   //对象生成在堆上,没有delete,有内存泄漏.
                label->show
    */
    QLabel label("helloQt");      //修改为创建在栈上,由程序自动管理。
    //QLabel label("<h2><i>hello</i>""<font color=red>Qt</font></h2>");
    label.show();                   //显示创建的窗口在代码结束

    return app.exec();          //使程序代码一直执行,进入事件循环,直到用户点击退出。
}

示例2引入了信号槽机制
#include <QApplication>
#include<QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc,argv);

    QPushButton button("quit");
    button.show();
    //QObject::connect(&button,SIGNAL(clicked(bool)),&app,SLOT(quit()));          //Qt4写法
    QObject::connect(&button,&QPushButton::clicked,&app,&QApplication::quit);   //Qt5写法

    return app.exec();
}
示例3引入布局的概念,让你从繁复的设置部件位置和大小中脱离出来。
#include <QApplication>
#include <QHBoxLayout>
#include <QSlider>
#include <QSpinBox>

int main(int argc, char *argv[])
{
    QApplication app(argc,argv);

    QWidget window;
    window.setWindowTitle("Enter You Age");
    QSpinBox spinBox;
    QSlider slider(Qt::Horizontal);
    spinBox.setRange(0,130);
    slider.setRange(0,130);
/*//带SIGNAL和SLOT的是Qt4通用写法
    QObject::connect(&spinBox,SIGNAL(valueChanged(int)),&slider,SLOT(setValue(int)));
    QObject::connect(&slider,SIGNAL(valueChanged(int)),&spinBox,SLOT(setValue(int)));
*/
    void (QSpinBox::*sb)(int)=&QSpinBox::valueChanged;//valueChanged有重载,指针要精确匹配函数才能作为信号
    QObject::connect(&spinBox,sb,&slider,&QSlider::setValue);   //Qt5.6写法
    QObject::connect(&slider,&QSlider::valueChanged,&spinBox,&QSpinBox::setValue);
    spinBox.setValue(35);
    QHBoxLayout layout;
    layout.addWidget(&spinBox);
    layout.addWidget(&slider);
    window.setLayout(&layout);

    window.show();
    return app.exec();
}
Qt5和Qt4比较多了两个connnect()函数重载,以及信号槽的类型检查。Qt4在运行时才检查,Qt5可以在编译时检查。
Qt4常用原型和新增函数原型如下:
QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)
QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
可见Qt4和5的发送者和接收者没有变化或者只是省略而已。不同的只是信号槽的类型变化,以前是字符指针型(需要用相应SIGNAL()或SOLT()宏转换),现在变为函数指针型(直接在函数前加&取地址符就好,书写简单了)。
二、关于信号槽的函数重载
在信号槽没有函数重载时Qt5比Qt4书写简单,且有类型检查,通过上面示例也可以看出来。
有重载时,因为信号槽是函数指针,而函数指针必须要指定的具体的函数,也就是说重载的每个函数都要指定一个函数指针,才能在connect()里使用。
但你没有明确初始化一个重载的信号槽函数时,直接使用信号槽函数的名称,编译器会因为不知道具体调用哪个重载的函数而报错。
上面的示例3使用了C语言的方式处理的信号槽。而在C++中建议是下面的处理方式:

QObject::connect(&spinBox,static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),&slider,&QSlider::setValue);
上面是在Qt5.7之前的写法,在Qt5.7及以后的写法是这样:
QObject::connect(&spinBox,qOverload<int>(&QSpinBox::valueChanged),&slider,&QSlider::setValue); //需要C++14
QObject::connect(&spinBox,QOverload<int>::of(&QSpinBox::valueChanged),&slider,&QSlider::setValue); //需要C++11



至于信号槽函数带默认参数时,实现方式就用lambda表达式吧。

JBHAODA 发表于 2022-2-27 13:55

小白一名帮顶

cnfitc 发表于 2022-2-27 15:40

挺好的一个入门教程,火钳刘明

boywhocools 发表于 2022-2-27 20:20

楼主是要提供资料吗?书?

xz91168 发表于 2022-2-28 06:46

我一小白,求大佬给个入门C++的好教程,谢谢

spygg 发表于 2022-2-28 20:16

lambda 简单调用还行,有时候有坑,比如变量作用域等问题

我系阿超 发表于 2022-3-4 10:13

顶一下!

a2504278 发表于 2022-3-6 12:51

我看我一年后还会不会看上面的代码,

liyajojo 发表于 2022-5-10 09:44

顶一下!

wangxiaohu104 发表于 2022-5-12 21:05

谢谢楼主分享,
页: [1] 2
查看完整版本: 从C++ GUI Qt4编程示例看Qt5的信号槽演变