06_Qt开发基础
.pro文件的配置
跨平台配置
之前我们分别在Windows、Mac环境的Qt项目中集成了FFmpeg。
可以发现在.pro文件的配置中,FFmpeg库在Mac、Windows上的位置是有所差异的。这样就会导致.pro文件无法跨平台使用。
# windows
INCLUDEPATH += D:/SoftwareInstall/ffmpeg-4.3.2/include
# mac
INCLUDEPATH += /usr/local/Cellar/ffmpeg@4/4.4.2_3/include
为了实现跨平台配置,可以在配置前面加上平台标识的前缀,表示这个配置只会在对应的平台生效。
# windows
win32:INCLUDEPATH += D:/SoftwareInstall/ffmpeg-4.3.2/include
win32:LIBS += -LD:/SoftwareInstall/ffmpeg-4.3.2/lib \
-lavcodec \
-lavdevice \
-lavfilter \
-lavformat \
-lavutil \
-lpostproc \
-lswscale \
-lswresample
# mac
macx:INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include
macx:LIBS += -L/usr/local/Cellar/ffmpeg@4/4.4.2_3/lib \
-lavcodec \
-lavdevice \
-lavfilter \
-lavformat \
-lavutil \
-lpostproc \
-lswscale \
-lswresample \
-lavresample
# linux
# linux:INCLUDEPATH += ...
# linux:LIBS += ...
以后针对每个平台的配置可能会比较多,可以使用大括号来简化。
# windows
win32 {
INCLUDEPATH += D:/SoftwareInstall/ffmpeg-4.3.2/include
LIBS += -LD:/SoftwareInstall/ffmpeg-4.3.2/lib \
-lavcodec \
-lavdevice \
-lavfilter \
-lavformat \
-lavutil \
-lpostproc \
-lswscale \
-lswresample
}
# mac
macx {
INCLUDEPATH += /usr/local/Cellar/ffmpeg@4/4.4.2_3/include
LIBS += -L/usr/local/Cellar/ffmpeg@4/4.4.2_3/lib \
-lavcodec \
-lavdevice \
-lavfilter \
-lavformat \
-lavutil \
-lpostproc \
-lswscale \
-lswresample \
-lavresample
}
自定义变量
可以将公共的信息抽取成变量,然后使用$${}去访问。
# mac
macx {
FFMPEG_HOME = /usr/local/Cellar/ffmpeg@4/4.4.2_3
INCLUDEPATH += $${FFMPEG_HOME}/include
LIBS += -L$${FFMPEG_HOME}/lib \
-lavcodec \
-lavdevice \
-lavfilter \
-lavformat \
-lavutil \
-lpostproc \
-lswscale \
-lswresample \
-lavresample
}
读取系统环境变量
也可以通过$$()读取系统的环境变量。比如,我的Windows中有个叫做JAVA_HOME的环境变量。

# 使用message打印环境变量JAVA_HOME的值
message($$(JAVA_HOME))
最后可以在概要信息处看到JAVA_HOME的打印结果。

控件的基本使用
为了更好地学习Qt控件的使用,建议创建项目时先不要生成ui文件。

打开mainwindow.cpp,在MainWindow的构造函数中编写界面的初始化代码。
窗口设置
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) {
// 设置窗口标题
setWindowTitle("主窗口");
// 设置窗口大小
// 窗口可以通过拖拽边缘进行自由伸缩
// resize(400, 400);
// 设置窗口的固定大小
// 窗口不能通过拖拽边缘进行自由伸缩
setFixedSize(400, 400);
// 设置窗口的位置
// 以父控件的左上角为坐标原点
// 没有父控件,就以屏幕的左上角作为坐标原点
move(100, 100);
}
Qt坐标系如下图所示。

