1.Qt是什么
Qt 是一个跨平台的 C++ 开发框架,用于开发桌面、移动和嵌入式设备的应用程序
C++ 开发框架是为简化和加速 C++ 应用程序开发而设计的一组工具、库和预定义的代码结构。它为开发者提供了一种标准化的方式来组织代码、管理资源、处理常见任务(如网络通信、图形用户界面设计、数据存储等),从而减少重复工作,提高开发效率和代码质量。
2.常见Qt模块
Qt 模块是 Qt 框架的核心组成部分,每个模块都提供了一组特定的功能和类,用于支持不同的开发需求。Qt 的模块化设计使得开发者可以根据项目需求选择性地使用所需的模块,从而优化应用程序的性能和资源占用。以下是一些常见的 Qt 模块及其功能:
1. Qt Core
-
功能:提供 Qt 框架的基础功能,包括数据结构、线程支持、国际化、文件和 I/O 操作等。
-
关键类:
-
QObject
:Qt 的核心类,所有其他 Qt 类的基类,提供信号与槽机制。 -
QString
:用于处理 Unicode 字符串。 -
QThread
:用于多线程编程。 -
QTimer
:用于定时器操作。
-
-
用途:几乎所有 Qt 应用程序都需要使用 Qt Core 模块。
2. Qt GUI
-
功能:提供图形用户界面相关的功能,包括窗口、控件、事件处理、绘图等。
-
关键类:
-
QWidget
:所有 GUI 控件的基类。 -
QPainter
:用于绘图操作。 -
QImage
:用于处理图像。 -
QColor
:用于颜色管理。
-
-
用途:用于开发具有图形用户界面的应用程序。
3. Qt Widgets
-
功能:提供一组丰富的 GUI 控件,如按钮、文本框、列表框等。
-
关键类:
-
QPushButton
:按钮控件。 -
QLineEdit
:单行文本输入框。 -
QLabel
:用于显示文本或图片。 -
QTableWidget
:表格控件。
-
-
用途:用于快速开发传统风格的桌面应用程序。
4. Qt Network
-
功能:提供网络编程支持,包括 TCP/UDP 通信、HTTP 客户端和服务器等。
-
关键类:
-
QTcpSocket
:用于 TCP 通信。 -
QUdpSocket
:用于 UDP 通信。 -
QNetworkAccessManager
:用于 HTTP 请求。
-
-
用途:用于开发需要网络功能的应用程序,如客户端/服务器应用程序。
5. Qt SQL
-
功能:提供数据库访问支持,支持多种数据库(如 MySQL、SQLite、PostgreSQL 等)。
-
关键类:
-
QSqlDatabase
:用于管理数据库连接。 -
QSqlQuery
:用于执行 SQL 查询。 -
QSqlTableModel
:用于数据模型。
-
-
用途:用于开发需要数据库支持的应用程序。
6. Qt Multimedia
-
功能:提供多媒体支持,包括音频、视频播放和录制。
-
关键类:
-
QMediaPlayer
:用于播放音频和视频。 -
QCamera
:用于摄像头操作。
-
-
用途:用于开发多媒体应用程序,如视频播放器、音频编辑器。
3.Qt基础知识
1.Qt坐标体系
Qt 框架中的坐标体系采用计算机坐标系(左手坐标系),其中坐标系的原点(0,0)是屏幕的左上角。对于控件来说,坐标原点是相对于父窗口或控件的。
2.Qt内存回收机制
Qt中有内存的自动回收机制,来防止在堆上通过new申请的内存没有释放而导致内存泄漏,但是不是所有对象的内存都会被自动回收,需要满足以下两个条件:
-
创建的对象必须是QObject的子类(间接子类也可以)。
-
创建出的类对象,必须要指定其父对象是谁。
4.Qt使用
1.使用类必须添加头文件,头文件名是类名
2.QApplication
QApplication
是 Qt 应用程序的入口点,它负责管理应用程序的控制流和其他方面的设置。在任何 Qt 应用程序中,QApplication
对象都是必不可少的,因为它负责初始化和清理 Qt 的核心功能,如事件循环、主线程设置、字体设置、翻译支持等。
#include <QApplication>
#include <QWidget>
int main(int argc, char *argv[])
{
QApplication app(argc, argv); // 创建 QApplication 对象
QWidget window; // 创建一个窗口
window.resize(250, 150); // 设置窗口大小
window.setWindowTitle("Hello Qt"); // 设置窗口标题
window.show(); // 显示窗口
//阻塞函数,进入事件循环
return app.exec(); // 进入事件循环
}
5.信号槽
信号(Signal)和槽(Slot)是 Qt 框架中用于实现对象间通信的核心机制。它们提供了一种非常灵活、解耦的方式,用于在对象之间传递消息、触发事件以及响应事件。
1. 基本概念
信号(Signal)
-
定义:信号是 Qt 对象发出的消息,表示某个事件已经发生。例如,按钮被点击、窗口被关闭、数据更新等。
-
特点:
-
信号由 Qt 的元对象系统(Meta-Object System)管理。
-
信号通常在某个事件发生时自动发出,例如,
QPushButton
的clicked()
信号在按钮被点击时发出。 -
信号的定义类似于函数声明,但它本身不包含实现代码。信号的发出由 Qt 的事件处理机制自动完成。
-
槽(Slot)
-
定义:槽是对象中可以被信号触发的函数。槽本质上是一个普通的成员函数,但它可以被信号连接到。
-
特点:
-
槽可以是普通的成员函数,也可以是
public
、protected
或private
的。 -
当信号被发出时,与该信号连接的槽函数会被自动调用。
-
槽可以有参数,这些参数由信号提供。
-
2. 信号和槽的连接
信号和槽之间的连接是通过 QObject::connect()
函数完成的。推荐使用基于函数指针的连接方式
1.标准信号槽
#include <QApplication>
#include <QPushButton>
#include <QDebug>
class MyWindow : public QObject {
Q_OBJECT
public:
MyWindow() {
// 创建一个按钮
QPushButton* button = new QPushButton("点击我", nullptr);
// 将按钮的点击信号(clicked)连接到自定义的槽函数(onButtonClicked)
QObject::connect(button, &QPushButton::clicked, this, &MyWindow::onButtonClicked);
// 显示按钮
button->show();
}
public slots:
void onButtonClicked() {
// 按钮点击时触发的槽函数
qDebug() << "按钮被点击了!";
}
};
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
// 创建窗口对象
MyWindow window;
// 运行应用程序
return app.exec();
}
2.自定义信号槽
子类必须继承QObject
必须添加Q_Object宏
信号函数返回值必须void,信号需要使用signals关键字声明(不需要定义),习惯性在信号函数前添加emit(声明被发送)
#include <QCoreApplication>
#include <QDebug>
class Sender : public QObject {
Q_OBJECT
public:
Sender() {}
signals:
void signal1();
void signal2();
};
class Receiver : public QObject {
Q_OBJECT
public:
Receiver() {}
public slots:
void slot1() {
qDebug() << "Slot1 called";
emit signal2(); // 在槽函数中发射另一个信号
}
void slot2() {
qDebug() << "Slot2 called";
}
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
Sender sender;
Receiver receiver;
// 连接信号与槽
QObject::connect(&sender, &Sender::signal1, &receiver, &Receiver::slot1);
QObject::connect(&receiver, &Receiver::signal2, &receiver, &Receiver::slot2);
// 发射信号
sender.signal1(); // 触发slot1,slot1中又发射signal2,触发slot2
return a.exec();
}
在 Qt 的 connect()
语法中,传递限定作用域的非静态成员函数指针,在 C++ 中,成员函数指针必须明确指定所属类,即 &monitor::MonitorWidget::ClickCpuButton
而不是 &ClickCpuButton
。
3.回调(Callback)与信号槽(Signal and Slot)的关系
1. 回调(Callback)的定义
回调是一种编程技术,其中一个函数(称为回调函数)被传递给另一个函数,以便在特定事件发生时被调用。回调函数通常用于实现异步操作、事件处理或通知机制。
2. 信号槽与回调的关系
信号槽机制本质上是一种特殊的回调机制,但它是专门为 Qt 框架设计的,用于实现对象之间的通信。信号和槽通过 Qt 的元对象系统(Meta-Object System)进行管理和连接。
6.常见类的使用
***关系图***
QObject
|
|-- QAbstractItemModel
| |
| |-- QAbstractTableModel
|
|-- QWidget
|
|-- QTableView
|
|-- QPushButton
|
|-- QLabel
|
|-- QLayout
|
|-- QGridLayout
|
|-- QHBoxLayout
|
|-- QStackedLayout
1.QWidget
QWidget
是所有用户界面控件的基类。几乎所有可见的GUI(Graphical User Interface,图形用户界面)
对象(如窗口、按钮、标签、文本框等)都是 QWidget
的子类。QWidget
提供了基本的窗口系统功能,包括绘制、事件处理、布局管理等。
1.QWidget
的主要功能
-
窗口和控件的基础:
-
QWidget
是所有 GUI 控件的基类,例如QPushButton
、QLabel
、QLineEdit
等都是从QWidget
派生而来。 -
它提供了窗口的基本功能,如设置窗口标题、大小、图标等。
-
-
事件处理:
-
QWidget
提供了事件处理机制,可以处理各种事件,如鼠标事件、键盘事件、绘制事件等。 -
通过重写事件处理函数(如
paintEvent
、mousePressEvent
等),可以自定义控件的行为和外观。
-
-
布局管理:
-
QWidget
支持布局管理器(如QHBoxLayout
、QVBoxLayout
、QGridLayout
等),用于自动排列子控件。 -
布局管理器可以确保控件在窗口大小改变时自动调整位置和大小。
-
-
绘制功能:
-
QWidget
提供了绘制功能,通过paintEvent
可以自定义控件的外观。 -
使用
QPainter
对象可以在控件上绘制图形、文本、图片等。
-
-
窗口属性:
-
QWidget
提供了设置窗口属性的函数,如setWindowTitle
、setWindowIcon
、setGeometry
等。 -
还可以设置窗口的透明度、窗口样式等。
-
-
子控件管理:
-
QWidget
可以包含多个子控件,通过setLayout
和addWidget
等方法可以管理子控件的布局。 -
子控件的显示和隐藏可以通过
show
和hide
方法控制。
-
2.创建QWidget实例
// MonitorWidget.h
#ifndef MONITORWIDGET_H
#define MONITORWIDGET_H
#include <QWidget>
class MonitorWidget : public QWidget {
Q_OBJECT
public:
explicit MonitorWidget(QWidget* parent = nullptr);
~MonitorWidget();
};
#endif // MONITORWIDGET_H
#include <QWidget>
#include <QPainter>
#include <QApplication>
class MyWidget : public QWidget {
protected:
void paintEvent(QPaintEvent *event) override {
QPainter painter(this);
painter.setPen(Qt::red);
painter.drawRect(10, 10, 100, 100);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyWidget widget;
// 1.指针操作
// MyWidget* w = new MyWidget(this);
widget.setWindowTitle("My QWidget Example");
widget.resize(300, 300);
widget.show(); // 2.创建独立窗口必须show,否则是内嵌的(没有边框)
return app.exec();
}
2.QVariant
QVariant
是 Qt 框架中一个非常重要的类,用于存储和操作多种数据类型的值。对各种数据进行打包形成QVarient::(Type)类型
以下是 QVariant
常用的函数:
1.类型检查
-
QVariant::type()
:获取存储的数据类型。 -
QVariant::canConvert<T>()
:检查是否可以安全地转换为指定类型。
2.类型转换
-
QVariant::toInt()
:将数据转换为int
。 -
QVariant::toDouble()
:将数据转换为double
。 -
QVariant::toString()
:将数据转换为QString
。 -
QVariant::toList()
:将数据转换为QVariantList
。 -
QVariant::toMap()
:将数据转换为QVariantMap
。
3.存储和赋值
-
QVariant::fromValue<T>()
:将任意类型的数据存储到QVariant
中。 -
QVariant::value<T>()
:从QVariant
中提取指定类型的值。
4.其他
-
QVariant::isNull()
:检查值是否为空。 -
QVariant::isValid()
:检查值是否有效。 -
QVariant::clear()
:清空存储的值。
3.QString
构造函数
-
默认构造:
QString str;
,创建一个空字符串。 -
从C++字符串构造:
QString str = "Hello";
,直接用双引号字符串初始化。 -
从其他类型构造:
QString str = QString::number(42);
,将数字等其他类型转换为字符串。
数据操作
-
拼接:
-
+
:QString str = "Hello" + "World";
,结果是"HelloWorld"
。 -
append()
或+=
:str.append(" World");
或str += " World";
,在字符串后追加内容。
-
-
QString::fromStdString
是一个静态成员函数,用于将std::string
转换为QString
。这是在 Qt 和标准 C++ 库之间进行字符串转换时非常有用的方法。QString QString::fromStdString(const std::string& str)
4.QAbstractTableModel:为QTableView提供数据
QAbstractItemModel
的派生类中的方法(如 rowCount
、columnCount
、headerData
和 data
)是由视图(如 QTableView
、QListView
等)调用的。这些方法的目的是为视图提供必要的数据,以便正确显示和操作模型中的数据。
以下是实例化QAbstractTableModel必须要重写的函数(为QTableView提供获取数据的方法)
1. data(const QModelIndex &index, int role = Qt::DisplayRole) const
作用:返回指定索引和角色的数据。
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
if (!index.isValid() || role != Qt::DisplayRole) return QVariant();
return dataList[index.row()][index.column()];
}
QVariant MonitorInterModel::data(const QModelIndex &index, int role) const {
if (role == Qt::TextAlignmentRole) {
return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
}
if (role == Qt::TextColorRole) {
return QVariant::fromValue(QColor(Qt::black));
}
if (role == Qt::BackgroundRole) {
return QVariant::fromValue(QColor(Qt::white));
}
return QVariant();
}
2. rowCount(const QModelIndex &parent = QModelIndex()) const
作用:返回模型的行数。
int rowCount(const QModelIndex &parent = QModelIndex()) const override {
if (parent.isValid()) return 0;
return dataList.size();
}
3. columnCount(const QModelIndex &parent = QModelIndex()) const
作用:返回模型的列数。
int columnCount(const QModelIndex &parent = QModelIndex()) const override {
if (parent.isValid()) return 0;
return dataList.isEmpty() ? 0 : dataList[0].size();
}
4. headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
作用:返回表头数据。
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override {
if (role != Qt::DisplayRole) return QVariant();
if (orientation == Qt::Horizontal) {
switch (section) {
case 0: return "Name";
case 1: return "Age";
case 2: return "Occupation";
}
}
return QVariant();
}
QVariant MonitorInterModel::headerData(int section, Qt::Orientation orientation,
int role) const {
if (role == Qt::FontRole) {
return QVariant::fromValue(QFont("Microsoft YaHei", 10, QFont::Bold));
}
if (role == Qt::BackgroundRole) {
return QVariant::fromValue(QColor(Qt::lightGray));
}
return QAbstractTableModel::headerData(section, orientation, role);
}
5.为什么需要 beginResetModel()
和 endResetModel()
?
在模型中进行大规模数据更新(如清空所有数据并重新加载)时,直接修改数据会导致视图的状态与模型的状态不一致。为了避免这种情况,需要在修改数据之前调用 beginResetModel()
,在修改数据之后调用 endResetModel()
。这两个函数的作用如下:
void CpuLoadModel::UpdateMonitorInfo(
const monitor::proto::MonitorInfo& monitor_info) {
beginResetModel();
monitor_data_.clear();
monitor_data_.push_back(insert_one_cpu_load(monitor_info.cpu_load()));
endResetModel();
return;
}
5.QModelIndex
QModelIndex
是 Qt 框架中用于表示模型中数据项位置的类。它是 QAbstractItemModel
的一部分,用于在视图(如 QTableView
、QTreeView
、QListView
等)和模型之间进行交互。QModelIndex
包含了行号、列号、父索引等信息,可以唯一标识模型中的一个数据项。
以下是关于 QModelIndex
的简洁介绍和常用操作示例:
1. 构造函数
QModelIndex(); // 创建一个无效的索引
QModelIndex(int row, int column, QObject* parent = nullptr); // 创建一个有效的索引
2. 获取索引信息
int row() const; // 获取行号
int column() const; // 获取列号
QModelIndex parent() const; // 获取父索引
3. 检查索引有效性
bool isValid() const; // 检查索引是否有效
6.QTableView:以表格形式显示数据
setModel(QAbstractItemModel *model)
作用:将模型与表格视图关联。
QTableView *tableView = new QTableView();
MyTableModel *model = new MyTableModel();
tableView->setModel(model); // 设置模型
7.QPushButton:创建按钮的类
1. setText(const QString &text)
作用:设置按钮显示的文本。 示例:
QPushButton *button = new QPushButton("Click Me", this);
2. clicked()
作用:按钮点击事件信号。
connect(button, &QPushButton::clicked, this, []() {
qDebug() << "Button clicked!";
});
7.QFont:创建一个字体对象。
QFont font("Arial", 14, QFont::Bold); // 设置字体为Arial,字号为14,加粗
QFont *font = new QFont("Microsoft YaHei", 15, 40);
cpu_button->setFont(*font);
soft_irq_button->setFont(*font);
mem_button->setFont(*font);
net_button->setFont(*font);
8.QLabel:显示文本或图片的控件。它
1. setText(const QString &text)
作用:设置标签显示的文本内容。
QLabel *label = new QLabel();
label->setText("Hello, World!"); // 设置文本内容
2. setAlignment(Qt::Alignment alignment)
label->setAlignment(Qt::AlignCenter); // 设置文本居中对齐
label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); // 设置文本左对齐且垂直居中
9.布局
window.setLayout(layout); // 将布局设置到窗口
不能对已设置 layout
的 QWidget
重新调用 setLayout()
1.QGridLayout:是一个网格布局管理器,用于以网格形式排列控件。
QWidget *window = new QWidget();
QGridLayout *layout = new QGridLayout(window);
QPushButton *button1 = new QPushButton("Button 1");
QPushButton *button2 = new QPushButton("Button 2");
QLabel *label = new QLabel("Label");
layout->addWidget(button1, 0, 0); // 将 button1 添加到第0行第0列
layout->addWidget(button2, 0, 1); // 将 button2 添加到第0行第1列
layout->addWidget(label, 1, 0, 1, 2); // 将 label 添加到第1行第0列,占1行2列
2.QStackedLayout:是一个堆叠布局管理器,用于创建多页面切换的界面,一次只能显示一个页面。
1. addWidget(QWidget *widget)
作用:将页面控件添加到堆叠布局中。
QWidget *window = new QWidget();
QStackedLayout *stackedLayout = new QStackedLayout(window);
QWidget *page1 = new QWidget();
page1->setStyleSheet("background-color: red;"); // 设置页面1的背景颜色为红色
QWidget *page2 = new QWidget();
page2->setStyleSheet("background-color: blue;"); // 设置页面2的背景颜色为蓝色
stackedLayout->addWidget(page1); // 添加页面1
stackedLayout->addWidget(page2); // 添加页面2
2 setCurrentWidget(QWidget *widget)
作用:切换到指定的页面控件。
stackedLayout->setCurrentWidget(page1); // 切换到页面1
3.QHBoxLayout:是一个水平布局管理器,用于在水平方向上排列控件。
1. addWidget(QWidget *widget)
作用:将控件添加到水平布局中。
QWidget *window = new QWidget();
QHBoxLayout *layout = new QHBoxLayout(window);
QPushButton *button1 = new QPushButton("Button 1");
QPushButton *button2 = new QPushButton("Button 2");
layout->addWidget(button1); // 将 button1 添加到水平布局
layout->addWidget(button2); // 将 button2 添加到水平布局
10.QSortFilterProxyModel:用于在模型(Model)和视图(View)之间提供排序和过滤功能。
-
功能:将源模型设置为代理模型的父模型。
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel();
QStandardItemModel *sourceModel = new QStandardItemModel();
proxyModel->setSourceModel(sourceModel);
7.在ubuntu22.04安装qt
1.安装
-
更新软件包列表:在终端中输入以下命令来更新Ubuntu的软件包列表。
sudo apt-get update
-
安装编译器:安装编译器,以便编译Qt程序。
sudo apt-get install build-essential
-
安装Qt相关软件包:安装Qt的开发工具和库。
sudo apt-get install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
- 安装其他依赖库:根据需要安装其他依赖库。
apt-get install -y \
libx11-xcb1 \
libfreetype6 \
libdbus-1-3 \
libfontconfig1 \
libxkbcommon0 \
libxkbcommon-x11-0
2.配置环境变量
- 打开
~/.bashrc
文件:sudo gedit ~/.bashrc
- 在文件末尾添加以下内容(假设Qt安装在
/opt/Qt
目录下,根据实际情况修改路径):
export QT_DIR=/opt/Qt
export PATH=$QT_DIR/5.15.2/gcc_64/bin:$PATH
export LD_LIBRARY_PATH=$QT_DIR/5.15.2/gcc_64/lib:$LD_LIBRARY_PATH
- 保存文件并退出编辑器,然后运行以下命令使环境变量生效:
source ~/.bashrc
3.验证安装
在终端中输入以下命令验证Qt是否安装成功:qmake --version
8.CMake
find_package(Qt5
REQUIRED COMPONENTS
Core
Widgets
)
set(SOURCES
main.cpp
monitor_inter.cpp
cpu_softirq_model.cpp
cpu_load_model.cpp
monitor_widget.cpp
cpu_stat_model.cpp
mem_model.cpp
net_model.cpp
)
add_executable(display ${SOURCES})
set_target_properties(display PROPERTIES AUTOMOC TRUE)
target_include_directories(display PUBLIC
${PROJECT_SOURCE_DIR}/rpc_manager
)
target_link_libraries(display
PUBLIC
client
monitor_proto
Qt5::Widgets
Qt5::Core
)
set_target_properties(display PROPERTIES AUTOMOC TRUE)
set(CMAKE_AUTOMOC ON)//必须放在目标之前
是一个特定的用法,主要用于 Qt 项目中,确保 Qt 的元对象系统(Meta-Object System)能够正确处理信号和槽。
作用
AUTOMOC
属性用于启用自动 MOC(Meta-Object Compiler)处理。MOC 是 Qt 的一个工具,用于处理包含 Q_OBJECT
宏的类,以支持信号和槽机制。当你设置 AUTOMOC TRUE
时,CMake 会自动运行 MOC 工具,处理包含 Q_OBJECT
宏的头文件,并生成必要的元对象代码。
示例
假设你有一个 Qt 项目,其中包含一个自定义的模型类 MonitorBaseModel
,并且你使用了 Q_OBJECT
宏。你需要确保 MOC 能够处理这个类,以便信号和槽机制能够正常工作。
9.在vscode使用Qt
1. 检查 Qt 头文件路径
dpkg -L qtbase5-dev | grep include
2. 配置 c_cpp_properties.json
确保在 VSCode 的 c_cpp_properties.json
文件中,includePath
正确指向你的 Qt 安装路径。
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/usr/include/qt5", // Qt 头文件根目录
"/usr/include/x86_64-linux-gnu/qt5", // Qt 库文件路径
"/usr/include/x86_64-linux-gnu/qt5/QtCore", // QtCore 头文件
"/usr/include/x86_64-linux-gnu/qt5/QtGui", // QtGui 头文件
"/usr/include/x86_64-linux-gnu/qt5/QtWidgets" // QtWidgets 头文件
],
"defines": [
"QT_CORE_LIB",
"QT_GUI_LIB",
"QT_WIDGETS_LIB"
],
"compilerPath": "/usr/bin/g++", // 使用正确的编译器路径
"cStandard": "c17", // 选择合适的 C 标准
"cppStandard": "c++17", // 选择合适的 C++ 标准
"intelliSenseMode": "linux-gcc-x64"
}
]
}