Qt开发 入门

news/2024/4/17 8:21:16

Qt开发 入门

Qt Hello World程序

使用"按钮”实现

纯代码方式实现

(1)创建工程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

剩下的直接下一步即可

(2)编写代码,widget.cpp

#include "widget.h"
#include "ui_widget.h"#include <QPushButton>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton *btn = new QPushButton; //QPushButton是Qt提供的一个标准按钮控件类。btn->setText("Hello World");  //设置按钮上显示的文本为"Hello World"。btn->setParent(this); //将按钮的父对象设置为当前的Widget实例,意味着按钮将出现在这个Widget窗口中//也可以直接在在创建的时候传递this QPushButton *btn = new QPushButton(this);
}Widget::~Widget()
{delete ui;
}

在这里插入图片描述

可视化操作实现

(1) 双击:”widget.ui"文件;

在这里插入图片描述

(2)拖拽控件至 ui 界面窗口并修改内容:

在这里插入图片描述

(3)构建并运行,效果如下所示:

在这里插入图片描述

Qt Designer 右上角,通过树形结构,显示出了当前界面上都有哪些控件

在这里插入图片描述

刚才往界面上拖拽了一个 QPushButton 控件。此时,ui 文件的 xml 中就会多出来这一段代码~~

在这里插入图片描述

进一步的 qmake 就会在编译项目的时候,基于这个内容生成一段 C++ 代码,通过这个 C++ 代码构建出界面内容了

我们可以通过查看源文件查看生成的代码,源文件ui_weight.h

在这里插入图片描述

在这里插入图片描述

#ifndef UI_WIDGET_H
#define UI_WIDGET_H#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget>QT_BEGIN_NAMESPACEclass Ui_Widget
{
public:QPushButton *pushButton;//这里就是具体的自动生成的代码void setupUi(QWidget *Widget){if (Widget->objectName().isEmpty())Widget->setObjectName("Widget");Widget->resize(800, 600);pushButton = new QPushButton(Widget);pushButton->setObjectName("pushButton");pushButton->setGeometry(QRect(260, 140, 121, 51));retranslateUi(Widget);QMetaObject::connectSlotsByName(Widget);} // setupUivoid retranslateUi(QWidget *Widget){Widget->setWindowTitle(QCoreApplication::translate("Widget", "Widget", nullptr));pushButton->setText(QCoreApplication::translate("Widget", "Hello World", nullptr));} // retranslateUi};namespace Ui {class Widget: public Ui_Widget {};
} // namespace UiQT_END_NAMESPACE#endif // UI_WIDGET_H

使用“标签”实现

纯代码方式实现

//widget.cpp
#include "widget.h"
#include "ui_widget.h"#include <QLabel>
#include <QFont>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QLabel *lab = new QLabel(this);lab->setText("Hello World"); //设置标签内容setFixedSize(1000,900);  //设置窗口大小//设置字体QFont font("宋体",64);lab->setFont(font);//设置标签内容显示的位置lab->move(300,300);//设置标签字体颜色lab->setStyleSheet("color:blue");}Widget::~Widget()
{delete ui;
}

在这里插入图片描述

可视化操作实现

(1) 双击:"widget.ui"文件;

在这里插入图片描述

(2)拖拽“标签”至 UI 设计界面中,并双击修改标签内容在这里插入图片描述

在这里插入图片描述

项目文件解析

.pro 文件解析

工程新建好之后,在工程目录列表中有一个后缀为“pro"的文件,"pro"文件就是工程文件(project)。它是 qmake 自动生成的用于生产 makefile 的配置文件。

//test.pro
QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += 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.0SOURCES += \main.cpp \widget.cppHEADERS += \widget.hFORMS += \widget.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

“.pro” 文件的写法如下:

  1. 注释:从“#”开始,到这一行结束
  2. QT += core gui // Qt 包含的模块
  3. greaterThan(QT_MAJOR_VERSION,4):QT += widgets 这条语句的含义是,如果 QT_MAJOR_VERSION 大于 4 也就是当前使用的 Qt5及更高版本) 需要增加 widgets 模块。如果项目仅需支持 Ot5,也可以直接添加"QT += widgets"一句。不过为了保持代码兼容,最好还是按照 QtCreator 生成的语句编写。
  4. 指定生成的应用程序名:TARGET=QtDemo
  5. TEMPLATE = app //模板。告诉 qmake 为这个立用程序生成哪种 makefile。下面是可供选择的模板:
    • app:建立一个应用程序的 makefile。这是默认值,所以如果模板没有被指定,这个将被使用。
    • lib:建立一个库的 makefile。
    • vcapp:建立一个应用程序的 VisualStudio 项目文件。
    • vclib: 建立一个库的 VisualStudio 项目文件。
    • subdirs:这是一个特殊的模板,它可以创一个能够进入特定目录的 makefile 并且为它调用 make 的 makefile。
  6. 工程中包含的源文件:SOURCES += main.cpp/widget.cpp
  7. 工程中包含的头文件:HEADERS += widget.h
  8. 工程中包含的资源文件:RESOURCES += painter.qrc
  9. 工程中包含的“ui"设计文件:FORMS += widget.ui
  10. 配置信息:CONFIG += c++17(使用c++17的特性) CONFIG 用来告诉 qmake 关于应用程序的配置信息。

widget.h 文件解析

在 Qt 中,如果要使用信号与槽 (signal和slot) 的机制就必须加入Q_OBJECT宏;

Ui::Widget*ui; 这个指针是用前面声明的namespace Ui里的 Widget 类定义的,所以指针 ui 是指向可视化设计的界面,后面要访问界面上的组件,都需要通过这个指针 ui 去访问。

//widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECT   //该宏允许类中使用信号和槽机制public:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;  //通过该指针可以访问ui设计界面中的任意控件
};
#endif // WIDGET_H

main.cpp 文件解析

使用 Qt Creator 新建任意工程之后,main.cpp 文件中都会自动生成如下代码:

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

解释:

  1. Ot 系统提供的标准类名声明头文件没有 h 后缀;
  2. Qt 一个类对应一个头文件,类名就是头文件名;
  3. QApplication 为应用程序类;QApplication a;(a为应用程序对象,有且仅有一个。)
    • QApplication 管理图形用户界面应用程序的控制流和主要设置
    • QApplication 是 Qt 的整个后台管理的命脉。它包含主事件循环,在其中来自窗口系统和其它资源的所有事件处理和调度。它也处理应用程序的初始化和结束,并且提供对话管理。
    • 对于任何一个使用 Qt 的图形用户界面应用程序,都正好存在一个 QApplication 对象,而不论这个应用程序在同一时间内是不是有 0、1、2 或更多个窗口。
  4. Widget w; //实例化窗口对象
  5. w.show(); //调用show函数显示窗口
  6. a.exec():程序进入消息循环,等待对用户输入进行响应。这里 main() 把控制权转交给 Qt,Qt 完成事件处理工作,当应用程序退出的时候 exec() 的值就会返回。在 exec() 中,Qt 接受并处理用户和系统的事件并且把它们传递给适当的窗口部件。

widget.cpp 文件解析

widget.cpp 文件是类 Widget 的实现代码,所有在窗体上要实现的功能添加在此文件中;

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);}Widget::~Widget()
{delete ui;
}

widget.ui 文件解析

widget.ui 是窗体界面定义文件,是一个 XML 文件,定义了窗口上的所有组件的属性设置、布局,及其信号与槽函数的关联等。用 UI 设计器可视化设计的界面都由 Qt 自动解析,并以XML文件的形式保存下来。在设计界面时,只需在 Ul 设计器里进行可视化设计即可,而不用管 widget.ui 文件是怎么生成的。

Qt 对象树

在 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 windows;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 对象,并且大胆在堆上创建。

Qt 对象树如图:

在这里插入图片描述

Qt 窗口坐标体系

坐标体系:以左上角为原点 (0,0) ,X向右增加,Y向下增加

在这里插入图片描述

对于嵌套窗口,其坐标是相对于父窗口来说的。

示例:使用 Qt 中的坐标系设置控件的位置;

在这里插入图片描述

运行结果如下图所示:

在这里插入图片描述


https://www.xjx100.cn/news/3293490.html

相关文章

幻兽帕鲁(Palworld 1.4.11.5.0)私有服务器搭建(docker版)

文章目录 说明客户端安装服务器部署1Panel安装和配置docker服务初始化设置设置开机自启动设置镜像加速 游戏服务端部署游戏服务端参数可视化配置 Palworld连接服务器问题总结 服务端升级&#xff08;1.5.0&#xff09; 说明 服务器硬件要求&#xff1a;Linux系统/Window系统&a…

UKP3d导出管道应力分析文件.psa,.cii文件的编号一致

今天&#xff0c;用户反馈&#xff1a;用户用UKP3d9.2.2&#xff0c;UKP3d导出的管道应力分析文件.CII文件的支吊架编号与UKP3d 支吊架编号不一致。如图&#xff1a; 过程&#xff1a;从UKP3d导出cii 中间文件后&#xff0c;再用CII软件转化为C2文件&#xff0c;再对比在UKP3d和…

敏捷中的左移测试:原因和最佳实践

在应用程序开发中&#xff0c;当今最受争议的话题之一是手动测试与自动化测试。即使在技术职业道路上&#xff0c;手动测试人员也面临着转向自动化测试的巨大压力。 虽然需要找出手动测试与自动化测试争论的解决方案变得越来越重要&#xff0c;但了解典型手动质量保证测试人员…

高性能Server的基石:reactor反应堆模式

业务开发同学只关心业务处理流程。但是我们开发的程序都是运行服务端server上&#xff0c;服务端server接收到IO请求后&#xff0c;是如何处理请求并最终进入业务流程的呢&#xff1f;这里不得不提到reactor反应堆模型。reactor反应堆模型来源于大师Doug Lea在 《Sacalable io …

【云安全】网络安全领域安全协议

IPSEC协议 IPSec&#xff08;Internet Protocol Security&#xff09;是一种网络层安全协议&#xff0c;用于在IP通讯过程中确保完整性、认证性和机密性。它通过在标准的IP协议上加入安全机制来实现加密和认证。IPSec主要由两个协议组成&#xff1a;认证头&#xff08;AH&…

探索 SPA 与 MPA:前端架构的选择与权衡

查看本专栏目录 关于作者 还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#x…

uniapp触感反馈(短震动)

使用 uni-app 开发一款 app&#xff0c;需求中有一项是点击 触感反馈&#xff0c;查阅了 uni-app 相关文档&#xff0c;发现并没有对应的 api&#xff0c;最开始尝试用“震动”的方式来模拟“触感反馈” , 但是感觉效果并不好&#xff0c;因为在ios中并不支持短震动(15ms), 只支…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的水果识别系统(Python+PySide6界面+训练代码)

摘要&#xff1a;本篇博客详尽介绍了一套基于深度学习的水果识别系统及其实现代码。系统采用了尖端的YOLOv8算法&#xff0c;并与YOLOv7、YOLOv6、YOLOv5等前代算法进行了详细的性能对比分析&#xff0c;提供在识别图像、视频、实时视频流和批量文件中水果方面的高效准确性。文…