添加子控件
#include <QPushButton>
// 创建按钮
QPushButton *btn = new QPushButton;
// 设置按钮的文字
btn->setText("登录");
// 设置父控件为当前窗口
btn->setParent(this);
// 设置按钮的位置和大小
btn->move(50, 50);
btn->resize(100, 50);
// 创建第2个按钮
new QPushButton("注册", this);
new出来的Qt控件是不需要程序员手动delete的,Qt内部会自动管理内存:当父控件销毁时,会顺带销毁子控件。
信号与槽
基本使用
- 信号(Signal):比如点击按钮就会发出一个点击信号
- 槽(Slot):一般也叫槽函数,是用来处理信号的函数
- 官方文档参考:Signals & Slots

上图中的效果是:
- Object1发出信号signal1,交给Object2的槽slot1、slot2去处理
- Object1是信号的发送者,Object2是信号的接收者
- Object1发出信号signal2,交给Object4的槽slot1去处理
- Object1是信号的发送者,Object4是信号的接收者
- Object3发出信号signal1,交给Object4的槽slot3去处理
- Object3是信号的发送者,Object4是信号的接收者
- 1个信号可以由多个槽进行处理,1个槽可以处理多个信号
通过connect函数可以将信号的发送者、信号、信号的接收者、槽连接在一起。
connect(信号的发送者, 信号, 信号的接收者, 槽);
// 比如点击按钮,关闭当前窗口
// btn发出clicked信号,就会调用this的close函数
connect(btn, &QPushButton::clicked, this, &MainWindow::close);
// 可以通过disconnect断开连接
disconnect(btn, &QPushButton::clicked, this, &MainWindow::close);
自定义信号与槽
信号的发送者和接收者都必须继承自QObject,Qt中的控件最终都是继承自QObject,比如QMainWindow、QPushButton等。
信号的发送者
- sender.h
- Q_OBJECT用以支持自定义信号和槽
- 自定义的信号需要写在
signals:下面 - 自定义的信号只需要声明,不需要实现
#ifndef SENDER_H
#define SENDER_H
#include <QObject>
class Sender : public QObject {
Q_OBJECT
public:
explicit Sender(QObject *parent = nullptr);
// 自定义信号
signals:
void exit();
};
#endif // SENDER_H
- sender.cpp
#include "sender.h"
Sender::Sender(QObject *parent) : QObject(parent) {
}
信号的接收者
- receiver.h
- 自定义的槽建议写在
public slots:下面
- 自定义的槽建议写在
#ifndef RECEIVER_H
#define RECEIVER_H
#include <QObject>
class Receiver : public QObject {
Q_OBJECT
public:
explicit Receiver(QObject *parent = nullptr);
// 自定义槽
public slots:
void handleExit();
};
#endif // RECEIVER_H
- receiver.cpp
#include "receiver.h"
#include <QDebug>
Receiver::Receiver(QObject *parent) : QObject(parent) {
}
// 实现槽函数,编写处理信号的代码
void Receiver::handleExit() {
qDebug() << "Receiver::handleExit()";
}
连接
- mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
};
#endif // MAINWINDOW_H
- mainwindow.cpp
#include "mainwindow.h"
#include "sender.h"
#include "receiver.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) {
// 创建对象
Sender *sender = new Sender;
Receiver *receiver = new Receiver;
// 连接
connect(sender,
&Sender::exit,
receiver,
&Receiver::handleExit);
// 发出信号
// 最终会调用Receiver::handleExit函数
emit sender->exit();
// 销毁对象
delete sender;
delete receiver;
}
MainWindow::~MainWindow() {
}
参数和返回值
信号与槽都可以有参数和返回值:
- 发信号时的参数会传递给槽
- 槽的返回值会返回到发信号的位置
// 自定义信号
signals:
int exit(int a, int b);
// 自定义槽
public slots:
int handleExit(int a, int b);
int Receiver::handleExit(int a, int b) {
// Receiver::handleExit() 10 20
qDebug() << "Receiver::handleExit()" << a << b;
return a + b;
}
// 发出信号
int a = emit sender->exit(10, 20);
// 30
qDebug() << a;
需要注意的是:信号的参数个数必须大于等于槽的参数个数。比如下面的写法是错误的:
// 自定义信号
signals:
void exit(int a);
// 自定义槽
public slots:
void handleExit(int a, int b);
连接2个信号
比如下图,连接了Object 1的Signal 1A和Object 2的Signal 2A
- 当Object 1发出Signal 1A时,会触发Slot X、Slot Y
- 当Object 2发出Signal 2A时,只会触发Slot Y,而不会触发Slot X

