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 addr 或 ifconfig,记录网卡(如 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 下载并安装客户端。
- 新建会话参数 :
- 协议 :选择 SFTP(推荐)或 SCP。
- 主机名:填入步骤一中获取的 Ubuntu IP 地址。
- 端口号 :默认 22(除非修改过配置)。
- 用户名/密码 :填入 Ubuntu 的登录账号及对应密码(非 root 需确认
PermitRootLogin配置)。
- 登录连接:点击"登录",首次连接会提示保存主机密钥,确认即可进入双窗格文件管理界面 。
文件传输操作
- 上传:左侧窗格选本地文件 → 右侧窗格选远程目录 → 点击工具栏"上传"或直接拖拽。
- 下载:右侧窗格选远程文件 → 左侧窗格选本地目录 → 点击工具栏"下载"或直接拖拽。
- 编码设置 :若文件名乱码,进入"选项"→"首选项"→"环境",将文件名编码设为 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