QT入门
- 一、简述QT
- 二、QT的基本使用
- [二、QT的Hello World](#二、QT的Hello World)
- 三、对象树
- 四、QT窗口坐标体系
一、简述QT
1、什么是QT
QT是一个跨平台的C++开发框架,主要用于开发图形用户界面应用程序,但同样支持开发不带界面的命令行程序
这里的图形用户界面是一种人与计算机通信的界面显示格式,允许用户通过图形化的操作元素 (如窗口、图标、按钮、菜单等)与计算机进行交互 ,而无需编写程序代码,图形用户界面的主要目的是使得用户能够更加直观、便捷地操作计算机,提高用户体验,也就是专门提供给非程序员的用户使用,因为并不是所有的用户都会编写代码
2、QT的优势
跨平台性:广泛支持几乎所有主流的操作系统
简单易用性:接口简单,容易上手
高效性:代码执行效率高,可维护性和扩展性好
发展性:有庞大的开源社区,市场份额在上升
它在一定程度上简化了内存回收的机制,并且可以进行嵌入式开发
3、应用场景
QT广泛应用于桌面应用程序 ,移动应用程序 ,嵌入式系统
我们熟知的WPS office 就是QT开发的
二、QT的基本使用
前面安装啥的就不再多说了
1、新建项目
(1)选择项目模版
新建项目对话框里一共有五类模版
项目模版 | 说明 |
---|---|
Application | QT应用程序,包括普通窗体程序和QtQuick程序 |
Library | 可以创建动态库、静态库以及QtQuick扩展插件、QtCreator自身插件 |
其他项目 | 可以创建单元测试项目、Qt4设计师自定义控件、子目录项目等 |
Non-Qt-Project | 非QT项目,可以创建纯C/C++项目 |
Import Project | 导入项目,从版本控制管理系统的软件项目导入旧的项目 |
这里我们常用的只有第一种,然后右边会出现四类子模版
Qt Widgets Application:普通窗体模板,传统基于部件的窗体界面程序
Qt Console Application:Qt 控制台应用程序,因为 Qt 主要用于图形界面设计,这个控制台项目模板基本不用
Qt for Python:在Python下用 LGPL 的许可来开发闭源 Qt 软件
Qt Quick Application: Qt 提供的⼀种高级用户界面技术,使用它可以方便快速的为移动以及嵌入式设备开发流畅美观的用户界面,Qt Quick 模块是开发 QML 应用的标准库,提供了使用 QML 创建用户界面所需的一切,包括可视化、交互、动画、模型、视图、粒子效果以及着色效果等
(2)选择项目路径
就是选择文件保存的位置,注意这个位置一定要全英文
(3)选择构建系统
qmake:是一个构建工具,用于自动生成makefile文件,支持跨平台构建,qmake编辑的是一个后缀为.pro的文件
CMake:是一个跨平台的构建工具,本身不是一个编译器,而是一个能够生成让编译器读懂编译流程的文件工具
Qbs:已经被Qt官方弃用了,不再维护,所以没必要多说了
(4)填写类信息设置界面
上面的红框是基类的选择,目前有三种基类
基类 | 说明 |
---|---|
QMainWindow | 主窗口类,一般用于较为复杂的应用程序,除了中央客户区界面,还包括菜单栏、工具栏、状态栏、以及多个可停靠的工具对话框等 |
QWidget | 最简单最基本的窗体程序,里面可以放置多个控件实现程序功能 |
QDialog | 基于对话框的程序,对话框一般用于弹窗,也可以用于主界面显示,对话框是从QWidget继承而来的,并丰富了一些功能,如模态显示和返回值等 |
它们的关系就是:QWidget是QMainWindow和QDialog的父类
(5)选择语言和翻译软件
这个用不到,当我们的水平走向国际化了,就可以用了
(6)选择QT套件
把安装包的所有东西都下上,直接都选上就行了
(7)选择版本控制系统
蓝框就是如果有GIT仓库(gitee或者github)就可以选择直接传到仓库中,如果没有或者不想传就选择None
红框中是自动生成的文件
(8)创建完毕
其实QT程序的编写窗口是很明了的,感觉跟VS的布局也差不了多少
二、QT的Hello World
既然我们会创建文件了,那么我们就应该动手写第一个QT程序了,和C语言一样,这里我们来写一个Hello World程序
1、使用按钮实现
(1)纯代码方式实现
cpp
#include "widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QPushButton* button = new QPushButton;
button->setText("Hello World");
button->setParent(this);
}
Widget::~Widget()
{
}
先包含按钮的头文件,然后构建一个指针,对指针进行操作,setText是设置文本,setParent是将按钮挂载到对象树上,对象树也是一种树形结构,通过对象树我们可以对树上的对象进行统一的析构,挂载在对象树上的内容才能被窗口显示
按钮默认在窗口左上角
(2)可视化操作实现
双击打开widget.ui文件,将Push Button拖到界面上,双击更改内容
这就是QT编译器自动生成的代码,我们通过自己编写的纯代码方式实现也会被解析成类似的代码
2、使用标签实现
跟上面差不多,不多说了
(1)纯代码方式实现
cpp
#include "widget.h"
#include <QLabel>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QLabel* q = new QLabel;
q->setText("Hello World");
q->setParent(this);
}
Widget::~Widget()
{
}
(2)可视化操作实现
三、对象树
在QT中创建很多对象的时候会提供一个Parent对象指针,QObject是以对象树的形式组织起来的,,当创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是parent,也就是父类指针
在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children列表
当父对象析构的时候,这个列表中的所有对象也会被析构(不是继承意义上的父对象,而是树意义上的父对象)
QWidget是能够在屏幕上显示的一切组件的父类
QWidget继承自QObject,因此也集成了这种对象树关系,一个孩子自动地成为父组件的一个子组件
当我们删除子对象时,包括它的子对象们会自动从其父对象列表中删除
QT引入对象树的概念在一定程度上解决了内存问题
当一个QObject对象在堆上创建的时候,QT会同时为其创建一个对象树,不过对象树种对象的顺序是没有定义的,任何QObject对象delete的时候,如果这个对象有parent则自动将其从parent的children列表中删除,如果有孩子,则自动delete每一个孩子,可以保证没有QObject会被delete两次
QObject要在堆上创建 ,且不说栈上的空间小,局部对象的析构顺序是按照其创建顺序的相反过程,但如果子对象先创建,父对象后创建呢,先析构父对象再析构子对象会造成两次析构函数
并且在构造的时候就要指定parent对象
验证
在Hello World处右键选择AddNew,选择C++文件,在蓝框中输入自定义类名以及该自定义类的父类是哪个类,红框是自动勾选的,不用动,下面黑框的一般也不用动,上面是自己修改的类所包含的头文件,中间是自己创建的类的源文件,可以修改最底下的路径
然后点下一步然后点完成就行,手动创建的类会自动添加到目标工程中,然后将自定义的类完善修改一下
mypushbutton.h
cpp
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H
//#include <QWidget>
#include <QPushButton>
class MyPushButton : public QPushButton
{
Q_OBJECT
public:
explicit MyPushButton(QWidget *parent = nullptr);
~MyPushButton();
signals:
public slots:
};
#endif // MYPUSHBUTTON_H
mypushbutton.cpp
cpp
#include "mypushbutton.h"
#include <QDebug>
MyPushButton::MyPushButton(QWidget *parent) : QPushButton(parent)
{
qDebug() << "按钮构造函数调用";
}
MyPushButton::~MyPushButton()
{
qDebug() << "按钮析构函数被调用";
}
widget.cpp
cpp
#include "widget.h"
#include "ui_widget.h"
#include "mypushbutton.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
MyPushButton* b = new MyPushButton;
b->setText("我的按钮");
b->setParent(this);
}
Widget::~Widget()
{
qDebug() << "Widget析构函数调用";
}
这里使用qDebug的原因是cout打印是GBK,而控制台是按照UTF-8来解析的,正好qDebug也是按照UTF-8来解析的,所以我们就用qDebug了
执行结果反映出对象树确保先释放子节点内存,后释放父节点内存
而析构函数的调用顺序则不一定遵守上述要求,因此看到子节点的析构执行在父节点之后(不能简单的认为调用析构函数就是释放内存)
你想想这样如果是放在栈上那不直接炸肛了吗
四、QT窗口坐标体系
左上角为原点,往右为x轴,往下为y轴
对于嵌套窗口来说,这个坐标是对于父窗口的,也就是父窗口的左上角是原点
通过move函数可以移动控件
今日分享就到这里了~