# QT 初步简介

# Qt 模块

模块描述
Qt CoreQt 类库的核心,所有其他模块都依赖于此模块
Qt GUI设计 GUI 界面的基础类,包括 OpenGL
Qt Multimedia音频、视频、摄像头和广播功能的类
Qt Multimedia Widgets实现多媒体功能的界面组件类
Qt Network使网络编程更简单和轻便的类
Qt QML用于 QML 和 JavaScript 语言的类
Qt Quick用于构建具有定制用户界面的动态应用程序的声明框架
Qt Quick Controls创建桌面样式用户界面,基于 Qt Quick 的用户界面控件
Qt Quick Dialogs用于 Qt Quick 的系统对话框类型
Qt Quick Layouts用于 Qt Quick 2 界面元素的布局项
Qt SQL使用 SQL 用于数据库操作的类
Qt Test用于应用程序和库进行单元测试的类
Qt Widgets用于构建 GUI 界面的 C++ 图形组件类

# 内容重述

QT ,hello word!, 初步 建立 UI, 代码生成 UI,代码和手动 UI 优缺点 对比, 默认生成文件对比 ,Object Trees 自动释放 子类 new 空间, 信号和槽

  • Qt 的安装路径和文件命名不能有中文
  • Qt 默认 UFTF8 编码

# 启动 QT

启动QT桌面的应用

# 基于对话框!Dialog

创建新项目,基于如下相关设置, QDialog 基于对话框的 QT

选择建立的系统

选择class类型以及class名字

选择编译组件

最后的summary

# UI 编辑区

UI编辑区

在编辑的 pro 文件下,最后添加 RC_ICONS = myico.ico

此 ico 文件需要 提前 在下载并放到文件代码所在位置

添加窗口logo

# 运行

点击左下角的运行,可选择 调试发布 两种,当要发布当前文件时选择 release

hello word执行窗口

# QT 软件的发布

在 QT 文件夹下使用 QT cmd 窗口输入,使用 windeployqt 将 QT 运行所需要的动态库存入到 myfirstQTAPP 当中(注意 myfirstQTAPP 需要提前将 QT release 所生成的 exe 文件存入到此文件夹中)。

windeployqt E:\C++study\QT\QT_exercise\QT01\myfirstQTAPP

生成后发布的文件

# Qwidget

创建项目 Base class 选择 Qwidget 创建的界面对所有的界面相关组件都是支持的

# .pro 文件详解

# 在此项目中加入core gui核心(控制台不需要)
# QT是以模块的形式组织类库,根据项目需求不同添加不同类库的支持
QT       += core gui
# 当QT版本大于4,在当前项目中添加widgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
# 都为自动生成的
# 源代码
SOURCES += \
    main.cpp \
    widgets.cpp
# 头文件
HEADERS += \
    widgets.h
# ui文件
FORMS += \
    widgets.ui
# Default rules for deployment.默认部署规则
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

槽类似 信号 ,当点击之后对相关函数进行响应。

槽

Signals and Slots Editor 信号与槽编辑,

  • 发送者即点击的对象,如图点击 pushButton_2 上面 close,
  • 第二个信号为 clicked() 即当点击发送者的时候,
  • 接受者为 发送者执行信号 clicked() 然后接受者 执行
  • close () 接受者 widgets (窗口) 即 关闭窗口
    信号与槽操作

# main.cpp

#include "widgets.h"
#include <QApplication>  //qt 的标准应用程序,QT 必须有得
int main(int argc, char *argv[])
{
    // 应用程序对应,在一个 Qt 项目中实例对应有且仅有一个
    // 类的作用:检测触发的事件,进行事件循环并处理
    QApplication a(argc, argv); // 必须引用对应的 #include <QApplication>
    //widgets 创建 w 对象
    widgets w;
    //w 调用 show 方法,显示窗体
    w.show();
    //a 为 qt 的应用程序,返回让 qt 执行起来。
    // 应用程序对应开始事件循环,保证应用程序不退出,阻塞函数
    return a.exec();
}

# widgets.h

#ifndef WIDGETS_H
#define WIDGETS_H
#include <QWidget>
QT_BEGIN_NAMESPACE
// 命名空间 Ui 里面的 widgets 类
namespace Ui { class widgets; }
QT_END_NAMESPACE
// 此 widgets 与上面命名空间的 ui 里的 widgets 不同,在不同的命名空间
class widgets : public QWidget // 来自 Qwidget 基类
{
    // 宏,使用 QT 的信号与槽都要使用到此宏
    Q_OBJECT
public:
    // 构造函数和析构函数
    widgets(QWidget *parent = nullptr);
    ~widgets();
private:
    // 私有成员 ui 命名空间里面的 widgets
    // 定义指针指向窗口的 UI 对象
    Ui::widgets *ui;
};
#endif // WIDGETS_H

