Qt创建项目及相关问题

3 篇文章 0 订阅

1. Qt项目创建

模板介绍:

image-20240831133004387

选择路径:

路径不要带中文!!!

中文会影响项目构建

image-20240831203313317

构建系统:

通过Qt写的程序,设计一系列源编程技术,通过代码来生成代码

image-20240831133713415

qmake是Qt老牌的构建工具

CMake并非Qt专属,很多开源项目会采用CMake

Qbs是新一代的Qt构建工具,但实际用的人非常少,Qt官方没怎么维护了

Details

Qt Creator创建项目的时候,会自动生成代码,生成的代码,就包含一个类,此处选择自动生产的类的父类

image-20240831134657003

Widget就是自动生成的类名,QWidget是生成类继承的父类

Qt中内置的类,都是以Q为前缀开头的

这里生成的文件名和类名是关联的,虽然不是强制要求,但还是建议弄成一样的

image-20240831134832336

Qt中创建图形化界面程序的方式有2种:

  1. 直接通过C++代码创建
  2. 通过form file以图形化的方式生成界面

勾选生成form file文件,就可以用Qt Designer 或者Qt Creator来编辑这个ui文件了,从而以图形化的方式快速生成图形界面

选择翻译文件:

此时不关注,这个是和国际化相关的

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

选择编译器的Qt SDK构建代码:

下载时只勾选了MinGW,就只有一个选项

image-20240831135948242

功能管理工具:

这里可选择是否加入到版本控制器里面,想加就加上即可

image-20240831140056575

2. 认识项目代码

main.cpp

C++的程序需要有main函数作为入口函数,此处的main函数是自动生成的。

image-20240831141609089

widget.h

这个文件里面就是Widget类的声明

image-20240831142717218

widget.cpp

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

widget.ui

双击这个ui文件,此时Qt Creator就会调用Qt Designer,打开ui文件,图形化界面编辑器

image-20240831143731220

再点击左侧的“编辑”按钮,此时显式的内容,就是ui文件本体了

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个文件格式叫xml格式

xml格式这里的标签,有哪些标签,表示什么含义,是由程序员自己定义的

这里的标签具体含义,我们不需要太关注,只需知道ui文件本质上是xml即可

Qt中使用xml文件就是描述程序界面是什么样的,进一步的qmake会调用相关工具,依据这个xml文件生成一些C++代码,从而把界面完整构造出来

.pro

.pro文件是Qt项目的工程文件,也是qmake构建的重要依据

image-20240831144903798

qmake搭配.pro起到的作用和Linux当中的makefile作用类似,Qt Creator把这个过程都封装好了,不需要过多关注,只需点击安装按钮即可

构建过程生成的中间文件

运行程序一次之后,在项目目录并列的地方,会多出来一个目录,这个目录里面就是该项目运行过程中生成的一些临时文件

image-20240831150107767

image-20240831151020909

3. Hello World程序

有2种方式实现显式hello world

  1. 图形化的方式,在页面创建控件
  2. 纯代码方式创建

图形化方式创建

按照上面流程,重新创建一个名为HelloWorld的项目

image-20240831160714829

双击widget.ui,进入Designer

这里拖拽Label控件到显示页面,然后可以修改里面的内容

image-20240831161300217

点左下角运行之后,就显示出了一个hello world的页面

image-20240831161409843

这里main.cppwidget.h这些文件并不会发生变化,发生变化的是widget.ui

image-20240831161550582

查看中间文件里的ui_widget.h文件:

void setupUi(QWidget *Widget)
{
    if (Widget->objectName().isEmpty())
        Widget->setObjectName(QString::fromUtf8("Widget"));
    Widget->resize(800, 600);
    label = new QLabel(Widget);
    label->setObjectName(QString::fromUtf8("label"));
    label->setGeometry(QRect(340, 330, 161, 91));

    retranslateUi(Widget);

    QMetaObject::connectSlotsByName(Widget);
} // setupUi

这里就会多了一段创建label对象的代码

代码方式创建

再次创建一个工程,名为HelloWorld_2

通过代码创建界面的时候,一般会把构造函数界面代码放到Widget的构造函数当中

QLabel* label = new QLabel();

image-20240831162348746

这里报错,找不到QLabel的定义,这是因为没有包含这个类的头文件

Qt当中每个类都有一个对于的同名的头文件

Label是界面上显示内容的字符串控件

在创建对象的时候,可以通过new的方式在堆上创建,也可以直接在栈上,一般推荐在堆上创建的方式

这里建议在创建的时候,给构造添一个this参数,这表明给当前创建的对象,指定一个父对象

QLabel* label = new QLabel(this);

image-20240831163054718

然后再调用setText()方法往里面插入内容即可

void setText(const QString &);

这里参数类型是QString,这是因为Qt出的比C++早,早年间C++还没有自己的标准,Qt自己造了一套轮子,来支持Qt开发,里面包括但不限于:

Qstring
QVector
QList
QMap

之后C++标准出了,这些引入的Qt容器类,也没删,和现有的STL容器共存

可以显式写为:

label->setText(QString("hello world");

也可以直接写:

label->setText("hello world");

QString中提供了C风格字符串参数作为构造函数

不显式构造QString,C风格字符串也会隐式构造QString对象

image-20240831164302260

内存泄漏问题

这里new之后,并没有delete,在C++当中,内存泄漏是需要特别关注的事情

但是上面的代码,在Qt中不会引起内存泄漏,这是因为我们将其挂在了对象树上

编辑框方式创建

编辑框分为2种:

  1. 单行编辑框:QLineEdit
  2. 多行编辑框:QTextEdit

这里采用QLineEdit作为演示:

image-20240902201227172

运行之后,这个输入框也可以进行编辑:
image-20240902201308771

也可以采用代码的方式:

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

    QLineEdit* edit = new QLineEdit(this);
    edit->text("hello world");
}

