四、关于Qt项目需要知道的

1、创建第一个Qt项目:

以上的先了解以下,其它的先不说,暂时用不到。

我们创建第一个项目的时候怎么选?

从上图看出,这里要说明的是:

QMainWindow就是一个窗口,如下:

QWidget就是一个空白窗口,如下:

QDialog一般有几个按钮,比如确认,OK,取消按钮,如下:

创建完成我们进行运行,可能会报错。那怎么办?

这是什么原因导致的?

答:在 Ubuntu 下刚装的 Qt Creator,毫无意外,第一次编译时会报"Cannot find -lgL"的错误。由于 Qt5.0 的库默认会链接到 OpenGL,但是在 Ubuntu 机器上没有安装 OpenGL, 所以们需要在 Ubuntu 下安装 OpenGL Library。在 Ubuntu 终端下输入如下指令。

复制代码
sudo apt-get install libglu1-mesa-dev

安装完成后,我们再点击左下角的绿色三角形试试,可以看到如下结果,是一个空白窗口!

(如果还有错误,就需要百度查资料或者问AI或者请教身边大神,一般情况下相信一定会解决掉的!)

2、项目文件介绍:

怎么添加其它模块?

这里以添加网络模块为例:

以下需要知道的:

复制代码
QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets //比Qt4版本高的话要加上widgets 模块

CONFIG += c++11  //C++11是一个标准

# 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 //一般大写字母的都是Qt的宏定义,上面的注释的意思是编译器或者GUI提醒你API过时了,会建议你使用新的API

# 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 \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.//默认的部署规则
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

以下是在linux-Ubuntu中两种方法执行Qt文件:

第一种是在Qt中直接点击绿色三角或者"ctrl+r"快捷键

另一种是,如下图:

如果我们想修改这个项目产物的名字,怎么改?

然后直接再.pro文件里改(TARGET就是目标产物的名字):

然后在项目里执行一下("ctrl+r"快捷键);

执行之后窗体出现。

3、Qt程序启动流程分析

这里着重研究好以下文件内的代码:

复制代码
//mywindow.h
#ifndef MYWINDOW_H
#define MYWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MyWindow; }
QT_END_NAMESPACE

class MyWindow : public QMainWindow
{
    //宏定义,Qt信号槽需要它
    Q_OBJECT

public:
    MyWindow(QWidget *parent = nullptr);
    ~MyWindow();
    int i;

private:
    Ui::MyWindow *ui;
};
#endif // MYWINDOW_H

//main.cpp
#include "mywindow.h"

#include <QApplication>

//程序入口
int main(int argc, char *argv[])
{
    //argc是命令行参数个数,argv是命令行参数
    //QApplication a(argc, argv),管理Qt程序的运行,和设置Qt应用程序,针对QWidget应用程序
    //QGuiApplication a(argc, argv),管理Qt程序的运行,和设置Qt应用程序,针对非QWidget应用程序,比如QQuick
    //QCoreApplication a(argc, argv),管理Qt程序的运行,和设置Qt应用程序,针对无界面应用程序
    QApplication a(argc, argv);
    //MyWindow是我们自定义的类,w是创建的对象
    MyWindow w;
    //w对象调用了show()方法
    w.show();
    //事件循环,QEvenLoop::exec(),等待鼠标和键盘等其他的输入
    return a.exec();
}

//mywindow.h
#include "mywindow.h"
#include "ui_mywindow.h"
#include <QDebug>

MyWindow::MyWindow(QWidget *parent)
    : QMainWindow(parent)
    , i(4)// i = 4 这里要放在这个位置(ui之前)
    , ui(new Ui::MyWindow)// ui = new Ui::MyWindows
{
    //也可以在这里初始化
    //i = 4;
    ui->setupUi(this);

    qDebug() << "构造函数执行了!" << endl;
}

MyWindow::~MyWindow()
{
    qDebug() << "析构函数执行了!" << endl;
    delete ui;
}

4、Qt Creator常用快捷键(要经常用经常记):