# widgets.cpp

#include "widgets.h"
#include "ui_widgets.h"
#include "testwidget.h"
widgets::widgets(QWidget *parent)
    : QWidget(parent), ui(new Ui::widgets) // 开辟类内存空间
{
    // 调用 setupUi,
        // 通过此就可修改主窗口的相关设置于获取
    ui->setupUi(this); // 实现窗口的各种空间属性,信号与槽关联等
    
    // 一般在 qt 的构造函数中进行数据初始化操作 (窗口,数据....)
    // 如显示当前窗口,并显示另一个窗口
    // 要独立显示窗口,必须要进行 show 操作
#if 0:
    TestWidget* w = new TestWidget;
    // 显示当前窗体
    w->show();
# else
	// 指定了父对象,子窗口和父窗口一起显示出来,内嵌入父窗口
	TestWidget* w = new TestWidget(this);  // 显示到 this 里面,testwidget 被嵌入到 this 对应的主窗口
#endig
}
widgets::~widgets()
{
    // 析构函数释放 new 的空间
    delete ui;
}

# 使用代码实现在 widgets 上的功能

QMainWindow带菜单栏 的窗口
使用代码实现不创建 UI 相关文件

文件列表

# 可视化和代码编写对比:

  • 可视化 用编写代码,极大的省去界面布局调节时间成本
  • 但有些组件没法完全通过 ui 进行可视化添加需要设计 纯代码
  • 纯代码确实效率会低,繁琐,但 可补充ui 无法实现的功能

# 对象数 Object Trees

QObjects organize themselves in object trees. When you create a QObject with another object as parent , it's added to the parent's children() list, and is deleted when the parent is. It turns out that this approach fits the needs of GUI objects very well. For example, a QShortcut (keyboard shortcut) is a child of the relevant window, so when the user closes that window, the shortcut is deleted too.
QQuickItem, the basic visual element of the Qt Quick module, inherits from QObject, but has a concept of the visual parent which differs from that of the QObject parent. An item's visual parent may not necessarily be the same as its object parent. See Concepts - Visual Parent in Qt Quick for more details.
QWidget, the fundamental class of the Qt Widgets module, extends the parent-child relationship. A child normally also becomes a child widget, i.e. it is displayed in its parent's coordinate system and is graphically clipped by its parent's boundaries. For example, when the application deletes a message box after it has been closed, the message box's buttons and label are also deleted, just as we'd want, because the buttons and label are children of the message box.
You can also delete child objects yourself, and they will remove themselves from their parents. For example, when the user removes a toolbar it may lead to the application deleting one of its QToolBar objects, in which case the tool bar's QMainWindow parent would detect the change and reconfigure its screen space accordingly.
The debugging functions QObject::dumpObjectTree() and QObject::dumpObjectInfo() are often useful when an application looks or acts strangely.

# QDebug

In the common case, it is useful to call the qDebug() function to obtain a default QDebug object to use for writing debugging information .

#include <QDebug> // 引用 QDebug 头文件
qDebug() << "Date:" << QDate::currentDate();

# 在 NO_UI 新建一个 QMyClass 类

验证 Object Trees 关闭是否可以 自动释放 new 的空间,而 无需 再析构函数手动 delete 申请的空间

# 代码验证

# widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
};
#endif // WIDGET_H

# widget.cpp

#include "widget.h"
#include <QLabel>
#include <QPushButton>
#include "qmyclass.h" // 引用刚才自己创建的类
// 对象树 // 窗口部件的销毁也会相应销毁子部件 label 等内容申请的空间
// 所以只需申请 new 而无需 delete
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 让其窗口隶属于父类 1,2,3
    // 请求 Qlabel 空间
    QLabel *label = new QLabel(this); //3, 直接带参数,直接隶属于其父类
    // 设立 text 文件
    label->setText("I Love You,XinXin");
    // 设置位置
    label->move(150,100);
    //c 创建按钮,但并未有操作功能
    QPushButton *button = new QPushButton(this); //this 内嵌到父类
    button->setText("Close"); // 设置 Pushbutton 内的文字
    button->setFixedSize(200,200); // 设置按钮的固定大小
    button->move(150,180); // 起点为父类的左上角
    // 当窗口被关闭后,QMyClass 的析构函数也被自动调用
    // 只需写 new,无需再手动写含 delete 的内容
    QMyClass *myclass = new QMyClass(this);
    //1, 此形式呈现会呈现在独立的窗口
    //label->show();
    //2, 让 label 隶属于其父类
    //label->setParent(this);
    // 指定窗体的大小
    resize(400,300);
    // 锁定大小,不可改变
    //setFixedSize(400,300);
    setWindowTitle("My First No UI");
}
Widget::~Widget()
{
    //
}

