1、概述
1.1、什么是Qt
Qt是一个跨平台的C++图形用户界面应用程序框架,它为应用程序开发者提供建立艺术级图形界面的所有功能,它是完全面向对象的,很容易扩展,并且允许真正的组件编程。
1.2、Qt的发展史
1991年Qt最早由奇趣科技开发;
1996年进入商业领域,它也是目前流行的Linux桌面环境KDE的基础;
2008年,奇趣科技被诺基亚公司收购,Qt称为诺基亚旗下的编程语言;
2012年,Qt又被Digia公司收购;
2014年4月,跨平台的集成开发环境Qt Creator 3.1.0 发布,同年5月20日配发了Qt5.3正式版,至此Qt实现了对ios、Android、WP等个平台的全面支持。当前Qt版本为5.9.0.
1.3、支持的平台
Windows - XP、Vista、Win7、Win8、Win2008、Win10;
Unix、X11 - Linux、Sun Solaris、HP-UX、Compaq Tru64 UNIX、IBM ATX、SGI IRIX、FreeBSD、BSD/OS 和其他很多X11平台。
Macintosh - Mac OS X;
Embedded - 有帧缓冲支持的嵌入式Linux平台,WIndows CE。
1.4、Qt 版本
Qt 按照不同的版本发行,分为商业版和开源版。
商业版:为商业软件提供开发,它们提供传统商业软件发行版,并且提供在商业有效期内的免费升级和技术支持服务;
开源的LGPL版本:为了开发自有而设计的开放源码软件,它提供了和商业版本同样的功能,在GNU通用公共许可下,它是免费的。
1.5、Qt 的下载与安装
下载地址:http://www.qt.io/download-open-source/
1.6、Qt 的优点
- 跨平台,几乎支持所有的平台;
- 接口简单,容易上手,学习Qt框架对学习其他框架有参考意义;
- 一定程度上简化了内存回收机制;
- 开发效率高,能够快速地构建应用程序;
- 有很好地社区氛围,市场份额在缓慢上升;
- 可以进行嵌入式开发。
1.7、成功案例
- Linux 桌面环境KDE;
- WPS Office 办公软件;
- Skype 网络电话;
- Google Earth 谷歌地图;
- VLC 多媒体播放器;
- VirtualBox 虚拟机软件。
2、创建 Qt 项目
#include "mywidget.h"
#include <QApplication> // 包含一个应用程序类的头文件
#include <QLocale>
#include <QTranslator>
// main 程序入口 argc命令行变量的数量 argv 命令行变量的数组
int main(int argc, char *argv[])
{
// 应用程序对象,在Qt中应用程序对象有且仅有一个
QApplication a(argc, argv);
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "TestDesktopProject_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
a.installTranslator(&translator);
break;
}
}
// 窗口对象 MyWidget父类 继承自 QWidget
MyWidget w;
// 窗口对象 默认不会显示,必须要调用show方法显示窗口
w.show();
// 让应用程序进入消息循环,让代码“阻塞”到这行
return a.exec();
}
2.1、.pro 文件
QT += core gui # Qt包含的模块,包含core和gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets # 如果Qt的主版本号大于4,则包含widget模块
TARGET = TestDesktopProjecttttt # 目标,生成的.exe程序的名称
TEMPLATE = app # 应用程序模板 Application,告诉qmake为这个应用程序生成哪种makefle。
# 下面是可供使用的选择
# app - 建立一个应用程序的makefile。这是默认值,所以如果模板没有被指定,这个将被使用
# lib - 建立一个库的makefile
# vcapp - 建立一个应用程序的VisualStudio项目文件
# vclib - 建立一个库的VisualStudio项目文件
# subdirs - 这是一个特殊的模板,它可以创建一个能够进入特定目录并且为一个项目文件生成makefile并且为它调用make的makefile
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 \
mainwindow.cpp \
mywidget.cpp
# 头文件
HEADERS += \
mainwindow.h \
mywidget.h
FORMS += \
mainwindow.ui
TRANSLATIONS += \
TestDesktopProject_zh_CN.ts
CONFIG += lrelease
CONFIG += embed_translations
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
2.2、快捷键
注释:ctrl + /
运行:ctrl + r
编译:ctrl + b
字体缩放:ctrl + 鼠标滚轮
查找:ctrl + f
整行移动:ctrl + shift + ↑或者↓
帮助文档:F1
自动对齐:ctrl + i
同名之间的.h和.cpp切换:F4
3、常用 API
3.1、按钮 QPushButton
// 自定义控件
class MyWidget: public QWidget {
Q_OBJECT // Q_OBJECT宏,允许类中使用信号和槽的机制
public:
MyWidget(QWidget* parent = 0) {
// 设置窗口的标题
setWindowTitle("这是窗口的标题");
// 重置窗口的大小(用户可以拖拽)
resize(400, 300);
// 设置窗口的固定大小(用户无法拖拽)
setFixedSize(400, 400);
// 创建一个按钮
QPushButton* btn = new QPushButton();
// 让btn对象依赖在 MyWidget 窗口中
btn->setParent(this);
// 显示文本
btn->setText("第一个按钮");
btn->resize(100, 50);
btn->show(); // 以顶层的方式弹出窗口控件
// 创建第二个按钮 按照控件的大小窗口
QPushButton* btn2 = new QPushButton("第二个按钮", this);
// 移动按钮位置
btn2->move(0, 100);
}
~MyWidget() {}
};
4、对象模型(对象树)
在Qt中创建对象的时候会提供一个Parent对象指针,下面来解释这个parent到底是干什么的。
QObject是以对象树的形式组织起来的。
- 当你创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是parent,也就是父对象指针。这相当于,在创建QObject对象会有自动添加到其父对象的children()列表;
- 当父对象析构的时候,这个列表中的所有父对象也会被析构(注意,这里的父对象并不是继承意义上的父类!这种机制在GUI程序设计中相当有用,例如,一个按钮有一个QShortcut(快捷键)对象作为其子对象,当我们删除按钮的时候,这个快捷键理应被删除,这是合理的;
QWidget是能够在屏幕上显示的一切组件的父类。
- QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的对象,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除,事实就是如此,因为这些都是对话框的子组件。
当创建的对象在堆区的时候,如果指定的父亲是QObject派生下来的类或者QObject子类派生下来的类,可以不用管理释放的操作,该对象会放入到对象树中,这一定程度上简化了内存回收机制。
5、Qt 窗口坐标体系
坐标体系:以左上角为原点(0,0),X向右增加,Y向下增加。
对于嵌套窗口,其坐标是相对于父窗口来说的。
6、信号和槽
connect(信号的发送者, 发送的具体信号, 信号的接收者, 信号的处理(槽函数))
信号和槽的优点:松散耦合,信号发送端和接收端本身是没有关联的,通过connect连接在一起。
当信号和槽出现重载:需要利用函数指针,明确指向函数的地址。
// 自定义控件
class MyWidget: public QWidget {
Q_OBJECT // Q_OBJECT宏,允许类中使用信号和槽的机制
public:
MyWidget(QWidget* parent = 0): QWidget(parent) {
// 设置窗口的标题
setWindowTitle("这是窗口的标题");
// 重置窗口的大小(用户可以拖拽)
resize(400, 300);
// 设置窗口的固定大小(用户无法拖拽)
setFixedSize(400, 400);
// 创建一个自己的按钮
MyPushButton* btn3 = new MyPushButton(this);
btn3->setText("我自己的按钮");
btn3->move(200, 0);
// 需求:点击我的按钮,关闭窗口
// 参数1:信号的发送者;参数2:发送的信号(函数的地址);参数3:信号的接受者;参数4:信号处理函数(槽函数)
connect(btn3, &MyPushButton::clicked, this, &MyWidget::close);
// 也可以使用父类函数地址:connect(btn3, &QPushButton::clicked, this, &QWidget::close);
}
~MyWidget() {
qDebug() << "MyWidget析构函数";
}
};
案例2:
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr) {}
signals:
public slots:
// 早期Qt版本,必须写到public slots下,高级版本可以写到public或者全局下
// 返回值void,需要声明,也需要实现
// 可以有参数,也可以发生重载
void treat()
{
qDebug() << "请老师吃饭";
}
void treat(const QString& foodName) {
qDebug() << "请老师吃" << foodName;
}
};
class Teacher: public QObject
{
Q_OBJECT
public:
Teacher(QObject* parent = nullptr) {}
signals:
// 自定义信号,写道signals下
// 返回值是void,只需要声明,不需要实现
// 可以有参数,可以重载
void hungry();
void hungry(const QString& foodName);
public slots:
};
namespace Ui {
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0)
: QWidget{parent}
{
// 创建一个老师对象
this->mTeacher = new Teacher(this);
// 创建一个学生对象
this->mStudent = new Student(this);
// 老师饿了,学生请客吃饭的连接
void(Teacher::*teacherSignal1)(void) = &Teacher::hungry;
void(Student::*studentSlot1)(void) = &Student::treat;
connect(mTeacher, teacherSignal1, mStudent, studentSlot1);
// 带参数的连接
// 函数指针 -> 函数地址
void(Teacher::*teacherSignal2)(const QString&) = &Teacher::hungry;
void(Student::*studentSlot2)(const QString&) = &Student::treat;
connect(mTeacher, teacherSignal2, mStudent, studentSlot2); // 注意信号和槽函数的参数要一致
// 调用下课函数
classIsOver();
// 点击一个 下课的按钮,再触发下课
QPushButton* btn = new QPushButton("下课", this);
// 重置窗口大小
this->resize(600, 400);
connect(btn, &QPushButton::clicked, mTeacher, teacherSignal1); // 点击按钮,触发下课
// 断开信号
disconnect(mTeacher, teacherSignal2, mStudent, studentSlot2);
// 拓展
// 1、信号是可以连接信号的
// 2、一个信号可以连接多个槽函数
// 3、多个信号可以连接同一个槽函数
// 4、信号和槽函数的参数,必须类型一一对应
// 5、信号和槽的参数个数:信号的参数个数可以多于槽函数的参数个数
// 6、Qt4版本以前的信号和槽的连接方式
// connect(信号发送者, SIGNAL(信号函数()), 信号接收者, SLOT(槽函数()));
// Qt4版本优点:参数直观;缺点:类型不做检测
// Qt5以上支持Qt4的版本写法,反之不支持
}
~Widget() {}
signals:
private:
Teacher* mTeacher;
Student* mStudent;
/**
* @brief 下课了,触发老师饿了的信号
*/
void classIsOver()
{
// 下课函数调用后,触发老师饿了的信号,使用emit关键字
emit mTeacher->hungry();
emit mTeacher->hungry("宫保鸡丁");
}
};
}
1
标签:窗口,Qt,对象,应用程序,信号,按钮,入门 From: https://www.cnblogs.com/aoe1231/p/18441541