查看某个类的帮助文档快捷键: F1(鼠标指向那个类然后按F1)
新建项目Ctrl+n
运行项目Ctrl+r
构建项目Ctrl+b
对齐整页代码:先ctrl+a再ctrl+i
对齐本段代码:ctrl+i
跳转到上一行:ctrl+shift+enter
跳转到下一行:ctrl+enter
向上移动行:ctrl+shift+⬆️
向下移动行:ctrl+shift+⬇️
复制当前行到上一行:ctrl+shift+Pageup(原快捷键与系统..冲突需自己设置 工具-选项-环境-键盘里面设置)
复制当前行到下一行:ctrl+shift+Pageup(原快捷键与系统..冲突需自己设置 工具-选项-环境-键盘里面设置)
查看类的层次结构图:鼠标放在类上,ctrl+shift+t
查看方法:按住ctrl键,点击它
头文件与源文件切换:F4
声明函数后怎么快速添加定义:右键它-Refactor-在mainwindow.cpp添加定义

5、Qt编程规范

文件命名都是小写字母的。

这里补充下怎么打开mainwindows类的源文件:

类的名字首写字母都是大写的。

除了构造函数和析构函数,成员函数首写字母都是小写,单词和单词之间首写字母是大写的。

成员变量首写字母都是小写,单词和单词之间首写字母是大写的。

参数和参数之间要加空格,形参和实参之间的空格严格遵照,一美观,二否则太紧凑。

当判断语句后面只有一行代码的时候不需要花括号。有多行代码是,第一个大括号最好与判断语句在一行,空一格。

6、UI设计器的简单使用

Qt的坐标系统,左上角是(0,0),右方向是x轴,下方向是y轴。

嵌入式的屏最小一般是(800,480).

运行之后弹出的屏幕会是随机的。但是我们使用UI设计器发现x和y事不能修改的。也就说明它就是随机的。其实我们可以用代码来修改它显示的位置。(怎么修改这里先留个悬念哈哈)

7、使用Qt的信号槽

信号槽的连接模型:

如何使用UI设计器实现一个按钮点击之后关闭窗口的操作?(也就是实现一个信号槽的连接)

还有一种实现的方法:

以上这两种方法实际上是同一种方法;下面会介绍另一种方法:

右键点击按钮-转到槽-选中clicked()-会自动跳转,我们编辑这个槽函数即可实现(下面是我们编辑的内容)

这里要注意:要想使用qDebug()需要提前在函数头文件声明#include <QDebug>

另外:下面的代码是.h文件里自动生成的:

8、如何用代码实现信号槽?

复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QObject::connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(close()));
}

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

要注意的是:我们可以省略限定符QObject,因为所有的Qt的类都继承QObject类,所以可以省略。

9、自定义信号槽

当Qt中的信号和槽不满足我们时,我们就会自定义信号和槽。以及我们还要明白信号槽的连接规则。

这里接触一个新的创建文件的方法,也就是创建类,这里创建了两个类,一个是School一个是Student。

下面统一成一个步骤:

先Ctrl+N,跳出来

School类已经创建好了,同理创建Student类。

创建完成之后:

学校是发生者,通知是信号,学生是接收者,上课是槽。通知这个信号是属于学校里面的,上课这个槽是属于学生的。下面开始写程序:

我把需要修改的文件的代码附出来(最好看源代码)

cpp 复制代码
//school.h
#ifndef SCHOOL_H
#define SCHOOL_H

#include <QObject>

class School : public QObject
{
    Q_OBJECT
public:
    explicit School(QObject *parent = nullptr);

signals://Qt信号的关键词 自定义的信号,只声明可以不用定义
    void sendMessage();

};

#endif // SCHOOL_H
cpp 复制代码
//student.h
#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject
{
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);

signals:
public slots://自定义的槽
    //声明后还需要定义
    void comeBackToClass();

};

#endif // STUDENT_H
cpp 复制代码
//mianwidow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "school.h"
#include "student.h"

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class School;
class Student;

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private:
    Ui::MainWindow *ui;
    School *school;//声明对象
    Student *student;//声明对象
};
#endif // MAINWINDOW_H
cpp 复制代码
//student.cpp
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{

}

void Student::comeBackToClass()
{
    qDebug() << "学生上课" << endl;
}
cpp 复制代码
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    school = new School(this);//实例化对象
    student = new Student(this);//实例化对象

    connect(school, SIGNAL(sendMessage()), student, SLOT(comeBackToClass()));
    //emit是发送信号的关键字
    emit school->sendMessage();
}

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

槽需要用public private protected修饰。

下面的内容也是要了解的:

