学习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()为槽函数,也需带括号及必要时填充的参数。

posted @ 2020-11-19 11:21  溪嘉嘉  阅读(212)  评论(0编辑  收藏  举报