QT开发
文章目录
前言
走进QT的大门,从这里开始
QT下载:http://download.qt.io/
1.特点
跨平台
接口简单,易上手,学习QT框架对学习其他框架有参考意义
开发效率高(继承多态)
一定程度上简化了内存回收机制
有很好的社区氛围
可以进行嵌入式开发
2.QT creator使用
1.选择合适的基类:
父类 Qwidget 精简版窗口
子类 QMainWindow 带菜单栏的窗口
子类 QDialog 对话框
2.QT助手是最靠谱的文档
点击索引即可查找需要的控件,前提是记住控件名称,比如按钮的名称为QPushButton,QT助手关于QPushButton的描述:
Contents
• Properties
• Public Functions //公共函数
• Reimplemented Public Functions //公共槽函数
• Public Slots
• Static Public Members
• Protected Functions
• Reimplemented Protected Functions
• Detailed Description
QPushButton Class
The QPushButton widget provides a command button. More…
Header: #include //头文件
qmake: QT += widgets //所在的模块
Inherits: QAbstractButton //父类(当前类不存在的性质多半继承自长辈,所以可以在长辈类中查找)
Inherited By: QCommandLinkButton //子类
• List of all members, including inherited members
• Obsolete members
3.解决窗口乱码问题
默认编码选择UTF-8(注意在新建的工程有效)
3.工程
1.pro工程文件
QT += core gui #core包含的模块,类比于操作系统中的内核 gui页面显示的核心代码
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
#TARGET = richard #应用程序名 生成的.exe文件
#TEMPLATE = app #模板类型 为 应用程序模板
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
还会有其他选项比如:
FORMS += forms/painter.ui #工程中包含的.ui设计文件
RESOURCES += qrc/painter.qre #工程中包含的资源文件
2.按钮示例
所需的方法都可以在Qt助手中找到,比如移动按钮位置,方法在他的爷爷类中。
main.cpp:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
//QApplication应用程序类,初始化我们的应用程序
QApplication a(argc, argv);
//创建一个主窗口控件
Widget w;
//显示主窗口,hide隐藏窗口(窗口默认是隐藏的,所以创建了之后一定要调用show)
w.show();
//a.exec()主事件循环(带阻塞 等待用户操作界面)widget.cpp
return a.exec();
}
widget.cpp:
#include "widget.h"
#include <QPushButton>
//界面的设计在这,窗口控件的构造函数中
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//this代表当前主窗口
this->setWindowTitle("第一个窗口");
//固定窗口(默认是窗口大小可以拉的)
//this->setFixedSize(800,600); //窗口不可以拖动
//设置窗口大小
this->resize(400,300); //窗口可以拖动
//在窗口上放一个按钮,包含头文件,qmake中增加模块QT += widgets (默认是添加了的),(QT助手)
//parent父对象(和父类的概念不同,表示button将来希望被谁接管)this表示button放到当前窗口,将来负责析构button,
//所以button下面是不需要显式调用delete的,也不需要调用~QPushButton析构函数
QPushButton *button1 = new QPushButton("跟屁虫",this);
//用new的好处:下面的对象树会讲,用局部变量,栈来存储会有什么坏处
//如下分开设置
QPushButton *button2 = new QPushButton;
button2->setParent(this);
button2->setText("Richard");
//默认控件会显示到主窗口左上方,会覆盖button1
//移动,move函数在QPushButton的爷爷类中
button2->move(400,300); //刚好被挡住,拖动窗口显示按钮
}
Widget::~Widget()
{
}
3.对象数
一句话概括就是子对象会被交由父对象接管,关闭程序时父对象会负责清理子对象留下的垃圾。如上述代码。
关于对象树的解释来自这篇文章:https://www.cnblogs.com/gd-luojialin/p/9215707.html(网站上存在大量的抄袭现象,这篇是我找到的中时间最早的,可能是原创,如有侵权请告知)
在Qt中创建对象的时候会提供一个Parent对象指针,下面来解释这个parent到底是干什么的。
QObject是以对象树的形式组织起来的。
当你创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针。
这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children()列表。
当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!)
这种机制在 GUI 程序设计中相当有用。例如,一个按钮有一个QShortcut(快捷键)对象作为其子对象。当我们删除按钮的时候,这个快捷键理应被删除。这是合理的。
QWidget是能够在屏幕上显示的一切组件的父类。
QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。
当然,我们也可以自己删除子对象,它们会自动从其父对象列表中删除。比如,当我们删除了一个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,并且自动调整屏幕显示。
Qt 引入对象树的概念,在一定程度上解决了内存问题。
当一个QObject对象在堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
任何对象树中的 QObject对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。
如果QObject在栈上创建,Qt 保持同样的行为。正常情况下,这也不会发生什么问题。来看下下面的代码片段:
{
QWidget window;
QPushButton quit("Quit", &window);
}
作为父组件的 window 和作为子组件的 quit 都是QObject的子类(事实上,它们都是QWidget的子类,而QWidget是QObject的子类)。这段代码是正确的,quit 的析构函数不会被调用两次,因为标准 C++要求,局部对象的析构顺序应该按照其创建顺序的相反过程。因此,这段代码在超出作用域时,会先调用 quit 的析构函数,将其从父对象 window 的子对象列表中删除,然后才会再调用 window 的析构函数。
但是,如果我们使用下面的代码:
{
QPushButton quit("Quit");
QWidget window;
quit.setParent(&window);
}
情况又有所不同,析构顺序就有了问题。我们看到,在上面的代码中,作为父对象的 window 会首先被析构,因为它是最后一个创建的对象。在析构过程中,它会调用子对象列表中每一个对象的析构函数,也就是说, quit 此时就被析构了。然后,代码继续执行,在 window 析构之后,quit 也会被析构,因为 quit 也是一个局部变量,在超出作用域的时候当然也需要析构。但是,这时候已经是第二次调用 quit 的析构函数了,C++ 不允许调用两次析构函数,因此,程序崩溃了。
由此我们看到,Qt 的对象树机制虽然帮助我们在一定程度上解决了内存问题,但是也引入了一些值得注意的事情。这些细节在今后的开发过程中很可能时不时跳出来烦扰一下,所以,我们最好从开始就养成良好习惯,在 Qt 中,尽量在构造的时候就指定 parent 对象,并且大胆在堆上创建。