学习Qt
Qt工程中的头文件与源文件
- widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } // 声明名称空间Ui中的类Widget,即Ui::Widget,用于描述设计的窗体 QT_END_NAMESPACE class Widget : public QWidget // 声明Widget类,与Ui中的Widget类同名,继承自QWidget类 { Q_OBJECT // 宏,涉及信号与槽机制 public: Widget(QWidget *parent = nullptr); // Widget类构造函数,使用默认参数将形参(指向基类QWidget的指针)设为空指针 ~Widget(); private: Ui::Widget *ui; // Widget类私有成员,Ui::Widget类型的指针 }; #endif // WIDGET_H
- widget.cpp
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) // Widget类构造函数的实现,使用成员初始化列表 : QWidget(parent) // 利用基类构造函数,将构造函数的形参传入 , ui(new Ui::Widget) // 将派生类Widget的私有成员(基类无此成员)初始化为指向Ui::Widget的指针,该指针用于指向设计的窗体 { ui->setupUi(this); // 利用Ui::Widget类的指针调用Ui::Widget类中的setupUi方法,用于对设计的窗体进行生成与设置等 } Widget::~Widget() { delete ui; // 析构函数,释放Widget类中动态分配内存的私有成员 }
- main.cpp
#include "widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); // 声明QApplication类对象a,即应用程序对象 Widget w; // 声明Widget对象w,创建窗体 w.show(); // 显示窗体 return a.exec(); // 运行应用程序 }
- ui_widget.h
/******************************************************************************** ** Form generated from reading UI file 'widget.ui' ** ** Created by: Qt User Interface Compiler version 5.14.2 ** ** WARNING! All changes made in this file will be lost when recompiling UI file! ********************************************************************************/ #ifndef UI_WIDGET_H #define UI_WIDGET_H #include <QtCore/QVariant> #include <QtWidgets/QApplication> #include <QtWidgets/QWidget> QT_BEGIN_NAMESPACE class Ui_Widget // 定义UiWiget类,用于封装可视化设计的界面 { public: void setupUi(QWidget *Widget) // 用于创建各个界面组件,并设置其属性即信号与槽的关联 { if (Widget->objectName().isEmpty()) Widget->setObjectName(QString::fromUtf8("Widget")); Widget->resize(800, 600); retranslateUi(Widget); QMetaObject::connectSlotsByName(Widget); } // setupUi void retranslateUi(QWidget *Widget) { Widget->setWindowTitle(QCoreApplication::translate("Widget", "Widget", nullptr)); } // retranslateUi }; namespace Ui { class Widget: public Ui_Widget {}; // 在名称空间Ui中定义一个继承自Ui_Widget的类 } // namespace Ui QT_END_NAMESPACE #endif // UI_WIDGET_H
上述头文件与源文件中涉及到的各种类的相对关系如下:
文件ui_widget.h |
在Qt中进行可视化界面设计后,会生成XML格式的widget.ui文件,该文件编译后会生成ui_widget.h,在此头文件中声明了一个Ui_Widget类用于实现界面,并由其派生出在名称空间Ui中的Ui::Widget类。 |
|||
名称空间Ui | ||||
类Ui_Widget | 派生 | 类Ui::Widget | ||
文件widget.h | 文件widget.h中声明的Widget类与Ui::Widget类重名,但并非同一个类,在Widget类中调用Ui::Widget类型的指针,从而访问可视化设计的界面组件。对于Qt用户来说,可视化界面设计所对应的代码是隐藏的。 | |||
类QWidget | 派生 | 类Widget | ||
私有成员 | Ui::Widget类指针 |
在Qt中新建工程,并创建名称为Widget的窗体类(Widget为Qt中默认名称,可更改为MyWidget等),可以看到,所创建窗体的基类为QWidget(MainWindow、Dialog与Widget类似)。此继承自QWidget的Widget类,即是main函数中窗体对象w的类型。若取消勾选Generate from,则不会自动生成扩展名为.ui的窗体可视化设计文件。
而Widget类中的私有成员指针ui所属的类为名称空间Ui中的Widget类,此Widget类声明于头文件ui_widget.h中,此头文件在编译后才生成,且在编译后的目录下。名称空间Ui中的Widget类派生自Ui_Widget类(此类名称中Ui前缀始终不变,“_”后的名称与自定义的窗体类名相同),而Ui_Widget类是真正用于封装可视化界面的。总的来说,名称空间中Ui中的Widget类(即Ui::Widget类)有双重身份,即是内层真正封装可视化界面类的派生类,也是外层暴露给用户的Widget类的私有成员,从而联系了外层Widget类与内层Ui_Widget类,实现了在外层类方法中通过其私有成员(指针ui)调用内层类方法。
ui_widget.h文件中实现界面功能的类是Ui_Widget。再定义一个类Widget从Ui_Widget继承而来,并定义在namespace Ui里,这样Ui::Widget与widget.h里的类Widget同名,但是用namespace区分开来。所以,界面是Ui::Widget类与文件widget.h里定义的类实际上是两个类,但是Qt的处理让用户感觉不到Ui::Widget类的存在,只需知道在Widget类里用ui指针可以访问可视化设计的界面组件就可以了。
总结
新建Qt工程(以基类为QWidget类名为Widget的窗体为例),则会自动生成头文件widget.h、源文件widget.cpp及main.cpp。
在main.cpp中的主函数里,其主要包括两部分内容:声明一个QApplication对象a并调用exec()方法,用以运行生成的Qt应用;声明一个Widget类对象w并调用show()方式,用以显示窗体。而窗体内容的体现,主要是通过对Widget类的设计来完成的。
在Widget类声明所在的widget.h文件中,主要包括以下内容:
- 引入名称空间Ui中的Ui::Widget类
- 声明Widget类,包括Q_OBJECT宏,公有部分的Widget类构造与析构函数,私有部分的槽函数(包括自动生成与手动编写)声明,私有部分的Ui::Widget类指针ui(用于指向并调用通过“设计”界面设计而自动生成的组件对象)
在Widget类实现所在的widget.cpp文件中,主要包括以下内容:
- 对Widget类构造函数的实现,此构造函数中包括通过Ui::Widget类指针ui调用其所属类方法setupUi(),以及手动关联信号与槽的connect()函数
- 对Widget类析构函数的实现,此析构函数中delete了ui指针
- 对各槽函数的实现
信号与槽
信号(Signal)是在特定情况下被发射的事件,例如PushButton最常见的信号是鼠标单击时发射的clicked()信号。
槽(Slot)是对信号的响应,其作为一个函数,可以定义在创建的窗体类的任何部分(public、private或protected),可以具有任何参数,也可以被直接调用。但与一般函数不同的是,槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。
一个信号可以连接多个槽,多个信号也可以连接同一个槽。
一个信号可与连接另外一个信号,从而在一个信号发射时,也会发射另外一个信号。
当一个信号被发射时,与其关联的槽函数立即被执行,当信号关联的所有槽信号执行完毕后,才会返回信号发射处并执行其后的代码。
在图形界面中关联信号与槽
- 在Qt的“设计”界面中,下方的Signals && Slots Editor可以进行信号与槽的关联。点击“+”可以增加一组关联,在发送者一栏中选择发射信号的组件,在信号一栏中选择相应的信号(如点击等),在接收者一栏选择响应信号的接收组件,而在槽一栏中选择响应的槽函数:
- 设置完成后,可以实现点击Clear按钮情况textEdit中内容:
自动关联信号与槽
- 右键点击需要添加信号与槽的组件,在弹出菜单中点击转到槽:
- 点击想要发送的信号:
- 则会在widget.cpp文件中自动生成槽函数框架:
- 在此函数框架中即可键入接受到信号所产生的响应,从而实现对文字添加下划线:
- 由于此处信号与槽由Qt自动生成(通过点击转到槽),因此二者的关联亦由Qt自动完成,具体实现在ui_widget.h中:
手动关联信号与槽
当槽函数并非通过右击组件自动生成而是手动编写时,信号与槽亦不会由Qt自动关联。此时需要在widget.cpp文件中的Widget构造函数手动添加信号与槽的关联。具体步骤如下:
- 在“设计”界面中拖入相关组件
- 在头文件widget.h中Widget类的private slots部分添加自定义的槽函数声明
- 在源文件widget.cpp中添加槽函数的实现(在头文件中添加函数声明后,通过左击此函数名以选中然后右击选中部分并在弹出菜单中选择Refactor,可实现在对应源文件中函数框架的自动生成)
- 在源文件widget.cpp中Widget类的构造函数中手动关联信号与槽,实现字体颜色的改变
用于关联信号与槽的的函数connect()格式如下:
connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
其中,sender为发射信号的对象,signal()为信号。signal()作为一个函数,需要带括号,必要时括号内还有参数。receiver是接收信号的对象,slot()为槽函数,也需带括号及必要时填充的参数。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)