可以利用connect函数连接2个信号
- 当sender发出exit信号时,sender2会发出exit2信号
- 当sender2发出exit2信号时,sender并不会发出exit信号
connect(sender,
&Sender::exit,
sender2,
&Sender2::exit2);
Lambda
也可以直接使用Lambda处理信号。
connect(sender, &Sender::exit, []() {
qDebug() << "lambda handle exit";
});
ui文件
如果你的控件是通过ui文件生成的,连接槽函数的步骤会更加简单。
首先建议给按钮们起个有意义的变量名,比如分别叫做:loginButton、registerButton。

对着登录按钮右键,选择转为槽。

选择clicked信号,然后OK。

此时,Qt Creator已经帮你自动生成了槽函数的声明和实现,当我们点击登录按钮时,就会调用这个函数。
class MainWindow : public QMainWindow {
Q_OBJECT
private slots:
// 槽函数的声明
void on_loginButton_clicked();
};
// 槽函数的实现
void MainWindow::on_loginButton_clicked() {
qDebug() << "on_loginButton_clicked";
}
其实,认真观察函数名可以发现一个规律,函数名的命名规则是:on_控件的变量名_事件名。
于是,我们可以尝试编写以下代码。
class MainWindow : public QMainWindow {
Q_OBJECT
private slots:
// 槽函数的声明
void on_registerButton_clicked();
};
// 槽函数的实现
void MainWindow::on_registerButton_clicked() {
qDebug() << "on_registerButton_clicked";
}
然后,你点击一下注册按钮,会发现成功调用了MainWindow::on_registerButton_clicked函数。
于是得知:ui文件中的控件会自动跟符合命名规则的槽函数建立连接。
最后,再提示一个知识点:ui文件中的控件可以在代码中通过ui->变量名访问。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
// 通过ui->访问ui文件中的2个按钮
ui->loginButton->setFixedSize(100, 30);
ui->registerButton->setFixedSize(100, 30);
}
06_Qt开发基础的更多相关文章
- .NET基础拾遗(5)多线程开发基础
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...
- .NET基础拾遗(6)ADO.NET与数据库开发基础
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...
- IOS开发基础知识碎片-导航
1:IOS开发基础知识--碎片1 a:NSString与NSInteger的互换 b:Objective-c中集合里面不能存放基础类型,比如int string float等,只能把它们转化成对象才可 ...
- JavaEE开发基础
1 JavaEE简介 Java平台有三个版本,分别是JavaSE(Java Platform, Standard Edition),JavaEE(Java Platform, Enterprise E ...
- ASP.Net开发基础温故知新学习笔记
申明:本文是学习2014版ASP.Net视频教程的学习笔记,仅供本人复习之用,也没有发布到博客园首页. 一.一般处理程序基础 (1)表单提交注意点: ①GET通过URL,POST通过报文体: ②需在H ...
- 从零3D基础入门XNA 4.0(1)——3D开发基础
[题外话] 最近要做一个3D动画演示的程序,由于比较熟悉C#语言,再加上XNA对模型的支持比较好,故选择了XNA平台.不过从网上找到很多XNA的入门文章,发现大都需要一些3D基础,而我之前并没有接触过 ...
- Android 开发基础及环境配置
2011年买了第一部安卓操作系统的手机,当时势头正盛的HTC不可思议(incredible),当时的想法就是想学习下智能手机开发,但是由于各种原因,客观上是公司的项目太忙了,忙于项目管理.团队建设.客 ...
- 【SharePoint学习笔记】第1章 SharePoint Foundation开发基础
SharePoint Foundation开发基础 第1章 SharePoint Foundation开发基础 SharePoint能做什么 企业信息门户 应用程序工具集(文档库.工作空间.工作流.维 ...
- JSP网站开发基础总结《一》
经过JAVASE的学习相信大家对JAVA已经不再陌生,那么JAVA都可以干什么呢?做算法.应用程序.网站开发都可以,从今天开始为大家奉上JAVAEE之JSP动态网站开发基础总结. 既然是动态网站开发, ...
- 20145212 实验四《Andoid开发基础》
20145212 实验四<Andoid开发基础> 实验内容 安装Android Studio 运行安卓AVD模拟器 使用Android运行出模拟手机并显示自己的学号 实验过程 一.安装An ...
随机推荐
- CF455D Serega and Fun 题解
题目链接:CF 或者洛谷 本题是可以用平衡树去做的,具体的为每个 \(k\) 开一棵平衡树去维护相对位置,而这种移动操作用平衡树维护又是很容易做到的,这种做法是双 \(log\).在 \(1e5\) ...
- CentOS7的udev的绑定规则
客户一套RAC环境是华为的存储,共享盘是/dev/sd*,咋一看还怀疑是没有进行多路径配置,实际和主机工程师是已经配置好的,我们使用upadmin show vlun命令可以查看到: [root@xx ...
- 2023 ASP.NET Core 开发者路线图
链接 ASP.NET Core Developer Roadmap
- 2023牛客暑期多校训练营6 ABCEG
比赛链接 A 题解 方法一 知识点:并查集,树形dp,背包dp. 因为需要路径中的最大值,因此考虑按边权从小到大加入图中,保证通过这条边产生贡献的点对已经全部出现. 在加边的同时进行树上背包,答案存在 ...
- PCIE分层结构
PCIe分层结构 绝大多数的总线或者接口,都是采用分层实现的.PCIe也不例外,它的层次结构如下: PCIe定义了下三层(彩色部分):事务层(Transaction Layer),数据链路层(Data ...
- python-web:flask框架下的html实例——用户注册页面
1.submit实现页面跳转,方法为get <h1>用户注册</h1> <!-- 使用get方式提交,method为post/get,action保存提交到哪里 --&g ...
- P1481魔族密码 题解(字典树)
魔族密码 题目背景 风之子刚走进他的考场,就-- 花花:当当当当~~偶是魅力女皇--花花!!^^(华丽出场,礼炮,鲜花) 风之子:我呕--(杀死人的眼神)快说题目!否则---_-### 题目描述 花花 ...
- 【libGDX】使用Mesh绘制立方体
1 前言 本文主要介绍使用 Mesh 绘制立方体,读者如果对 Mesh 不太熟悉,请回顾以下内容: 使用Mesh绘制三角形 使用Mesh绘制矩形 使用Mesh绘制圆形 在绘制立方体的过程中,主 ...
- 【Azure Redis】中国区Redis在东三区的资源无法在通过门户上与北三区资源之间建立灾备链接
问题描述 为应用启用灾备管理,在北三区建立了一个Azure Redis,同时,在东三区也建立了一个同样的Prem级Redis服务.但是在建立灾备(DR:Disease Recovery)时候,却无法选 ...
- 5分钟教你从爬虫到数据处理到图形化一个界面实现山西理科分数查学校-Python
5分钟教你从爬虫到数据处理到图形化一个界面实现山西理科分数查学校-Python 引言 在高考结束后,学生们面临的一大挑战是如何根据自己的分数找到合适的大学.这是一个挑战性的任务,因为它涉及大量的数据和 ...