一个信号可以连接多个槽。

可以使用上面的程序演示:

cpp 复制代码
    connect(school, SIGNAL(sendMessage()), student, SLOT(comeBackToClass()));
    connect(school, SIGNAL(sendMessage()), this, SLOT(hide()));

多个信号可以连接同一个槽。

cpp 复制代码
    connect(school, SIGNAL(sendMessage()), student, SLOT(comeBackToClass()));
    connect(school, SIGNAL(sendMessage2()), student, SLOT(comeBackToClass()));

一个信号可以连接另外一个信号。

cpp 复制代码
    connect(school, SIGNAL(sendMessage2()), this, SIGNAL(iconSizeChanged()));

10、如何通过代码的方式实现界面并实例化一个按钮?(这将会为为后面的内容打好基础)

实现的功能有:

1)设置一个按钮;

2)设置按钮上的文本、位置、大小

2)设置主窗口的大小

实现步骤如下:

新建文件时,取消勾选Generate form。

由.h文件可知,MainWindow是继承QMainWindow,QMainWindow是一个界面类,是一个空白的窗口(其实是有菜单栏和状态栏的只是没有显示)。

我们通过帮助文档,找到QPushButton的使用说明。可知我们使用这个类要声明头文件。所以我们在.h文件中把他的头文件添加进去。我们还看到,qmake还要+widget,由于已经加进去了,所以不用加了。

我们参考它的使用实例:

复制代码
QPushButton *button = new QPushButton("&Download", this);
   类         对象   

实现代码如下:

cpp 复制代码
//mianwindows.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    QPushButton *pushButton;//我们要使用一个类要先声明类的对象

};
#endif // MAINWINDOW_H

//mianwindows.cpp
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    pushButton = new QPushButton(this);//不加参数也可以,因为有一个重载函数默认参数为空
    pushButton->setText("我是一个按钮");//设置按钮的文本
    pushButton->setGeometry(50, 150, 100, 50);//设置按钮的位置和大小
    this->resize(800, 480);//设置主窗口的大小
}

MainWindow::~MainWindow()
{
}

//main.cpp
#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;//MainWindow实例化对象w,就会执行w的构造函数
    w.show();
    return a.exec();
}

11、Qt的Object Tree(对象树)

设置父对象的两种方法:

1.通过构造函数传参(其实它最终也是调用了setParent()方法)

2.通过setParent()方法

Qt的对象树机制:

主要代码如下:

这里创建的工程是继承Widget,还创建了一个类

cpp 复制代码
//mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>

class MyWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MyWidget(QWidget *parent = nullptr);
    ~MyWidget();//析构函数
signals:

};

//widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QPushButton>
#include <QWidget>
#include <mywidget.h>

class MyWidget;
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    QPushButton *pushButton;
    MyWidget *myWidget;
};
#endif // WIDGET_H

//mywidget.cpp
#include "mywidget.h"
#include <QDebug>

MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{

}

MyWidget::~MyWidget()
{
    qDebug() << "MyWidget类的析构函数执行了" << endl;
}

//widget.cpp
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //为什么要设置父对象?因为窗口需要互相联系
    //比如A要显示在B的上面,A需要指定B作为父对象
    //pushButton = new QPushButton(this);//这是设置父对象的第一种方法
    pushButton = new QPushButton;
    pushButton->setParent(this);//这是设置父对象的第二种方法
    //总结:设置父对象的两种方法:
    //1.通过构造函数传参(其实它最终也是调用了setParent()方法)
    //2.通过setParent()方法

    //Qt的对象树机制目的就是方便管理内存
    myWidget = new MyWidget(this);

}

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

//main.cpp
#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

Qt的对象树机制目的就是方便内存管理。假设不指定父对象,而是一直创建对象,这样的话他只有在程序结束后由系统回收,如果一些开发板或者一些平台内存比较小,这样很容易造成内存泄漏。

12、怎么在Qt项目中添加资源文件?

有时候我们会用到图片或者图标,这些都是资源文件。

在配置资源文件之前,我们要在新装的Ubuntu18需要做以下配置:

将Ubuntu网络设置为桥接模式

sudo apt-get update //更新列表

sudo apt-get install net-tools (UBuntu18)

sudo apt-get install openssh-server

使用WinScp或者FileZilla传输文件

如何配置Ubuntu传输文件?

