# QT 初步简介
# Qt 模块
模块 | 描述 |
---|---|
Qt Core | Qt 类库的核心,所有其他模块都依赖于此模块 |
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
# 基于对话框!Dialog
创建新项目,基于如下相关设置,
QDialog
基于对话框的 QT
# UI 编辑区
# 修改 logo
在编辑的
pro
文件下,最后添加RC_ICONS = myico.ico
此 ico 文件需要
提前
在下载并放到文件代码所在位置
# 运行
点击左下角的运行,可选择
调试
和发布
两种,当要发布当前文件时选择release
# 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 asparent
, 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 arealso
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/
* 嵌入式开发设计