Widget::~Widget()
{
    delete ui;
}

按钮方式创建

这个按钮是可以点击的,这涉及Qt的信号槽机制

本质就是给按钮的点击操作,关联上一个处理函数,用户点击的时候,就会执行这个处理函数

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
 Q_OBJECT

public:
 Widget(QWidget *parent = nullptr);
 ~Widget();

 void handleClick();

private:
 Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

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

 //QLineEdit* edit = new QLineEdit(this);
 //edit->text("hello world");
 // 访问到form file(ui文件)创建的控件
 connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick);
}

Widget::~Widget()
{
 delete ui;
}

void Widget::handleClick()
{
 //点击之后,切换文本
 if(ui->pushButton->text() == QString("Hello World"))
 {
     ui->pushButton->setText("Hello Qt");
 }
 else
 {
     ui->pushButton->setText("Hello World");
 }

}

这个connectQObject这个类提供的静态函数,这个函数的作用就是连接信号和槽

  • ui->pushButton:访问form file(ui文件)中创建的控件

    image-20240902202628740

    这个值会自动生成,也可以手动修改,但是要求在界面中是唯一的

    qmake在处理ui文件的时候,就会根据这里的objectName生成对应的C++代码

  • &QPushButton::clicked:点击按钮pushButton的时候,就会触发信号

  • this:谁来处理这个信号

  • &Widget::handleClick:具体信号怎么处理

    GIF 2024-9-2 21-22-10

这里ui能够找到objectName这个属性,是因为qmake编译的时候会自动生成,objectName设置成什么值,变量名就叫什么:

image-20240902212643880

通过代码创建:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void handleClick();

private:
    Ui::Widget *ui;
    QPushButton* myButton;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    myButton = new QPushButton(this);
    myButton->setText("hello world");

    connect(myButton, &QPushButton::clicked, this, &Widget::handleClick);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::handleClick()
{
    if(myButton->text() == QString("hello world"))
    {
        myButton->setText("hello qt");
    }
    else
    {
        myButton->setText("hello world");
    }
}

对于纯代码版本,按钮对象是自己new的,而且为了保证其他函数能够访问到这个变量,就需要把这个按钮对象设定为widget类的成员变量;

对于图形化,不需要自己newnew对象的操作被Qt自动生成了,而且这个按钮对象,已经作为ui对象里的成员变量了

4. 对象树

引入对象树原因

Qt中有一个对象树(N叉树),将界面的各种元素组织起来

image-20240831165141802

通过这个树形结构,就将这些控件对象组织起来了,最主要的目的就是为了能够在合适的时间,将这些对象统一释放

如何理解“合适的时间”?

当窗口关闭/销毁的时候,这写对象就会被统一消耗,如果某个对象提前销毁,就会导致控件在界面上不存在

这就是为什么要通过new的方式创建对象,将对象的生命周期交给Qt的对象树进行统一管理

image-20240831165734863

这里将对象在栈上创建,运行程序,hello world并没有显示,这是因为label对象随着构造函数的结束就销毁了

对象树自动释放对象实验演示

上面的QLabel是内置的一个对象,并不会显示输出析构信息。

我们可以自定义一个label类,然后显式输出析构信息

image-20240831200921782

mylabel.h

#ifndef MYLABEL_H
#define MYLABEL_H
#include<QLabel>

class MyLabel : public QLabel
{
public:
    MyLabel(QWidget* parent);	//引入父元素
    ~MyLabel();
};

#endif // MYLABEL_H

mylabel.cpp

#include "mylabel.h"
#include<iostream>
#include<qDebug>
MyLabel::MyLabel(QWidget* parent) : QLabel(parent)
{

}

MyLabel::~MyLabel()
{
    std::cout << "MyLabel 销毁" << std::endl;
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include"mylabel.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    MyLabel* label = new MyLabel(this);
    label->setText("hello world");
}

Widget::~Widget()
{
    delete ui;
}

运行之后发现,虽然没有手动delete,但是由于将MyLabel挂到了对象树当中,销毁窗口的时候,就会自动销毁对象树中的所以对象

这里有一点,虽然输出了析构信息,但是中文部分是乱码的

在这里插入图片描述

5. 乱码问题

乱码问题的原因,有且只有一个:编码方式不匹配

计算机中,一个汉族占几个字节?

回答这个问题,先得知道当前中文编码采用的字符集。

英文采用ASCII码表,而汉族的字符集,有很多种,最主流的是两种:

  1. GBK(中国大陆较多),使用2个字节表示一个汉字

    Windows简体中文版采用的就是默认GBK

  2. UTF-8/utf8,是一种边长编码,表示一个符合使用的字节数有变化,中文一般是3字节

查看编码网站:查看字符编码(UTF-8) (mytju.com)

我们查看当前文件的编码方式为utf8

image-20240831202513741

Qt Creator出现乱码,就表明终端并不是utf8方式编码,但是也不好修改文件和终端的编码方式

要解决这个乱码问题,可以使用Qt内置的qDebug工具,这可以很好的处理字符编码问题

image-20240831202735145

后续想在Qt中通过打印日志的方式输出调试信息,优先使用qDebug

qDebug可以通过编译开关,来实现一键式打开/关闭

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

加法器+

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值