Ubuntu 虚拟机:先安装SSH服务端,打开终端执行:

cpp 复制代码
sudo apt update && sudo apt install openssh-server

启动并验证服务 ‌:执行 sudo systemctl status ssh,确认显示 active (running);若未运行则执行 sudo systemctl start ssh

获取 IP 地址 ‌:执行 ip addrifconfig,记录网卡(如 eth0 或 ens33)对应的 IPv4 地址(例如 192.168.x.x)。如果执行失败看看是什么意思(可能要先安装net-tools,执行指令是:sudo apt install net-tools)

检查防火墙/网络模式 ‌:确保虚拟机网络适配器设为‌桥接模式 ‌或‌NAT 模式 ‌(能与宿主机 ping 通),若开启 UFW 防火墙需执行 sudo ufw allow ssh

确认网络模式‌:确保虚拟机网络设置(NAT/桥接)能使宿主机 Ping 通该 IP,否则需调整虚拟机网络适配器设置

以上执行后需要重启,确保虚拟机IP与主机IP在一个网段。

Windows 宿主机端操作(WinSCP 配置)

下载安装 ‌:从官网 WinSCP 下载并安装客户端。

  1. 新建会话参数 ‌:
    • 协议 ‌:选择 ‌SFTP‌(推荐)或 SCP。
    • 主机名‌:填入步骤一中获取的 Ubuntu IP 地址。
    • 端口号 ‌:默认 ‌22‌(除非修改过配置)。
    • 用户名/密码 ‌:填入 Ubuntu 的登录账号及对应密码(非 root 需确认 PermitRootLogin 配置)。
  2. 登录连接‌:点击"登录",首次连接会提示保存主机密钥,确认即可进入双窗格文件管理界面 。‌‌

文件传输操作

  • 上传‌:左侧窗格选本地文件 → 右侧窗格选远程目录 → 点击工具栏"上传"或直接拖拽。
  • 下载‌:右侧窗格选远程文件 → 左侧窗格选本地目录 → 点击工具栏"下载"或直接拖拽。
  • 编码设置 ‌:若文件名乱码,进入"选项"→"首选项"→"环境",将文件名编码设为 ‌UTF-8‌ 。‌‌

首先将logo.png从桌面拖到项目文件夹根目录下,

然后在项目中新建:

资源文件的后缀是qrc

添加前缀:

添加文件,双击那个文件

保存ctrl+s之后可以看到:

13、样式表的使用

Qt样式表是一种强大的Qt机制,它允许自定义小部件的外观。Qt样式表的概念、术语和语法HTML层叠样式表(CSS)类似。

修改Label的文本、字体颜色和字体大小:

点击添加资源:

这时是这样的一个效果:

我们修改成铺满整个Label,怎么修改呢?只需要修改这里:

我们还要修改文字,直接双击文本即可修改。

我们还要修改文字颜色和文字大小:

最后的执行效果图如下:

以上内容就是样式表的使用,我们要知道帮助文档怎么检索和使用!

14、qss文件的使用

我们重新建一个项目:

修改主窗口的背景颜色-红色:

很多情况下我们没有使用.ui文件那么我们怎么设置样式表呢?

实现效果是:

我们可以使用qss文件就是样式表文件:

QSS 文件是使用 Qt 程序相关联的样式表文件。它由 GUI 元素的外观和感觉,包括布局,颜色,鼠标的行为,大小和字体。它的风格,一个可以合并到一个 UI(用户界面)。 与 HTML 的 CSS 类似, Qt 的样式表是纯文本的格式定义,在应用程序运行时可以载入和解析这些样式定义,从而使应用程序的界面呈现不同的效果。

添加qss文件可以参看下面的步骤:

这里由于我们之前没有添加资源文件,我们要重新添加一下,添加好之后就添加qss文件:

直接下一步到完成。

在Qt项目里使用qss文件,我们要用下面的模板代码来读取:

cpp 复制代码
QFile file(":/style.qss");
/* 判断文件是否存在 */
if (file.exists() ) {
/* 以只读的方式打开 */
file.open(QFile::ReadOnly);
/* 以字符串的方式保存读出的结果 */
QString styleSheet = QLatin1String(file.readAll());
/* 设置全局样式 */
qApp->setStyleSheet(styleSheet);
/* 关闭文件 */
file.close();
}