# qmyclass.h

#ifndef QMYCLASS_H
#define QMYCLASS_H
#include <QWidget>
class QMyClass : public QWidget
{
    Q_OBJECT
public:
    explicit QMyClass(QWidget *parent = nullptr);
    ~QMyClass(); // 作为判断析构函数是否被调用到
signals:
};
#endif // QMYCLASS_H

# qmyclass.cpp

#include "qmyclass.h"
#include <QDebug>  // 输出内容头文件
QMyClass::QMyClass(QWidget *parent)
    : QWidget{parent}
{
}
QMyClass::~QMyClass()
{
    //QT 打印内容,qDebug 输出内容
    qDebug() << "delete myclass"; // 当手动关系窗口,析构函数被调用
}

# main.cpp 和 NO_UI.pro 不变

# 基础窗口类

  • QWidget
    • 所有窗口 类的 基类
    • Qt 中的控件 (按钮,输入框,单选框…) 也属于窗口,基类都是 QWidget
    • 可以内嵌 到其他窗口中:没有边框
    • 可以不内嵌单独显示:独立的窗口,有边框
  • QDialog
    • 对话框类
    • 不能内嵌 到其他窗口中,必须调用 show 方法才显示。
  • QMainWindow
    • 工具栏,状态栏,菜单栏
    • 不能内嵌 到其他窗口中

# 窗口的显示

  • 内嵌窗口
    • 依附于 某一个大的窗口,作为了大窗口的一部分
    • 大窗口就是这个内嵌窗口的父窗口
    • 父窗口显示的时候,内嵌的窗口也就被显示出来了
  • 不内嵌窗口
    • 这类窗口有边框,有标题栏
    • 需要调用函数才可以显示 show
//QWidget 是所有窗口类的基类,调用这个提供的 show () 方法显示窗口 非模态显示
void QWidget::show(); // 显示当前窗口和它的子窗口
// 对话框窗口的模态显示,// 会阻塞当前窗口,不能切换到其它窗口
[virtual slot] int QDialog::exec();

# Qt 坐标

Qt 的坐标原点在窗口 左上角 。内嵌的情况下基于其父窗口。
x轴 递增,
y轴 递增

# Qt 内存回收

new 创建堆内存,
析构顺序从子窗口到顶层主窗口
若创建的对应是 QObject 类的之类 (间接之类也可). 创建的对应,必须要指定其父对象是谁,

// 通过构造函数 parent 当前窗口的父对象
QWidget::QWidget(QWidget *parent = Q_NULLPTR,Qt::WindowFlags f = Qt::WindowFlags());
QTimer::QTimer(QObject *parent = nullptr)
//2,通过 setParent () 方法
void QWidget::setParent(QWidget *parent)
void QObject::setParent(QWidget *parent)

# Qt log 输出

#include <QDebug>
QDebug() << "输出日志";

若向将 log日志 文件输出到 控制台 ,进入 pro 文件,在 CONFIG 后面加 console , 重新构建即可。

CONFIG += C++11 console

# 字符类型

# QByteArray

char* 的升级版

# QString

QString 是 QByteArray封装
QString 计算长度根据字符个数,而 QByteArray 是将一个中文字符对应三个
具体参考 原文

# QVariant

使用 QVariant自定义类型 进行处理

struct Person
{
	int id;
	QString name;
}
// 引用
// 创建 Person 对象
Person p;
p.id = 25;
p.name = "张三";
// 将其设置为 QVariant 有两种方法
#if 0
	QVariant v;
	v.setValue(p);
#else
	QVariant v = QVariant::fromValue(p)
#endif
	// 取出 V 对象中的数据
	if(v.canConvert<Person>())
	{
		// 转换
		Person tmp = v.value<Person>();
		qDebug()<<tmp.id<<tmp.name;
	}

参考资料:
* 爱编程的大丙:详细部分 https://subingwen.cn/qt/qt-basetype/
* 嵌入式开发设计