graphical user interface
Qt类库里大量的类根据功能分为各种模块,这些模块又分为以下几大类:
Qt官网或者帮助文档的“All Modules”页面可以查看所有这些模块的信息。以下是官方对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++ 图形组件类 |
VirtualBox
:虚拟机软件。VLC多媒体播放器
:一个体积小巧、功能强大的开源媒体播放器。YY语音
:又名“歪歪语音”,是一个可以进行在线多人语音聊天和语音会议的免费软件。咪咕音乐
:咪咕音乐是中国移动倾力打造的正版音乐播放器WPS Office
:金山公司(Kingsoft)出品的办公软件,与微软Office兼容性良好,个人版免费。Skype
:一个使用人数众多的基于P2P的VOIP聊天软件。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NHkBqWdY-1656382081210)(assets/image-20200909122848368.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwxKCwoj-1656382081210)(assets/image-20200909123014167.png)]
在指定项目的存储路径的时候, 路径中不能包含中文, 不能包含中文, 不能包含中文
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BLTTdnRF-1656382081211)(assets/image-20200909123314313.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yJzKMsSb-1656382081211)(assets/image-20200909123356763.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ocJdxE2v-1656382081211)(assets/image-20200909123543447.png)]
# 在项目文件中, 注释需要使用 井号(#)
# 项目编译的时候需要加载哪些底层模块
QT += core gui
# 如果当前Qt版本大于4, 会添加一个额外的模块: widgets
# Qt 5中对gui模块进行了拆分, 将 widgets 独立出来了
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# 使用c++11新特性
CONFIG += c++11
#如果在项目中调用了废弃的函数, 项目编译的时候会有警告的提示
DEFINES += QT_DEPRECATED_WARNINGS
# 项目中的源文件
SOURCES += \
main.cpp \
mainwindow.cpp
# 项目中的头文件
HEADERS += \
mainwindow.h
# 项目中的窗口界面文件
FORMS += \
mainwindow.ui
main.cpp
#include "mainwindow.h" // 生成的窗口类头文件
#include // 应用程序类头文件
int main(int argc, char *argv[])
{
// 创建应用程序对象, 在一个Qt项目中实例对象有且仅有一个
// 类的作用: 检测触发的事件, 进行事件循环并处理
QApplication a(argc, argv);
// 创建窗口类对象
MainWindow w;
// 显示窗口
w.show();
// 应用程序对象开始事件循环, 保证应用程序不退出
return a.exec();
}
mainwindow.ui
<ui version="4.0">
<class>MainWindowclass>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0x>
<y>0y>
<width>800width>
<height>600height>
rect>
property>
<property name="windowTitle">
<string>MainWindowstring>
property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar"/>
<widget class="QStatusBar" name="statusbar"/>
widget>
<resources/>
<connections/>
ui>
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include // Qt标准窗口类头文件
QT_BEGIN_NAMESPACE
// mainwindow.ui 文件中也有一个类叫 MainWindow, 将这个类放到命名空间 Ui 中
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT // 这个宏是为了能够使用Qt中的信号槽机制
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui; // 定义指针指向窗口的 UI 对象
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow) // 基于mainwindow.ui创建一个实例对象
{
// 将 mainwindow.ui 的实例对象和 当前类的对象进行关联
// 这样同名的连个类对象就产生了关联, 合二为一了
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
我们在通过Qt向导窗口基于窗口的应用程序的项目过程中倒数第二步让我们选择跟随项目创建的第一个窗口的基类, 下拉菜单中有三个选项, 分别为:
QMainWindow
、QDialog
、QWidget
如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-quQ1hAXS-1656382081212)(assets/image-20200909165056959.png)]
QWidget
内嵌窗口
父窗口显示的时候, 内嵌的窗口也就被显示出来了
不内嵌窗口
这类窗口有边框, 有标题栏
需要调用函数才可以显示
// QWidget是所有窗口类的基类, 调用这个提供的 show() 方法就可以显示将任何窗口显示出来
// 非模态显示
void QWidget::show(); // 显示当前窗口和它的子窗口
// 对话框窗口的非模态显示: 还是调用show() 方法
// 对话框窗口的模态显示
[virtual slot] int QDialog::exec();
Qt的坐标原点在窗口的左上角
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fFwWVAKp-1656382081212)(assets/1.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aWHBlhOi-1656382081213)(assets/2.png)]
在Qt的某一个窗口中有可能有若干个控件, 这个控件都是嵌套的关系
每个窗口都有坐标原点, 在左上角
Qt中窗口显示的时候使用的相对坐标, 相对于自己的父窗口
将子窗口移动到父窗口的某个位置
// 所有窗口类的基类: QWidget
// QWidget中提供了移动窗口的 API函数
// 参数 x, y是要移动的窗口的左上角的点, 窗口的左上角移动到这个坐标点
void move(int x, int y);
void move(const QPoint &);
在Qt中创建对象的时候会提供一个
Parent对象指针
(可以查看类的构造函数),下面来解释这个parent到底是干什么的。QObject是以对象树的形式组织起来的。
当你创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针
。这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children()列表。当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!
)QWidget是能够在屏幕上显示的一切组件的父类。QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。
Qt 引入对象树的概念,在一定程度上解决了内存问题。
当一个QObject对象在堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
任何对象树中的 QObject对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0FQjIrb8-1656382081213)(assets/image-20200909165237496.png)]
综上所述, 我们可以得到一个结论: Qt中有内存回收机制, 但是不是所有被new出的对象被自动回收, 满足条件才可以回收
, 如果想要在Qt中实现内存的自动回收, 需要满足以下两个条件:
创建的对象必须是QObject类的子类(间接子类也可以)
QObject类是没有父类的, Qt中有很大一部分类都是从这个类派生出去的
创建出的类对象, 必须要指定其父对象是谁, 一般情况下有两种操作方式:
// 方式1: 通过构造函数
// parent: 当前窗口的父对象, 找构造函数中的 parent 参数即可
QWidget::QWidget(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
QTimer::QTimer(QObject *parent = nullptr);
// 方式2: 通过setParent()方法
// 假设这个控件没有在构造的时候指定符对象, 可以调用QWidget的api指定父窗口对象
void QWidget::setParent(QWidget *parent);
void QObject::setParent(QObject *parent);