那么我们怎么做呢?

首先原来的这两行代码(位于widget.cpp)需要注释掉(其实通过指向的意思也可以看出来):

cpp 复制代码
//this->setStyleSheet("QWidget {background-color:blue}");//主窗口的背景颜色
//label->setStyleSheet("QLabel {background-color:red}");//按钮的背景颜色

我们把它里面引号的内容COPY到qss文件里,如下:

cpp 复制代码
QWidget {background-color:blue}
QLabel {background-color:red}

然后将将刚刚的代码COPY到main.cpp里面,如下:

cpp 复制代码
#include <QApplication>
#include <QFile> 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QFile file(":/style.qss");
    /* 判断文件是否存在 */
    if (file.exists() ) {
        /* 以只读的方式打开 */
        file.open(QFile::ReadOnly);
        /* 以字符串的方式保存读出的结果 */
        QString styleSheet = QLatin1String(file.readAll());
        /* 设置全局样式 */
        qApp->setStyleSheet(styleSheet);
        /* 关闭文件 */
        file.close();
    }

    Widget w;
    w.show();
    return a.exec();
}

我们可以看到:这段内容需要COPY到 Widget w;代码之前,要理解其用意--也就是说在窗口显示之前(或者COPY到构造函数这里也是可以的)。

其中 QFile file(":/style.qss");引号的内容是路径,可以这样获取:

最后实现的效果图如下(另外要注意qss文件里不允许使用//符号来注释内容):

另外我们还想实现再添加一个label,与它的原先那个label有不同的样式那怎么修改呢,效果又是怎样的?我们先看下效果:

需要修改的地方:

在构造函数里面添加一个label2:

cpp 复制代码
    QLabel *label2 = new QLabel(this);//定义label2,放在父类上
    label2->setGeometry(100, 100, 100, 100);//按钮的大小
    label2->setObjectName("label2");

在qss文件里最后一行添加(我们留意下符号**#**是怎么使用的):

cpp 复制代码
QLabel#label2 {background-color:green}

这样就能实现上面的效果。

结语:如果使用样式表的地方非常多的话建议使用qss文件,这样子我们的代码看起来就不会那么臃肿。使用比较少也可以不用qss文件。


下面内容是一些小的知识点:

1.怎么添加网络模块(QtNetwork)?

先在.pro文件里修改

复制代码
QT       += core gui
修改为
QT       += core gui network

然后在mainwidows.h中引用该类:

复制代码
#include <QtNetwork>
网络模块的头文件有很多还可以是:
#Include <QnetworkAccessManager>

2.我在准备使用WinScp 互传文件时发现Ubuntu遇到无法连接网络,是怎么解决的?(实测有效)

VMware 虚拟网络重置

① 虚拟机完全关机(不要挂起)

② VMware顶部菜单 → 编辑 → 虚拟网络编辑器 → 更改设置

③ 选中 VMnet8(NAT) → 点【还原默认设置】,等待重置完成

虚拟机网卡设置

虚拟机设置 → 网络适配器

✅ 网络模式:NAT模式(不要桥接/仅主机)

✅ 勾选:已连接、启动时连接

随后重启虚拟机。可以打开终端测试ifconfig,看到有IP地址说明已经链接OK


相关推荐
程序喵大人2 小时前
【C++进阶】STL算法与函数对象 - 02 sort为什么需要随机访问迭代器
开发语言·c++·算法
hanlin032 小时前
动态规划专练:力扣第121、122题
笔记·算法·leetcode
SomeB1oody2 小时前
【RustyML入门】2.6. 线性判别分析
开发语言·后端·机器学习·rust·教程
摇滚侠3 小时前
SpringBoot 官网 阅读笔记 启用生产就绪功能 端点
spring boot·笔记·后端
用户昵称1003 小时前
C/C++编程-工程实践-本地存储log的工程意义
c语言·开发语言
AI云海3 小时前
完整机器学习工业项目流水线笔记
人工智能·笔记·机器学习
2601_965799683 小时前
2026 在线笔试平台深度测评与选型指南:从功能、稳定性、AI能力、防作弊全面分析
人工智能·笔记·功能测试
xqqxqxxq3 小时前
SQL 连接查询技术笔记
数据库·笔记·sql
吹什么轩4 小时前
c++复习:map和set的使用
开发语言·c++