框架模块
模块的使用:
-
在项目文件中声明,比如:
.pro:QT += core gui widgets
CMake:find_package(Qt6 COMPONENTS Core Gui Widgets REQUIRED)
-
包含头文件,根据需要包含各个模块的头文件
-
在源代码中创建相关的类,就可以使用模块的功能
Qt常用头文件

|
全局定义
包含Qt框架的全局定义,包括基本数据类型,函数和宏
一般Qt类的头文件都会包含这个头文件,所以用户程序中无须包含这个头文件就可以使用其中的定义。
QtGlobal中定义的数据类型
QtGlobal 头文件提供了一些基础的数据类型和宏,这些类型和宏常用于增强跨平台的兼容性,以及简化开发工作。
基础整数类型
2、布尔类型
- bool: Qt 使用 C++ 标准布尔类型,但也提供了有时用到的 Q_BOOL 宏来表示布尔型。
3、浮点类型
- qreal: 平台相关的浮点数类型,通常为 float 或 double,具体取决于平台或编译选项。常用于图形计算。
4、其他类型
- QString 和 QByteArray: 虽然不是在 QtGlobal 中定义,但它们是在使用这些基础类型时常见的字符串处理类型。
示例:如何使用 QtGlobal 中定义的类型。
cpp
#include <QtGlobal>
#include <QDebug>
enum MyFlags {
Flag1 = 0x1,
Flag2 = 0x2
};
Q_DECLARE_FLAGS(MyFlags, MyFlags)
int main() {
qint32 signedInt = -42;
quint32 unsignedInt = 42;
qreal floatValue = 3.14;
MyFlags flags = Flag1 | Flag2;
qDebug() << "Signed Int:" << signedInt;
qDebug() << "Unsigned Int:" << unsignedInt;
qDebug() << "Float Value:" << floatValue;
qDebug() << "Flags:" << flags;
return 0;
}
运行结果:
makefile
Signed Int: -42
Unsigned Int: 42
Float Value: 3.14
Flags: Qt::Vertical_Flags (Flag1 and Flag2)
示例:
cpp
#include <QCoreApplication>
#include <QtGlobal>
#include <QDebug>
#include <cstdlib> // 用于 rand 和 srand
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
// 1. 使用 qAbs()
int number = -42;
qDebug() << "The absolute value of" << number << "is" << qAbs(number); // 输出绝对值
// 2. 使用 qMin() 和 qMax()
int a = 10;
int b = 20;
qDebug() << "The min of" << a << "and" << b << "is" << qMin(a, b); // 输出最小值
qDebug() << "The max of" << a << "and" << b << "is" << qMax(a, b); // 输出最大值
// 3. 使用 qRound()
float floatValue = 5.6f;
qDebug() << "Rounded value of" << floatValue << "is" << qRound(floatValue); // 四舍五入
// 4. 使用 qrand() 和 qsrand()
qsrand(static_cast<uint>(time(nullptr))); // 用当前时间来初始化随机数种子
int randomValue = qrand() % 100; // 生成 [0, 100) 的随机数
qDebug() << "Random value between 0 and 99:" << randomValue;
// 5. 使用 qDebug() 进行调试输出
QString debugMessage = "This is a debug message";
qDebug() << debugMessage;
return a.exec();
}
运行结果:
The absolute value of -42 is 42
The min of 10 and 20 is 10
The max of 10 and 20 is 20
Rounded value of 5.6 is 6
Random value between 0 and 99: 47
This is a debug message
示例:
cpp
#include <QCoreApplication>
#include <QtGlobal>
#include <QDebug>
enum class Color {
Red,
Green,
Blue,
Yellow
};
Q_DECLARE_FLAGS(ColorFlags, Color)
void assertExample(int value) {
Q_ASSERT(value > 0); // 如果值小于等于0,则程序在调试模式下崩溃
qDebug() << "Value is valid:" << value;
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
// 1. 使用 Q_ASSERT
assertExample(10);
// assertExample(-5); // 如果取消注释,将在调试模式崩溃
// 2. 使用 Q_UNLIKELY 和 Q_LIKELY
if (Q_LIKELY(true)) {
qDebug() << "This branch is likely taken.";
}
if (Q_UNLIKELY(false)) {
qDebug() << "This branch is unlikely taken."; // 不会打印
}
// 3. 使用 Q_DECLARE_FLAGS
ColorFlags flags = ColorFlags(Color::Red | Color::Green);
if (flags & ColorFlags(Color::Red)) {
qDebug() << "Red color is included in flags.";
}
// 4. 使用 QT_VERSION
qDebug() << "Current Qt Version:" << QT_VERSION;
// 5. 使用 Q_ENUM
Color color = Color::Green;
qDebug() << "Color value:" << static_cast<int>(color); // 输出枚举值
// 6. 使用 Q_STATIC_ASSERT
Q_STATIC_ASSERT(sizeof(int) == 4); // 在编译时检查 int 大小是否为4字节
return a.exec();
}
运行结果:
Value is valid: 10
This branch is likely taken.
Red color is included in flags.
Current Qt Version: 0x050c01
Color value: 1
Qt元对象系统核心概览
元对象系统是对C++的扩展,为Qt对象提供了运行时反射、动态类型检查、灵活的对象间通信等强大功能。
核心工作机制:
- 声明 :在类头文件中使用
Q_OBJECT宏。 - 生成:MOC工具处理该宏,生成包含元信息(如信号、槽)的C++代码。
- 编译:将生成的代码与用户源代码一同编译,实现运行时功能。
主要扩展特性:
- 信号与槽:实现对象间灵活通信的机制。
- 动态属性系统:允许在运行时为对象添加和访问属性。
- 内省(反射):可在运行时查询对象的类名、方法、属性等信息。
核心组件
1. QObject - 系统的基石
所有使用元对象系统的类都必须直接或间接继承自 QObject。Q_OBJECT 宏是启用所有相关特性的关键。
关键成员函数(与元对象系统相关):
| 函数 | 核心作用 |
|---|---|
metaObject() |
核心:返回对象的元对象,提供运行时类型信息。 |
setProperty() / property() |
动态设置与获取属性值。 |
connect() / disconnect() |
连接与断开信号和槽。 |
blockSignals() |
临时阻塞对象的所有信号。 |
inherits() |
检查对象是否属于某个类或其派生类。 |
基础示例:
cpp
#include <QObject>
class MyObject : public QObject {
Q_OBJECT // 必须添加此宏
public:
MyObject() {}
signals:
void mySignal(); // 声明信号
public slots:
void mySlot() { /* 槽函数实现 */ } // 声明槽
};
2. QMetaObject - 运行时反射的核心
每个 QObject 子类都有一个对应的 QMetaObject 实例,它描述了该类的结构信息。
关键查询函数:
| 类别 | 函数 | 核心作用 |
|---|---|---|
| 类信息 | className() |
获取类名字符串。 |
superClass() |
获取父类的元对象。 | |
| 方法相关 | methodCount(), method() |
获取方法的数量和详细信息。 |
indexOfMethod(), indexOfSignal(), indexOfSlot() |
通过名称查找方法、信号、槽的索引。 | |
| 属性相关 | propertyCount(), property() |
获取属性的数量和详细信息。 |
indexOfProperty() |
通过名称查找属性的索引。 | |
| 枚举相关 | enumeratorCount(), enumerator() |
获取枚举的数量和详细信息。 |
| 动态调用 | invokeMethod() |
重要:通过方法名动态调用对象的成员函数。 |
辅助类:
QMetaMethod: 描述方法(信号、槽、普通成员函数)的元信息。QMetaProperty: 描述属性的元信息,可用于动态读写。QMetaEnum: 描述枚举类型的元信息。
总结 :QObject 和 Q_OBJECT 宏提供了使用元对象功能的入口和基础能力;而 QMetaObject 及其辅助类提供了在运行时探查和操作这些能力的接口,共同构成了Qt强大的元对象系统。
示例:
cpp
#include <QCoreApplication>
#include <QObject>
#include <QMetaObject>
#include <QDebug>
class MyClass : public QObject {
Q_OBJECT
public:
MyClass(QObject *parent = nullptr) : QObject(parent) {}
signals:
void mySignal(int value);
public slots:
void mySlot(QString message) {
qDebug() << "Slot called with message:" << message;
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
MyClass obj;
// 使用 QMetaObject
const QMetaObject *metaObject = obj.metaObject();
// 打印类名称
qDebug() << "Class Name:" << metaObject->className();
// 遍历信号
for (int i = 0; i < metaObject->methodCount(); ++i) {
QMetaMethod method = metaObject->method(i);
if (method.isSignal()) {
qDebug() << "Signal:" << method.methodSignature();
} else if (method.isSlot()) {
qDebug() << "Slot:" << method.methodSignature();
}
}
// 连接信号与槽
QObject::connect(&obj, &MyClass::mySignal, &obj, &MyClass::mySlot);
// 发射信号
emit obj.mySignal(42);
return app.exec();
}
代码解释
- 定义类: Person 类继承自 QObject ,并使用 Q_PROPERTY 宏定义了两个属性: name 和 age 。
- 获取元对象:通过调用 metaObject() 方法,获取 Person 实例的元对象。
- 打印类名和属性信息:
- 使用 className() 打印类名。
- 遍历属性,使用 propertyCount() 和 property(i) 打印每个属性的名称和类型。
- 动态访问属性:使用元对象的 write() 方法动态设置 name 和 age 属性。
- 打印更新后的属性值:调用对应的 getter 方法输出更新后的值。
QObject 和 QMetaObject的区别:
| 特性 | QObject | QMetaObject |
|---|---|---|
| 定义 | Qt的基础类,提供对象的基本功能 | 存储元数据,包括类信息和信号槽机制 |
| 主要功能 | 对象之间的通信、事件处理、内存管理 | 反射机制、动态属性和信号槽支持 |
| 继承 | 其他类通常继承自QObject | 不能直接实例化 |
| 信号槽机制 | 使用QObject实现信号和槽 | 提供元信息以支持信号槽机制 |
| 元数据 | QObject 包含元对象(Meta-Object) | QMetaObject 存储类的所有元数据信息 |
| 访问方式 | 通过QObject 及其派生类直接访问 | 通过 QMetaObject::method() 等函数访问 |
| 应用场景 | 创建对象、处理事件、信号发射 | 查找类信息、连接信号与槽 |
运行时类型信息
使用 QObject 和 QMetaObject 接口函数来动态获取对象的类名称和其父类的名称,以及如何判断一个对象是否继承自某个类。
属性系统
属性定义
-
属性概念:在Qt C++中,属性是基于元对象系统的一个扩展特性,标准C++语言中没有属性。
允许开发者在运行时反射和访问对象的属性
-
定义方式:在QObject的子类中,使用宏 Q_PROPERTY 来定义属性。
-
格式:
cppQ_PROPERTY(type name READ getFunction WRITE setFunction NOTIFY signalMember)- type :属性的数据类型。可以是QVariant支持的任何类型或自定义类型。
- name :属性的名称。
- READ 和 WRITE :分别指定读取和设置属性值的函数。
- NOTIFY :可选,指定当属性值改变时发出的信号。
属性的使用
- 在Qt类库中的应用:很多基于QObject的类,特别是界面组件类如QWidget,都定义了属性。
- 属性编辑器:在Qt Designer中,属性编辑器允许用户修改组件的属性值。
- 函数命名规范:可读写的属性通常有一个用于读取的函数(函数名与属性名相同),和一个用于设置的函数(通常在属性名前加"set")。
动态属性
- 概念:使用函数 QObject::setProperty() 可以设置对象的动态属性,即在对象上定义新的属性。
- 特点:动态属性是针对类的实例定义的,只能通过 QObject::property() 读取。
- 示例需求:如窗口上的组件与数据库表字段关联,可以根据字段的必填性使用动态属性来设置组件的样式。
附加的类信息
- 概念:元对象系统还支持使用宏 Q_CLASSINFO 在类中定义类信息。
- 限制:类信息包括名称和值,但值只能以字符串形式表示。
定义和使用属性
示例:如何使用 Q_PROPERTY 定义和使用属性
cpp
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QLabel>
#include <QColor>
class MyWidget : public QWidget {
Q_OBJECT
Q_PROPERTY(QColor backgroundColor READ getBackgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged)
public:
MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
QVBoxLayout *layout = new QVBoxLayout(this);
label = new QLabel("Hello, Qt!", this);
layout->addWidget(label);
setLayout(layout);
}
QColor getBackgroundColor() const {
return m_backgroundColor;
}
void setBackgroundColor(const QColor &color) {
if (m_backgroundColor != color) {
m_backgroundColor = color;
emit backgroundColorChanged(m_backgroundColor);
QPalette palette = this->palette();
palette.setColor(QPalette::Window, m_backgroundColor);
this->setPalette(palette);
}
}
signals:
void backgroundColorChanged(const QColor &newColor);
private:
QColor m_backgroundColor = Qt::white; // 默认背景颜色
QLabel *label;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyWidget widget;
widget.resize(400, 300);
widget.setBackgroundColor(Qt::yellow); // 设置背景颜色为黄色
widget.show();
return app.exec();
}
#include "main.moc"
运行结果:

属性系统应用场景
1. UI组件属性管理
-
场景:动态管理界面组件(按钮、文本框等)的样式和状态。
-
示例 :自定义按钮,通过属性修改标签文本并触发UI更新。
cppclass Button : public QPushButton { Q_OBJECT Q_PROPERTY(QString labelText READ getLabelText WRITE setLabelText NOTIFY labelTextChanged) public: QString getLabelText() const { return text(); } void setLabelText(const QString &text) { if (this->text() != text) { setText(text); // 更新按钮文本 emit labelTextChanged(text); } } signals: void labelTextChanged(const QString &newText); };
2. 数据绑定与模型-视图框架
-
场景:实现数据与UI的自动同步(模型-视图架构)。
-
示例 :
Person对象的name属性变化时,自动更新绑定的UI控件。cppclass Person : public QObject { Q_OBJECT Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged) public: void setName(const QString &name) { if (m_name != name) { m_name = name; emit nameChanged(m_name); // 通知UI更新 } } // ... 其他代码 };
3. Qt Designer集成
-
场景:将自定义控件及其属性集成到Qt Designer中,方便可视化设计。
-
示例 :自定义颜色控件,暴露
color属性,可在设计器中直接修改。cppclass ColorWidget : public QWidget { Q_OBJECT Q_PROPERTY(QColor color READ getColor WRITE setColor NOTIFY colorChanged) public: void setColor(const QColor &color) { if (m_color != color) { m_color = color; update(); // 触发重绘 emit colorChanged(m_color); } } // ... 重绘等实现 };
Q_CLASSINFO
-
作用:为类附加元数据(如作者、版本等),用于运行时查询。
-
语法 :
Q_CLASSINFO("Name", "Value") -
示例 :
cppclass MyClass : public QObject { Q_OBJECT Q_CLASSINFO("Author", "John Doe") // 元信息:作者 Q_CLASSINFO("Version", "1.0") // 元信息:版本 };运行时可通过
QMetaObject::classInfo()查询。
信号与槽
核心机制
- 信号:事件触发的通知(只需声明,无需实现)。
- 槽:响应信号的函数(需要实现)。
- 连接 :使用
connect()关联信号与槽,实现对象间通信。
连接方式
-
传统方式 (Qt4风格):
cppconnect(button, SIGNAL(clicked()), label, SLOT(setText("Clicked"))); -
推荐方式 (Qt5/6,类型安全):
cppconnect(button, &QPushButton::clicked, label, &QLabel::clear); -
Lambda表达式 (适用于简单操作):
cppconnect(button, &QPushButton::clicked, [](){ qDebug() << "Button clicked"; });
自定义信号与槽
-
声明信号 (在
signals:下):cppsignals: void dataReady(const QByteArray &data); -
定义槽函数 (在
public slots:下):cpppublic slots: void processData(const QByteArray &data); -
发射信号 :
cppemit dataReady(rawData);
连接特性
- 一对多:一个信号可连接多个槽。
- 多对一:多个信号可连接同一个槽。
- 信号连信号:实现信号转发。
对象树与内存管理
- 机制:QObject及其子类可组织为父子树,父对象删除时自动删除所有子对象。
- 应用:简化窗口和UI组件的内存管理。
- 关键函数 :
setParent():设置父对象。children():获取子对象列表。findChild()/findChildren():查找子对象。
示例:创建窗口和按钮,窗口作为按钮的父对象。
cpp
QWidget *window = new QWidget;
QPushButton *button = new QPushButton("Click", window); // 指定父对象
// 删除window时,button会自动被删除
容器类
Qt容器特点
- 隐式共享:复制时共享数据,修改时才分离,提高效率。
- 线程安全:只读访问可跨线程。
- 迭代器:提供STL风格和Java风格两种迭代器。
顺序容器
| 容器 | 特点 | 适用场景 |
|---|---|---|
QList<T> |
动态数组,快速随机访问,适合频繁增删 | 通用列表存储 |
QVector<T> |
连续内存,随机访问性能极高 | 大数据集,侧重访问速度 |
QStack<T> |
后进先出(LIFO)栈 | 撤销操作、递归算法 |
QQueue<T> |
先进先出(FIFO)队列 | 任务队列、缓冲 |
关联容器
| 容器 | 特点 | 适用场景 |
|---|---|---|
QMap<Key, T> |
按键排序,基于平衡树 | 需要有序键值对 |
QHash<Key, T> |
哈希表,查找速度更快 | 快速查找,不要求顺序 |
QSet<T> |
无序集合,基于哈希 | 去重、快速成员检查 |
QMultiMap / QMultiHash |
一键多值 | 一对多映射 |
示例代码
-
QList 基本操作:
cppQList<QString> list; list << "Apple" << "Banana"; list.append("Cherry"); qDebug() << list[0]; // 输出: "Apple" -
QMap 示例:
cppQMap<QString, int> map; map.insert("apple", 5); map["banana"] = 3; qDebug() << map.value("apple"); // 输出: 5 -
QHash 示例(用法类似QMap,但无序):
cppQHash<QString, int> hash; hash.insert("key1", 100); qDebug() << hash.value("key1");
常用基础类
QVariant - 通用数据容器
- 作用:存储和传递任意类型的数据(整数、字符串、对象等),实现运行时类型转换。
- 核心方法 :
toInt(),toString(),toDouble():类型转换。canConvert<T>():检查能否转换为指定类型。type():返回存储的数据类型。
- 应用场景 :
- 信号槽传递不同类型数据。
- 动态属性系统。
- 通用数据存储。
示例:
cpp
QVariant data = 42; // 存储整数
qDebug() << data.toInt(); // 输出: 42
data = "Hello"; // 存储字符串
qDebug() << data.toString(); // 输出: "Hello"
if (data.canConvert<QString>()) { // 类型检查
QString str = data.toString(); // 安全转换
}
QFlags - 标志位集合
- 作用:将多个枚举标志组合为一个值,支持位运算。
- 使用步骤 :
- 定义枚举(使用2的幂次值)。
- 使用
Q_DECLARE_FLAGS声明标志类型。 - 使用
Q_DECLARE_OPERATORS_FOR_FLAGS启用运算符。
示例:
cpp
class Window {
public:
enum Style {
NoStyle = 0,
TitleBar = 0x1,
Resizable = 0x2,
CloseButton = 0x4
};
Q_DECLARE_FLAGS(Styles, Style)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Window::Styles)
// 使用
Window::Styles styles = Window::TitleBar | Window::Resizable;
if (styles & Window::TitleBar) {
qDebug() << "有标题栏";
}
QRandomGenerator - 随机数生成
- 特点:线程安全,高质量随机数生成。
- 常用方法 :
global():获取全局生成器实例。bounded(int max):生成[0, max)的整数。bounded(int min, int max):生成[min, max)的整数。generateDouble():生成[0.0, 1.0)的浮点数。
示例:
cpp
QRandomGenerator *rng = QRandomGenerator::global();
int dice = rng->bounded(1, 7); // 1-6的随机整数
double prob = rng->generateDouble(); // 0-1的随机浮点数
参考示例
1. 实时获取对象元信息
场景:动态查询对象的属性、类信息等元数据。
核心代码:
cpp
// 获取类名
QString className = obj->metaObject()->className();
// 遍历所有属性
const QMetaObject *meta = obj->metaObject();
for (int i = meta->propertyOffset(); i < meta->propertyCount(); i++) {
QMetaProperty prop = meta->property(i);
qDebug() << "属性:" << prop.name()
<< "值:" << obj->property(prop.name());
}
// 获取类附加信息
for (int i = meta->classInfoOffset(); i < meta->classInfoCount(); i++) {
QMetaClassInfo info = meta->classInfo(i);
qDebug() << info.name() << ":" << info.value();
}
2. 获取类继承关系
场景:查询对象的类名及其父类信息。
示例:
cpp
// 获取类名
Child obj;
qDebug() << "类名:" << obj.metaObject()->className(); // 输出: "Child"
// 获取父类名
qDebug() << "父类:" << obj.metaObject()->superClass()->className(); // 输出: "Parent"
// 遍历继承链
const QMetaObject *meta = obj.metaObject();
while (meta) {
qDebug() << meta->className();
meta = meta->superClass();
}
3. 类型继承判断
场景:运行时判断对象是否属于某个类或其派生类。
方法:
-
使用inherits():
cppQObject *obj = new Child(); if (obj->inherits("Parent")) { qDebug() << "obj是Parent或其子类"; } -
使用元对象继承检查:
cppif (obj->metaObject()->inherits(&Parent::staticMetaObject)) { qDebug() << "obj继承自Parent"; } -
使用qobject_cast进行安全转换:
cppParent *parent = qobject_cast<Parent*>(obj); if (parent) { qDebug() << "转换成功,obj是Parent类型"; }
关键要点总结
| 功能 | 实现方式 | 应用场景 |
|---|---|---|
| 动态类型信息 | metaObject()->className() |
调试、日志、运行时类型识别 |
| 属性反射 | property(), setProperty() |
动态UI配置、数据绑定 |
| 类信息查询 | QMetaClassInfo |
获取版本、作者等元数据 |
| 继承判断 | inherits(), qobject_cast<>() |
安全类型转换、插件系统 |
| 标志位管理 | QFlags, 位运算 |
选项组合、权限管理 |
| 通用数据存储 | QVariant |
信号槽参数、配置文件 |
实用技巧:
-
动态属性 :可为任何QObject对象动态添加属性。
cppbutton->setProperty("highlighted", true); -
信号槽连接检查 :
cppif (connect(sender, &Sender::signal, receiver, &Receiver::slot)) { qDebug() << "连接成功"; } -
遍历子对象 :
cppforeach(QObject *child, parent->children()) { qDebug() << child->objectName(); }
第四章 常用界面组件
界面组件概述
GUI程序的核心是窗口界面,界面上有各种组件实现交互操作。Qt提供了丰富的widget组件,这些组件统称为界面组件。
QWidget - 所有可视组件的基类
核心特性:
- 所有界面组件都基于QWidget构建
- 提供绘制、事件处理和布局管理等基本功能
- 继承自QObject和QPaintDevice(多重继承)
主要属性:
| 属性 | 描述 |
|---|---|
| geometry | 控件的位置和大小 |
| size | 当前尺寸 |
| visible/enabled | 可见性和启用状态 |
| focusPolicy | 焦点获取策略 |
| styleSheet | 样式表(CSS风格) |
常用方法:
cpp
widget->setGeometry(x, y, width, height); // 设置位置和大小
widget->move(x, y); // 移动位置
widget->resize(width, height); // 调整尺寸
widget->show() / hide(); // 显示/隐藏
widget->setFocus(); // 设置焦点
widget->setStyleSheet("样式"); // 应用样式
示例:基本窗口创建
cpp
QWidget window;
window.setWindowTitle("示例窗口");
window.resize(400, 300);
window.setStyleSheet("background-color: lightblue;");
window.show();
常用界面组件分类
1. 按钮类组件
| 组件 | 用途 | 特点 |
|---|---|---|
| QPushButton | 普通按钮 | 最常用,触发动作 |
| QToolButton | 工具按钮 | 常用于工具栏,可带菜单 |
| QRadioButton | 单选按钮 | 互斥选择,一组只能选一个 |
| QCheckBox | 复选框 | 多项选择,可独立选中 |
QAbstractButton(抽象基类)提供:
- 属性:checked(选中状态)、text(文本)、icon(图标)
- 信号:clicked()、pressed()、released()、toggled(bool)
- 方法:setChecked()、toggle()、click()
2. 输入类组件
文本输入:
- QLineEdit:单行文本输入框
- QTextEdit:富文本编辑器(支持HTML)
- QPlainTextEdit:纯文本编辑器(性能更好)
数值输入:
- QSpinBox:整数值输入(带增减按钮)
- QDoubleSpinBox:浮点数值输入
- QComboBox:下拉选择框
滑动输入:
- QSlider:滑块(水平/垂直)
- QDial:旋转拨盘
- QScrollBar:滚动条
3. 显示类组件
| 组件 | 用途 |
|---|---|
| QLabel | 显示文本/图片 |
| QTextBrowser | 富文本浏览器 |
| QProgressBar | 进度条 |
| QLCDNumber | 液晶数字显示 |
| QCalendarWidget | 日历控件 |
QLabel扩展功能:
- 显示超链接(linkActivated信号)
- 显示图片(setPixmap)
- 自动换行(wordWrap属性)
- 对齐方式(alignment属性)
4. 容器类组件
| 组件 | 用途 |
|---|---|
| QGroupBox | 分组框(带标题) |
| QTabWidget | 标签页容器 |
| QStackedWidget | 堆叠窗口(一次显示一个) |
| QScrollArea | 可滚动区域 |
| QDockWidget | 可停靠窗口 |
| QToolBox | 工具箱(类似QQ侧边栏) |
5. Item组件(模型/视图结构)
两种类型:
- Item Views :基于模型(Model),数据与显示分离
- QListView、QTreeView、QTableView
- Item Widgets :便利类,直接存储数据
- QListWidget、QTreeWidget、QTableWidget
选择原则:
- 简单场景用Item Widgets
- 复杂/大数据量用Item Views
布局管理
布局管理器概述
作用:
- 自动排列控件位置
- 窗口调整时自动重排控件
- 保持界面美观一致
核心类:QLayout(抽象基类)
- 不是可见组件,用于管理其他组件
- 基于QLayoutItem管理每个控件
常用布局类型
1. QVBoxLayout(垂直布局)
cpp
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(button1);
layout->addWidget(button2);
layout->addStretch(); // 添加伸缩空间
window->setLayout(layout);
2. QHBoxLayout(水平布局)
cpp
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(label);
layout->addWidget(lineEdit);
layout->addStretch();
3. QGridLayout(网格布局)
cpp
QGridLayout *layout = new QGridLayout;
layout->addWidget(label1, 0, 0); // 第0行第0列
layout->addWidget(lineEdit1, 0, 1); // 第0行第1列
layout->addWidget(label2, 1, 0); // 第1行第0列
layout->addWidget(lineEdit2, 1, 1); // 第1行第1列
layout->addWidget(button, 2, 0, 1, 2); // 跨2列
4. QFormLayout(表单布局)
cpp
QFormLayout *layout = new QFormLayout;
layout->addRow("姓名:", nameEdit);
layout->addRow("年龄:", ageEdit);
layout->addRow("", submitButton); // 空标签
5. QStackedLayout(堆叠布局)
cpp
QStackedLayout *stacked = new QStackedLayout;
stacked->addWidget(page1);
stacked->addWidget(page2);
stacked->setCurrentIndex(0); // 显示第一页
6. QSplitter(分割器)
cpp
QSplitter *splitter = new QSplitter(Qt::Horizontal);
splitter->addWidget(textEdit1);
splitter->addWidget(textEdit2);
splitter->setSizes({200, 100}); // 设置初始大小
布局属性控制
| 属性/方法 | 描述 |
|---|---|
| setMargin() | 设置外边距 |
| setSpacing() | 设置控件间距 |
| setStretch() | 设置伸缩因子 |
| addStretch() | 添加伸缩空间 |
| setAlignment() | 设置对齐方式 |
字符串处理
QString核心特性
- UTF-16编码,每个字符2字节
- 隐式共享(写时复制)
- 丰富的字符串操作API
常用操作:
cpp
QString str = "Hello Qt";
int len = str.length(); // 长度
str.append(" World"); // 追加
str.insert(5, " Beautiful"); // 插入
QString sub = str.mid(0, 5); // 子串
str.replace("Hello", "Hi"); // 替换
bool contains = str.contains("Qt"); // 包含检查
类型转换:
cpp
// 字符串转数值
QString str = "123";
int num = str.toInt();
double d = str.toDouble();
// 数值转字符串
QString s1 = QString::number(123);
QString s2 = QString::number(3.14159, 'f', 2); // 2位小数
QChar字符处理
cpp
QChar ch = 'A';
bool isDigit = ch.isDigit(); // 是否数字
bool isLetter = ch.isLetter(); // 是否字母
QChar lower = ch.toLower(); // 转小写
QChar upper = ch.toUpper(); // 转大写
ushort unicode = ch.unicode(); // Unicode码
数值输入输出组件
1. QSpinBox/QDoubleSpinBox
cpp
QSpinBox *spinBox = new QSpinBox;
spinBox->setRange(0, 100); // 范围
spinBox->setValue(50); // 当前值
spinBox->setSingleStep(1); // 步长
spinBox->setSuffix(" 个"); // 后缀
spinBox->setPrefix("$ "); // 前缀
// 浮点版本
QDoubleSpinBox *doubleSpin = new QDoubleSpinBox;
doubleSpin->setDecimals(2); // 小数位数
2. QSlider
cpp
QSlider *slider = new QSlider(Qt::Horizontal);
slider->setRange(0, 100);
slider->setValue(50);
slider->setTickInterval(10); // 刻度间隔
slider->setTickPosition(QSlider::TicksBelow); // 刻度位置
// 连接信号
connect(slider, &QSlider::valueChanged, [](int value) {
qDebug() << "当前值:" << value;
});
3. QProgressBar
cpp
QProgressBar *progress = new QProgressBar;
progress->setRange(0, 100);
progress->setValue(50);
progress->setTextVisible(true); // 显示百分比
progress->setFormat("%p%"); // 格式
4. 其他数值组件
- QScrollBar:滚动条
- QDial:旋转拨盘(类似音量旋钮)
- QLCDNumber:液晶数字显示(数码管风格)
文本编辑组件
1. QLineEdit(单行)
cpp
QLineEdit *lineEdit = new QLineEdit;
lineEdit->setPlaceholderText("请输入...");
lineEdit->setEchoMode(QLineEdit::Password); // 密码模式
lineEdit->setValidator(new QIntValidator(0, 100)); // 输入验证
lineEdit->setClearButtonEnabled(true); // 清空按钮
2. QTextEdit(富文本)
cpp
QTextEdit *textEdit = new QTextEdit;
textEdit->setPlainText("纯文本"); // 设置纯文本
textEdit->setHtml("<b>粗体</b>文本"); // 设置HTML
textEdit->append("追加文本"); // 追加内容
QString content = textEdit->toPlainText(); // 获取内容
3. QPlainTextEdit(纯文本)
- 性能优于QTextEdit
- 适合大文本处理
- 不支持富文本格式
按钮组件详解
1. QPushButton(普通按钮)
cpp
QPushButton *button = new QPushButton("点击我");
button->setIcon(QIcon("icon.png")); // 图标
button->setShortcut(QKeySequence("Ctrl+S")); // 快捷键
button->setCheckable(true); // 可切换状态
button->setAutoDefault(true); // 回车触发
// 样式设置
button->setStyleSheet("QPushButton {"
" background-color: blue;"
" color: white;"
" border-radius: 5px;"
"}");
2. QRadioButton(单选按钮)
cpp
// 需要分组确保互斥
QButtonGroup *group = new QButtonGroup;
QRadioButton *radio1 = new QRadioButton("选项1");
QRadioButton *radio2 = new QRadioButton("选项2");
group->addButton(radio1);
group->addButton(radio2);
radio1->setChecked(true); // 默认选中
3. QCheckBox(复选框)
cpp
QCheckBox *checkbox = new QCheckBox("同意协议");
checkbox->setTristate(true); // 三态:选中/未选中/部分选中
checkbox->setCheckState(Qt::PartiallyChecked);
4. QDialogButtonBox(对话框按钮组)
cpp
QDialogButtonBox *buttons = new QDialogButtonBox;
buttons->setStandardButtons(QDialogButtonBox::Ok |
QDialogButtonBox::Cancel);
connect(buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
日期时间处理
1. 核心类
- QTime:时间处理(时、分、秒、毫秒)
- QDate:日期处理(年、月、日)
- QDateTime:日期时间组合
基本操作:
cpp
QTime time = QTime::currentTime(); // 当前时间
QDate date = QDate::currentDate(); // 当前日期
QDateTime datetime = QDateTime::currentDateTime(); // 当前日期时间
// 格式化输出
qDebug() << time.toString("hh:mm:ss"); // 12:30:45
qDebug() << date.toString("yyyy-MM-dd"); // 2023-10-25
qDebug() << datetime.toString("yyyy-MM-dd hh:mm:ss");
// 计算
QDateTime later = datetime.addDays(7); // 加7天
QDateTime earlier = datetime.addSecs(-3600); // 减1小时
2. 界面组件
cpp
// 日期选择
QDateEdit *dateEdit = new QDateEdit;
dateEdit->setDate(QDate::currentDate());
dateEdit->setDisplayFormat("yyyy年MM月dd日");
// 时间选择
QTimeEdit *timeEdit = new QTimeEdit;
timeEdit->setTime(QTime::currentTime());
// 日期时间选择
QDateTimeEdit *datetimeEdit = new QDateTimeEdit;
datetimeEdit->setDateTime(QDateTime::currentDateTime());
// 日历控件
QCalendarWidget *calendar = new QCalendarWidget;
calendar->setSelectedDate(QDate::currentDate());
定时器
1. QTimer(定时触发)
cpp
QTimer *timer = new QTimer;
timer->setInterval(1000); // 1秒间隔
// 单次定时
timer->setSingleShot(true);
// 连接信号
connect(timer, &QTimer::timeout, []() {
qDebug() << "定时触发";
});
timer->start(); // 启动
timer->stop(); // 停止
2. QElapsedTimer(耗时测量)
cpp
QElapsedTimer timer;
timer.start(); // 开始计时
// ... 执行操作 ...
qint64 elapsed = timer.elapsed(); // 获取毫秒数
qDebug() << "耗时:" << elapsed << "毫秒";
下拉列表框
QComboBox
cpp
QComboBox *comboBox = new QComboBox;
comboBox->addItem("选项1");
comboBox->addItem("选项2");
comboBox->addItem("选项3");
comboBox->setEditable(true); // 可编辑
// 批量添加
QStringList items = {"A", "B", "C"};
comboBox->addItems(items);
// 当前选中
int index = comboBox->currentIndex();
QString text = comboBox->currentText();
// 信号
connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
[](int index) {
qDebug() << "选中索引:" << index;
});
主窗口组件
1. QMainWindow结构
cpp
QMainWindow mainWindow;
mainWindow.setWindowTitle("主窗口");
// 中心部件
QTextEdit *textEdit = new QTextEdit;
mainWindow.setCentralWidget(textEdit);
// 菜单栏
QMenuBar *menuBar = mainWindow.menuBar();
QMenu *fileMenu = menuBar->addMenu("文件");
QAction *newAction = fileMenu->addAction("新建");
// 工具栏
QToolBar *toolBar = mainWindow.addToolBar("主工具栏");
toolBar->addAction(newAction);
// 状态栏
QStatusBar *statusBar = mainWindow.statusBar();
statusBar->showMessage("就绪", 3000); // 显示3秒
// 停靠窗口
QDockWidget *dock = new QDockWidget("工具面板");
dock->setWidget(new QListWidget);
mainWindow.addDockWidget(Qt::LeftDockWidgetArea, dock);
2. QAction(动作)
- 可关联到菜单、工具栏、快捷键
- 统一管理功能触发
cpp
QAction *action = new QAction("保存", this);
action->setIcon(QIcon("save.png"));
action->setShortcut(QKeySequence::Save);
action->setStatusTip("保存文件");
// 添加到菜单和工具栏
fileMenu->addAction(action);
toolBar->addAction(action);
// 连接信号
connect(action, &QAction::triggered, []() {
qDebug() << "保存动作触发";
});
Item Widget组件
1. QListWidget(列表)
cpp
QListWidget *listWidget = new QListWidget;
listWidget->addItem("项目1");
listWidget->addItem("项目2");
// 自定义项
QListWidgetItem *item = new QListWidgetItem("自定义项");
item->setIcon(QIcon("icon.png"));
item->setCheckState(Qt::Checked); // 带复选框
listWidget->addItem(item);
// 选择模式
listWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); // 多选
// 信号
connect(listWidget, &QListWidget::itemClicked,
[](QListWidgetItem *item) {
qDebug() << "点击:" << item->text();
});
2. QTreeWidget(树形)
cpp
QTreeWidget *treeWidget = new QTreeWidget;
treeWidget->setHeaderLabels({"名称", "大小", "类型"});
// 根节点
QTreeWidgetItem *root = new QTreeWidgetItem(treeWidget, {"根目录"});
// 子节点
QTreeWidgetItem *child1 = new QTreeWidgetItem(root, {"子文件夹1"});
QTreeWidgetItem *child2 = new QTreeWidgetItem(root, {"子文件夹2"});
// 孙节点
new QTreeWidgetItem(child1, {"文件1.txt"});
new QTreeWidgetItem(child1, {"文件2.txt"});
// 展开所有
treeWidget->expandAll();
// 获取选中
QTreeWidgetItem *selected = treeWidget->currentItem();
3. QTableWidget(表格)
cpp
QTableWidget *tableWidget = new QTableWidget(3, 3); // 3行3列
tableWidget->setHorizontalHeaderLabels({"姓名", "年龄", "性别"});
// 设置数据
tableWidget->setItem(0, 0, new QTableWidgetItem("张三"));
tableWidget->setItem(0, 1, new QTableWidgetItem("25"));
tableWidget->setItem(0, 2, new QTableWidgetItem("男"));
// 设置整行
QStringList rowData = {"李四", "30", "女"};
for (int col = 0; col < rowData.size(); ++col) {
tableWidget->setItem(1, col, new QTableWidgetItem(rowData[col]));
}
// 单元格对齐
tableWidget->item(0, 1)->setTextAlignment(Qt::AlignCenter);
// 选择模式
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); // 整行选择
实用技巧与最佳实践
1. 组件样式定制
cpp
// 使用样式表(CSS-like)
widget->setStyleSheet(
"QPushButton {"
" background-color: #4CAF50;"
" border: none;"
" color: white;"
" padding: 10px 20px;"
" border-radius: 5px;"
"}"
"QPushButton:hover {"
" background-color: #45a049;"
"}"
"QPushButton:pressed {"
" background-color: #3d8b40;"
"}"
);
2. 布局动态调整
cpp
// 动态添加/移除控件
layout->addWidget(newWidget);
layout->removeWidget(oldWidget);
oldWidget->deleteLater();
// 更新布局
layout->update();
// 调整伸缩因子
layout->setStretchFactor(widget1, 2); // 占2份
layout->setStretchFactor(widget2, 1); // 占1份
3. 信号槽连接优化
cpp
// C++11风格(推荐)
connect(button, &QPushButton::clicked, this, &MyClass::onButtonClicked);
// Lambda表达式(简单逻辑)
connect(button, &QPushButton::clicked, [this]() {
// 直接处理
label->setText("已点击");
});
// 带参数的Lambda
connect(slider, &QSlider::valueChanged, [label](int value) {
label->setText(QString::number(value));
});
4. 性能优化建议
- 大量数据用模型/视图:避免使用QListWidget等存储大量数据
- 合理使用样式表:避免过度复杂的样式计算
- 及时释放资源:动态创建的控件要正确删除
- 避免阻塞UI线程:耗时操作用多线程或QTimer分批处理
总结对比
| 组件类型 | 适用场景 | 推荐组件 |
|---|---|---|
| 简单列表 | 少量项,静态数据 | QListWidget |
| 复杂列表 | 大量数据,动态更新 | QListView + QStandardItemModel |
| 层级数据 | 树形结构(文件系统) | QTreeWidget / QTreeView |
| 表格数据 | 二维表格(Excel风格) | QTableWidget / QTableView |
| 表单输入 | 数据录入界面 | QFormLayout + 各种输入组件 |
| 主界面 | 复杂应用程序 | QMainWindow + 各种子组件 |
第五章 模型视图结构
模型/视图
模型/视图(Model/View)结构是一种用于分离数据存储和界面展示的编程模式。它提供了一种结构化的方法来管理用户界面和数据交互,确保各组件职责清晰。
结构概述
- 模型(Model) :
- 负责存储和管理数据。
- 提供数据的接口供视图访问。
- 通知视图和代理有关数据变化的信号。
- 视图(View) :
- 负责展示模型中的数据。
- 将用户界面和模型的数据进行绑定。
- 自动更新以反映模型数据的变化。
- 代理(Delegate) :
- 负责在视图中编辑模型的数据。
- 提供自定义数据编辑的接口。
这种结构的关键在于实现:
- 数据与界面的分离 :
- 模型处理数据,视图负责显示。
- 视图仅通过模型的接口访问数据。
- 自动更新机制 :
- 模型中的数据变更会自动通知视图更新显示。
- 灵活的视图/模型组合 :
- 可以使用多种视图展示相同的模型。
模型/视图结构基本原理
模型/视图架构是一种用于分离界面和数据的机制。这种架构能够很好地维护数据和表示之间的独立性,常用于数据库应用程序,因为它允许数据以灵活、强大的方式在用户界面组件和后端之间传递。
模型/视图架构的设计理念:
- 分离界面和原始数据 :
- 数据直接存储在模型中(通常来自数据库等)。
- 界面(视图)仅负责显示数据,不直接操作它。
- 模型的作用 :
- 模型是数据和视图之间的桥梁。
- 模型代表了数据的逻辑结构,可以是表格、树、列表等结构。
- 视图的作用 :
- 负责将模型中的数据展示给用户。
- 用户可以通过视图直观地查看、编辑、操作数据。
- 控制器 (在 Qt 的实现中通常是槽函数):
- 通过信号与槽机制完成模型和视图间的通信。
- 修改后的数据通过模型传递到数据库等原始源。
在Qt中如何处理这些关系:
数据 (Source Data)
- 数据源可能是内存中的字符串列表、二维表、数据库表,甚至是磁盘文件的数据。
- 数据只存储在后台,与视图分离。
模型 (Model)
- 负责与数据源的通信,提取需要显示的数据,并提供给视图进行展示。
- 模型是视图间接访问数据的桥梁。
- Qt 提供了一些标准模型类:
- QStringListModel :处理字符串列表数据。
- QStandardItemModel :处理通用的表格型数据。
- QSqlTableModel :用于数据库表数据。
视图 (View)
- 是用户界面的显示组件。
- 从模型中获取数据,并呈现在用户界面上。
- Qt 提供了一些标准视图类:
- QListView :显示列表型数据。
- QTreeView :显示树型数据。
- QTableView :显示表格型数据。
代理 (Delegate)
- 用于在视图中编辑模型数据的临时编辑器。
- 自定义代理可以设置专用的编辑器组件(如使用滑块 QSlider 编辑表格数据中的数值)。
- 通常提供数据的展示和编辑方案(如使用 QItemDelegate 或 QStyledItemDelegate )。
信号与槽 (Signals and Slots)
- 模型和视图通过信号与槽通信。
- 当数据发生变化时:
- 模型发出信号通知视图更新。
- 当用户通过视图操作数据时:
- 视图发出信号通知模型更新数据。
- 代理也通过信号与槽与模型和视图之间互动。
由于显示与数据源,编辑分离:
- 可以将一个模型在不同的视图中显示
- 为特殊数据源设计自定义模型
- 为数据设计特殊的视图
模型
所有基于项(item)的模型类都是从 QAbstractItemModel 类派生的。这个类定义了视图组件和代理访问数据的接口。
- 模型的作用 :
- 模型类用于临时存储数据。
- 数据来源可以是其他类、文件、数据库或者任何数据源。
- 继承 :
- QAbstractItemModel 是从 QObject 继承的。
- 由于继承了 QObject ,模型类支持 Qt 的元对象系统。
- 主要特性 :
- 提供了视图和数据之间的接口。
- 支持信号与槽机制,便于数据变动的实时响应。
QAbstractItemModel 不能直接用于创建实例对象。
常用类型类
| 模型类名称 | 描述 |
|---|---|
| QFileSystemModel | 用于展示文件系统结构的模型。它允许你以树状结构浏览文件系统中的文件和目录。这个模型主要用于图形界面的文件浏览器或资源管理器中。 |
| QStringListModel | 一个简单的模型,用于展示字符串列表。通常用于简单的列表视图,比如用于展示列表项的简单列表视图控件。 |
| QStandardItemModel | 提供了一种灵活的方式来存储和操作数据模型。它是一个标准的表模型,允许你创建自定义的数据结构并展示在视图控件中。这个模型提供了许多有用的方法和功能,用于处理复杂的表结构。 |
| QSqlQueryModel | 用于数据库查询结果的模型。它封装了数据库查询的结果,使得你可以在视图控件中展示这些结果。它简化了与数据库的交互过程,特别是在处理大量数据的时候。 |
| QSqlTableModel | 一个更加专门的数据库模型,通常用于创建和维护数据库的表结构。它可以提供对数据库表的读写访问,并允许你直接在模型中编辑数据,然后同步到数据库中。这对于创建基于数据库的界面非常有用。 |
视图
视图就是用于显示模型中的数据的界面组件,Qt提供的视图组件主要有以下几个。
| 视图组件名称 | 描述 | 适用数据类型 |
|---|---|---|
| QListView | 用于显示单列的列表数据。 | 一维数据(列表形式) |
| QTreeView | 用于显示树状结构数据。 | 树状结构数据(如文件夹和文件) |
| QTableView | 用于显示表格数据,包括行和列的二维数据。 | 二维表格数据(如数据库表或电子表格) |
| QColumnView | 用多个 QListView 显示树状结构数据,每一层用一个 QListView 显示。 | 树状结构数据(分层展示) |
| QUndoView | 用于显示 undo 指令栈内数据的视图组件,是 QListView 的子类。 | Undo 指令栈内的数据(操作历史记录等) |
QListWidget 、 QTreeWidget 和 QTableWidget 这三个是用于处理项数据的组件。它们分别是三个视图类的子类,也叫视图类的便利类。
视图类的使用:
- 视图类通过 setModel() 函数与模型连接来显示数据。
- 视图组件直接与模型交互,在视图中修改数据时会更新模型。
- 都不直接存储数据,数据的展示和修改由模型处理。
便利类的特点:
- 便利类不使用模型,而是通过项(如 QTableWidgetItem )来存储数据。
- 为每个节点或单元格创建一个项,用项来替代模型的功能。
适用范围:
- 便利类适用于小型数据的展示和编辑。
- 没有模型,用项的方式代替模型的功能。缺乏处理大型数据源的灵活性。
- 相比之下,视图组件通过模型来处理数据,更灵活且适合大型数据源。
示例:使用便利类。 QTableWidget 作为便利类将数据直接存储在 QTableWidgetItem 中,每个单元格有自己的数据对象。这种方式适合小型数据集
cpp
#include <QApplication>
#include <QTableWidget>
#include <QTableWidgetItem>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QTableWidget tableWidget(3, 2); // 3行2列
// 设置数据
tableWidget.setItem(0, 0, new QTableWidgetItem("Item 0,0"));
tableWidget.setItem(0, 1, new QTableWidgetItem("Item 0,1"));
tableWidget.setItem(1, 0, new QTableWidgetItem("Item 1,0"));
tableWidget.setItem(1, 1, new QTableWidgetItem("Item 1,1"));
tableWidget.setItem(2, 0, new QTableWidgetItem("Item 2,0"));
tableWidget.setItem(2, 1, new QTableWidgetItem("Item 2,1"));
tableWidget.show();
return app.exec();
}
示例:模型/视图框架,适合处理大型和动态数据。 QStandardItemModel 用作数据模型, QTableView 显示其数据。任何在视图中的更改都会自动更新到模型中
cpp
#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QTableView tableView;
QStandardItemModel model(3, 2); // 3行2列
// 设置数据
model.setItem(0, 0, new QStandardItem("Item 0,0"));
model.setItem(0, 1, new QStandardItem("Item 0,1"));
model.setItem(1, 0, new QStandardItem("Item 1,0"));
model.setItem(1, 1, new QStandardItem("Item 1,1"));
model.setItem(2, 0, new QStandardItem("Item 2,0"));
model.setItem(2, 1, new QStandardItem("Item 2,1"));
tableView.setModel(&model);
tableView.show();
return app.exec();
}
代理
代理用于在视图组件中为数据编辑提供临时编辑器。它负责在视图和模型之间协调数据的展示和编辑操作。
QAbstractItemDelegate 是所有代理类的基类,不能直接使用。
常用的代理类有 QItemDelegate 和 QStyledItemDelegate 。
对于特殊编辑需求,可以通过继承 QStyledItemDelegate 创建自定义代理类。
代理的作用
-
编辑器的提供:代理负责在视图组件(如 QTableView )上为数据编辑提供临时编辑器,例如默认情况下单元格数据的编辑器是 QLineEdit 。
-
数据的处理:从模型获取数据,显示在编辑器中。
-
在编辑完成后,将编辑器中修改后的数据保存回模型。
代理类的继承结构
-
基类:QAbstractItemDelegate
抽象类,不能直接用于创建代理对象。
-
子类:
QItemDelegate :功能基本与 QStyledItemDelegate 相同。
QStyledItemDelegate :默认代理类。
-
支持使用 Qt 样式表绘制代理组件。
特殊需求处理
-
通过为视图组件设置自定义代理,可以实现特殊数据编辑需求:
例如:
- 只允许输入整数时,可用 QSpinBox 作为代理组件。
- 数据需从预设列表中选择时,可用 QComboBox 作为代理组件。
-
可通过继承 QStyledItemDelegate 创建自定义代理类,根据需求配置特殊的编辑器或行为。
模型/视图结构相关概念
在模型/视图框架中,模型为视图组件和代理提供了存取数据的接口,通过统一的模型结构完成了数据展示与交互方式的分离。
模型中的数据存储单元是以 项 (item) 为基本单位,每个项由行号、列号和父项定义,同时通过 模型索引 (QModelIndex) 作为临时指针来存取数据。
模型的基本结构
-
基类与继承:
- QAbstractItemModel 是所有模型类的基类。
- 其子类将底层数据组织成特定的表格层次结构,不论实际的数据结构如何。
-
常见模型结构:
-
列表模型 (list model):数据存储为单列。
-
表格模型 (table model):数据存储为二维规则表格(行和列的结构)。
-
树状模型 (tree model):数据存储为有父子关系的树状结构(复杂结构,每个节点可能有子节点)。
-
-
数据项的组成:
- 每个数据项由 行号 和 列号 唯一标识。
- 每个项有一个 父项 (parent item)。
- 模型都包含一个隐藏的 根项 (root item),作为数据结构的起点。
模型索引
- 作用:
- 模型索引用来表示与模型中的一个数据项对应的临时指针。
- 视图组件 和 代理 使用模型索引与模型交互来获取或修改数据。
- 特点:
- 通过 QModelIndex 表示模型索引,模型索引包含行号、列号以及父项索引。
- 唯一性: 每个数据项有一个唯一的模型索引。
- 临时性: 模型的数据结构可能随时变化,因此,模型索引是临时的,数据被修改后可能失效。
- 使用场景:
- 例如在 QTreeView 组件中,获取某节点的模型索引后,若模型发生改变,则之前的模型索引可能无效。
行号与列号
- 作用:
- 模型的基本形式是以 行号 和 列号 为标准的表格数据模型,为界面组件间的数据交互提供统一标准。
- 参数构成:
- 一个模型索引需要以下 3 个参数:
- 行号
- 列号
- 父项的模型索引
- 一个模型索引需要以下 3 个参数:
- 说明:
- 模型底层未必用二维数组存储数据,行号和列号仅用于简化访问方式。
- 例如表格模型中的项 A、B、C 的示例:,通过 (行号, 列号, 父项索引) 来获取其模型索引。
父项
- 概念:
- 所有项都有一个父项,顶层项的父项为隐藏的根项( root item )。
- 结构特性:
-
列表模型或表格模型:
父项通常是顶层项,所有项共享一个共同的父项。
-
树状模型:
每个节点都有一个父节点,同时可能作为其他节点的父节点。
构造节点的模型索引时,必须提供行号、列号以及父节点的索引。
-
项的角色
- 定义:
- 数据项( item )的每个角色对应一组数据,角色由 Qt 的角色枚举常量定义。
- 设置数据:
-
setData() 函数用于为模型的某项设置数据。
-
数据可根据不同的角色被多次设置:
如: Qt::EditRole (编辑用数据)、 Qt::DecorationRole (装饰用数据,如图标)等。
-
抽象类
QAbstractltemModel类
QAbstractltemModel是所有模型类的直接或间接父类
-
它定义了模型的通用接口函数,例如用于插入行、删除行、设置数据的函数。
-
QAbstractItemModel是抽象类,不能直接用于创建对象实例,各个具体的模型类实现了这些接口函数。
这个模型类是所有其他特定模型的基类,例如 QStandardItemModel 、 QStringListModel 等。
在 Qt 中,模型用于管理数据以及与视图(如 QListView 、 QTreeView 等)之间的数据交互。模型提供了数据展示的核心逻辑和视图所需要的数据。视图负责展示模型的数据和用户交互。
QAbstractItemModel 提供了一个通用的接口,使得开发者可以创建自定义的模型来满足特定的数据展示需求。它定义了基本的模型功能,如数据的索引访问、数据行数、列数等。此外,它还定义了一些基本的操作,如添加和删除行或列等。具体的实现则由继承自 QAbstractItemModel 的子类来完成。子类通常包含数据的实际存储和处理逻辑。
QAbstractItemModel 的重要特性:
- 索引访问:模型通过索引来访问数据。每个索引指向模型中的一个特定位置(行和列)。这允许视图高效地访问和更新数据。
- 数据角色:模型定义了不同的数据角色(如文本、图标等),这些角色用于描述模型中数据的不同属性。视图可以通过这些角色来获取或设置数据。
- 信号与槽:模型通过发出信号来通知视图数据的改变,比如数据添加或删除。这使得视图可以实时响应模型的改变并更新界面。
- 可定制性:由于它是一个抽象类,开发者可以扩展它并实现自定义的数据存储和逻辑处理来满足特定应用的需求。这包括数据的过滤、排序等高级功能。
QAbstractltemView类
QAbstractItemView 是 Qt 框架中的一个抽象类,它提供了实现列表或表格类视图的接口。
这个类是各种具体视图类(如 QListView 、 QTableView 和 QTreeView )的基础,并为这些类提供了核心的功能和数据管理逻辑。
主要功能和特点:
- 数据模型管理: QAbstractItemView 用来显示模型数据(例如,由 QAbstractItemModel 或其子类提供的模型数据)。它将用户界面与模型分离,允许开发人员使用模型-视图-委托(Model-View-Delegate)架构来管理数据的展示和编辑逻辑。
- 支持编辑操作:用户可以在某些类型的单元格(例如在 QTableView 中的单元格)中进行编辑操作, QAbstractItemView 提供了一种机制来处理这些编辑操作。它允许开发者定义哪些单元格是可编辑的,并处理编辑事件。
- 自定义布局:尽管 QAbstractItemView 为不同种类的视图提供了预定义的布局(如列表、表格和树状结构),但它也允许开发者通过继承这个类来创建自定义的视图布局。这使得开发者可以根据特定需求定制视图的外观和行为。
- 键盘导航和快捷键处理:它处理用户的键盘输入事件来导航数据和选择项。这意味着用户可以轻松地通过键盘来浏览列表或表格数据。
- 数据排序和筛选:提供了对数据进行排序和筛选的方法,这有助于根据不同的需求和优先级对数据进行展示和管理。例如,在 QTableView 中可以按某一列进行排序,或者根据特定的条件过滤数据。
使用示例:
QAbstractItemView 是一个抽象类不能直接使用,但通过其子类如 QListView 或 QTableView ,可以轻松实现一个基础的列表或表格视图。
例如,在 QTableView 中,你可以创建一个模型来存储数据,然后将这个模型与视图关联起来,从而展示数据给用户。此外,你还可以自定义视图的外观和行为,比如使用委托来定义单元格的编辑方式或展示样式等。
示例:如何使用 QTableView 和 QStandardItemModel 来创建和显示一个表格视图。
cpp
//用 QStandardItemModel 存储一些数据,并将其关联到 QTableView。
#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 创建一个 QStandardItemModel,3 行 3 列
QStandardItemModel model(3, 3);
// 设置模型中的数据
for (int row = 0; row < 3; ++row) {
for (int column = 0; column < 3; ++column) {
QStandardItem *item = new QStandardItem(QString("Row %1, Column %2").arg(row).arg(column));
model.setItem(row, column, item);
}
}
// 创建 QTableView
QTableView tableView;
tableView.setModel(&model); // 将模型关联到视图
// 显示视图
tableView.show();
return app.exec();
}
解释
- QApplication: 应用程序对象,负责管理应用程序的控制流和主要设置。
- QStandardItemModel: 用于存储数据的模型,具有3行3列的表格。
- QStandardItem: 用来填充模型的数据项,文本格式为 "Row X, Column Y"。
- QTableView: 用于显示模型数据的视图。
- setModel: 关联模型和视图,将数据呈现到界面上。
QAbstractItemDelegate类
QAbstractItemDelegate 是 Qt 框架中的一个重要类,它位于信号与槽和视图/模型之间。它是用于创建自定义数据编辑功能的基类,允许用户自定义如何在视图控件中渲染和编辑模型中的数据。
以下是关于 QAbstractItemDelegate 的简要介绍:
主要功能:
- 渲染数据:定义如何渲染或显示模型中的数据。这意味着您可以控制视图中的单元格、行或任何其他数据单元如何显示。
- 编辑数据:定义如何编辑模型中的数据。当用户点击一个单元格并尝试编辑其内容时,可以使用 QAbstractItemDelegate 来提供一个自定义的编辑器。
主要特点:
- 它提供了一个接口来定义如何在视图中显示和编辑模型中的项。这意味着你可以为列表、表格或其他任何视图控件创建自定义的渲染和编辑行为。
- 它允许创建复杂的编辑器,如自定义对话框或复杂的表单,用于编辑模型中的特定数据。
- 它允许开发者创建具有丰富界面和数据验证逻辑的视图控件。例如,开发者可以验证输入的数据是否符合特定的格式或条件。
使用示例:
当你想为 QTableView 或 QListView 中的某个特定列创建自定义编辑器时,你可以继承 QAbstractItemDelegate 并重写其方法(如 createEditor , setEditorData , setModelData 等)。然后,你可以将这个自定义委托应用到视图控件的特定列或行上。这样,当用户尝试编辑该列或行的数据时,将使用你的自定义编辑器而不是标准的单元格编辑器。
QStringListModel 和 QListView
QStringListModel
- 功能: 用于存储和管理字符串列表。
- 接口: 提供添加、删除、修改字符串的方法。
- 自动更新: 修改模型的数据后,视图会自动反映更新的内容。
QListView
- 功能: 用于显示和编辑模型中的数据。
- 默认代理: 支持使用 QLineEdit 进行字符串编辑。
- 职责: 仅作数据显示和编辑,不直接修改数据。
应用场景
- 用于创建简单的字符串列表编辑界面。
- 适用于需要实时更新和反馈的应用。
QStringListModel
QStringListModel是管理字符串列表数据的模型类,与 QListView组件搭配组成模型/视图结构,适合处理字符串列表数据。
- 它主要用于为基于 Qt 的应用程序提供数据模型,尤其是在需要展示一行行文本数据的情况下。
- 这个模型是为 QListView 或其他基于模型的视图控件设计的,以便在这些控件中展示字符串列表。
主要特点:
- 存储字符串列表: QStringListModel 用于存储一系列的字符串数据。这些字符串可以是任何文本形式,例如列表中的项目、文件的名称等。
- 简单的数据模型:相对于其他更复杂的模型(如 QStandardItemModel ), QStringListModel 是一个简单的模型,它主要关注于字符串列表的展示。它提供了插入、删除和修改字符串的基本方法。
- 与视图控件配合使用: QStringListModel 通常与 QListView 或其他基于模型的视图控件一起使用,以展示数据给用户。这使得数据的展示更加灵活和易于管理。
- 基本的CRUD操作:这个模型提供了创建(Create)、读取(Read)、更新(Update)和删除(Delete)操作的基本实现,以管理字符串列表中的数据。
示例:如何使用 QStringListModel 与 QListView 结合
cpp
#include <QApplication>
#include <QListView>
#include <QStringListModel>
#include <QVBoxLayout>
#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口
QWidget window;
window.setWindowTitle("QStringListModel Example");
// 创建布局
QVBoxLayout *layout = new QVBoxLayout(&window);
// 创建字符串列表模型
QStringListModel *model = new QStringListModel();
// 初始化数据
QStringList stringList;
stringList << "Apple" << "Banana" << "Cherry";
model->setStringList(stringList);
// 创建 QListView
QListView *listView = new QListView();
listView->setModel(model); // 设置模型
// 创建输入框和按钮用于添加新项
QLineEdit *lineEdit = new QLineEdit();
QPushButton *addButton = new QPushButton("Add Item");
// 连接按钮点击信号与添加项功能
QObject::connect(addButton, &QPushButton::clicked, [&]() {
QString newItem = lineEdit->text();
if (!newItem.isEmpty()) {
model->insertRow(model->rowCount()); // 在最后一行插入新项
model->setData(model->index(model->rowCount() - 1), newItem); // 设置数据
lineEdit->clear(); // 清空输入框
}
});
// 将组件添加到布局
layout->addWidget(listView);
layout->addWidget(lineEdit);
layout->addWidget(addButton);
window.setLayout(layout);
window.resize(300, 200);
window.show();
return app.exec();
}
代码解析
- 创建 QApplication:初始化 Qt 应用程序。
- 创建主窗口:使用 QWidget 创建主窗口,并设置标题。
- 布局:使用 QVBoxLayout 创建垂直布局,以便容纳列表和输入控件。
- 创建 QStringListModel :
- 实例化模型,并设置初始字符串列表(例如 "Apple"、"Banana" 和 "Cherry")。
- **创建 QListView **:用于显示字符串列表,并将模型与视图连接。
- 输入框和按钮:
- 使用 QLineEdit 创建一个输入框和 QPushButton 按钮,允许用户添加新项。
- 连接按钮点击信号到一个 lambda 函数,输入框内容不为空时,插入新项到模型中。
- 布局添加:将 QListView、输入框和按钮添加到布局中,并设置为主窗口的布局。
- 显示窗口:设置窗口大小并显示主窗口。
运行结果:

QListView
QListView 是用于显示列表数据的视图组件,适合展示简单的项集合。它支持许多样式、选择方式以及与模型(如 QStringListModel )的结合使用。
主要特性
- 单列展示:适合显示单列数据,可以按行排列。
- 模型/视图架构:使用 Model/View 架构,与模型(如 QStandardItemModel 或 QStringListModel )协同工作。
- 自定义项:支持自定义数据项和渲染。
- 支持选择:允许单选或多选模式,用户可以选择列表中的一个或多个项。
使用方法
- **创建 QListView **:实例化 QListView 对象。
- 设置模型:将数据模型(如 QStringListModel )与 QListView 连接。
- 配置选择模式:可配置行或复选框选择。
- 添加和更新数据:通过模型的方法来增加、修改或删除项。
示例:使用 QListView 和 QStringListModel
cpp
#include <QApplication>
#include <QListView>
#include <QStringListModel>
#include <QVBoxLayout>
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口
QWidget window;
window.setWindowTitle("QListView Example");
// 创建布局
QVBoxLayout *layout = new QVBoxLayout(&window);
// 创建 QStringListModel
QStringListModel *model = new QStringListModel();
// 初始化数据
QStringList items;
items << "Item 1" << "Item 2" << "Item 3";
model->setStringList(items);
// 创建 QListView
QListView *listView = new QListView();
listView->setModel(model); // 设置模型
// 创建输入框和按钮用于添加新项
QLineEdit *lineEdit = new QLineEdit();
QPushButton *addButton = new QPushButton("Add Item");
// 连接按钮点击信号与添加项功能
QObject::connect(addButton, &QPushButton::clicked, [&]() {
QString newItem = lineEdit->text();
if (!newItem.isEmpty()) {
model->insertRow(model->rowCount()); // 在最后一行插入新项
model->setData(model->index(model->rowCount() - 1), newItem); // 设置数据
lineEdit->clear(); // 清空输入框
}
});
// 将组件添加到布局
layout->addWidget(listView);
layout->addWidget(lineEdit);
layout->addWidget(addButton);
window.setLayout(layout);
window.resize(300, 200);
window.show();
return app.exec();
}
代码解析
- 创建 QApplication:初始化 Qt 应用程序。
- 创建主窗口:使用 QWidget 创建主窗口,并设置窗口标题。
- 布局:使用 QVBoxLayout 创建垂直布局,以便容纳列表和输入控件。
- 创建 QStringListModel :
- 实例化模型,并设置初始字符串列表(例如 "Item 1"、"Item 2" 和 "Item 3")。
- **创建 QListView **:用于显示字符串列表,并将模型与视图连接。
- 输入框和按钮:
- 使用 QLineEdit 创建一个输入框和 QPushButton 按钮,允许用户添加新项。
- 连接按钮点击信号到 lambda 函数,输入框内容不为空时,插入新项到模型中。
- 布局添加:将 QListView 、输入框和按钮添加到布局中,并设置为主窗口的布局。
- 显示窗口:设置窗口大小并显示主窗口。
运行结果:

QStandardItemModel和 QTableView
QStandardItemModel:
- 基于项的模型类。通用模型,支持树状结构和表格数据。
- 存储二维数据,项为 QStandardItem 对象。
- 保存文字、字体、对齐方式等角色的数据。
QTableView:
- 二维表格视图组件。
- 每个单元格显示模型中的一个项。
- setModel() 函数用于设置数据模型。
QItemSelectionModel:
- 项选择模型类。
- 跟踪视图组件的单元格选择状态。
- 获取选中单元格的模型索引。
QStandardItemModel
QStandardItemModel 是 Qt 6 中一个非常方便的模型类,适用于存储和管理简单的数据项。它支持多种数据类型和层级结构,适合用于 QListView 、 QTreeView 和 QTableView 等视图组件。
主要特性
- 层级结构:支持树形结构,可以创建父子项。
- 多种数据类型:支持存储文本、图像和复选框等多种类型的数据。
- 方便的API:提供丰富的方法来插入、更新和删除数据项。
使用方法
- **创建 QStandardItemModel **:实例化模型并设置行和列数。
- 添加数据项:使用 QStandardItem 来创建和管理数据项。
- 连接视图:将模型与视图(如 QListView 或 QTreeView )连接。
示例:如何使用 QStandardItemModel 和 QTreeView 来创建一个简单的树型视图。
cpp
#include <QApplication>
#include <QTreeView>
#include <QStandardItemModel>
#include <QVBoxLayout>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口
QWidget window;
window.setWindowTitle("QStandardItemModel Example");
// 创建布局
QVBoxLayout *layout = new QVBoxLayout(&window);
// 创建 QStandardItemModel
QStandardItemModel *model = new QStandardItemModel();
model->setColumnCount(2); // 设置两列
model->setHeaderData(0, Qt::Horizontal, "Item Name");
model->setHeaderData(1, Qt::Horizontal, "Description");
// 添加根项
QStandardItem *rootItem = model->invisibleRootItem();
// 添加第一个子项
QStandardItem *item1 = new QStandardItem("Item 1");
item1->setData("This is Item 1", Qt::ToolTipRole); // 设置提示信息
rootItem->appendRow(item1);
// 添加第二个子项及其子项
QStandardItem *item2 = new QStandardItem("Item 2");
rootItem->appendRow(item2);
QStandardItem *subItem = new QStandardItem("Sub Item 2.1");
item2->appendRow(subItem); // 将子项添加到 Item 2
// 添加更多项
QStandardItem *item3 = new QStandardItem("Item 3");
rootItem->appendRow(item3);
// 创建 QTreeView
QTreeView *treeView = new QTreeView();
treeView->setModel(model); // 设置模型
treeView->expandAll(); // 展开所有项
// 将组件添加到布局
layout->addWidget(treeView);
window.setLayout(layout);
window.resize(400, 300);
window.show();
return app.exec();
}
代码解析
- 创建 QApplication:初始化 Qt 应用程序。
- 创建主窗口:使用 QWidget 创建主窗口,并设置窗口标题。
- 布局:使用 QVBoxLayout 生成垂直布局。
- 创建 QStandardItemModel :
- 实例化模型,设置列数,并为列设置表头。
- 添加数据项:
- 获取根项,并创建多个子项,设置其数据及提示信息。
- 使用 appendRow 方法将子项添加到父项。
- **创建 QTreeView **:用于显示层级结构的数据模型,并将模型与视图连接。
- 展开所有项:使用 expandAll() 方法使视图展示所有项。
- 布局添加:将 QTreeView 添加到布局并设置为主窗口的布局。
- 显示窗口:设置窗口大小并显示主窗口。
运行结果:

QTableView
QTableView 是 Qt 6 中用于显示表格数据的视图类,它与模型相结合使用,可以显示和编辑二维数据结构。与 QStandardItemModel 或自定义模型结合使用,可以轻松管理和展示数据。
主要特性
- 数据展示:适合展示行列结构的数据。
- 可编辑:支持直接在视图中编辑数据。
- 数据排序:支持排序和过滤数据。
- 自定义绘制:可以通过代理类自定义单元格的外观。
使用方法
- **创建 QTableView ** 视图。
- 创建数据模型(如 QStandardItemModel )。
- 将模型设置到视图。
- (可选)设置代理以自定义单元格的显示和编辑行为。
示例:如何使用 QTableView 和 QStandardItemModel 来创建一个简单的表格应用。
cpp
#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
#include <QVBoxLayout>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口
QWidget window;
window.setWindowTitle("QTableView Example");
// 创建布局
QVBoxLayout *layout = new QVBoxLayout(&window);
// 创建 QStandardItemModel
QStandardItemModel *model = new QStandardItemModel(4, 3); // 4行3列
model->setHorizontalHeaderLabels({"Name", "Age", "Occupation"}); // 设置表头
// 填充模型数据
model->setItem(0, 0, new QStandardItem("Alice"));
model->setItem(0, 1, new QStandardItem("30"));
model->setItem(0, 2, new QStandardItem("Engineer"));
model->setItem(1, 0, new QStandardItem("Bob"));
model->setItem(1, 1, new QStandardItem("25"));
model->setItem(1, 2, new QStandardItem("Designer"));
model->setItem(2, 0, new QStandardItem("Charlie"));
model->setItem(2, 1, new QStandardItem("35"));
model->setItem(2, 2, new QStandardItem("Manager"));
model->setItem(3, 0, new QStandardItem("Diana"));
model->setItem(3, 1, new QStandardItem("28"));
model->setItem(3, 2, new QStandardItem("Artist"));
// 创建 QTableView
QTableView *tableView = new QTableView();
tableView->setModel(model); // 关联模型
// 设置单元格可编辑
for (int row = 0; row < 4; ++row) {
for (int col = 0; col < 3; ++col) {
QStandardItem *item = new QStandardItem("Editable");
item->setFlags(item->flags() | Qt::ItemIsEditable); // 设置为可编辑
model->setItem(row, col, item);
}
}
// 将组件添加到布局
layout->addWidget(tableView);
window.setLayout(layout);
window.resize(400, 300);
window.show();
return app.exec();
}
代码解析
- 创建 QApplication:初始化 Qt 应用程序。
- 创建主窗口:使用 QWidget 创建窗口,并设置标题。
- 布局:使用 QVBoxLayout 创建布局。
- 创建数据模型:
- 实例化 QStandardItemModel ,设置行数和列数。
- 使用 setHorizontalHeaderLabels 方法设置表头。
- 使用 setItem 方法填充模型数据。
- 创建 QTableView:
- 实例化 QTableView ,并通过 setModel 方法将模型与视图连接。
- 设置编辑策略:使用 setEditStrategy 设置为 OnFieldChange ,表示在单元格内容改变时立即保存。
- 布局添加:将 QTableView 添加到布局中。
- 显示窗口:设置窗口大小并显示。
运行结果:

QStandardItem
QStandardItem 是 Qt 6 中的一个用于构建模型中单个项的类,常与 QStandardItemModel 一起使用。它允许存储多种数据格式,可以设置各种属性,例如图标、字体、文本颜色等,适合构建简单和复杂的树形或表格数据结构。
主要特性
- 多类型数据:支持存储不同类型的数据,如文本、图像等。
- 自定义属性:可设置图标、字体、背景色等属性。
- 层级结构:可以创建层级结构的项目,如树形视图。
- 可编辑性:支持编辑内容、复制、粘贴等操作。
使用方法
- 创建 QStandardItem 对象。
- 为项目设置属性(如文本、图标等)。
- 将 QStandardItem 添加到模型(如 QStandardItemModel )。
示例:
以下是一个示例,展示了如何使用 QStandardItem 来创建一个简单的树形视图应用。
cpp
#include <QApplication>
#include <QTreeView>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QVBoxLayout>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口
QWidget window;
window.setWindowTitle("QStandardItem Example");
// 创建布局
QVBoxLayout *layout = new QVBoxLayout(&window);
// 创建 QStandardItemModel
QStandardItemModel *model = new QStandardItemModel();
model->setHorizontalHeaderLabels({"Name", "Description"});
// 创建根项目
QStandardItem *rootItem = model->invisibleRootItem();
// 创建子项目
QStandardItem *item1 = new QStandardItem("Fruits");
QStandardItem *item1Desc = new QStandardItem("All kinds of fruits");
rootItem->appendRow({item1, item1Desc});
// 添加子项到 Fruits
item1->appendRow(new QStandardItem("Apple"));
item1->appendRow(new QStandardItem("Banana"));
// 创建第二个子项目
QStandardItem *item2 = new QStandardItem("Vegetables");
QStandardItem *item2Desc = new QStandardItem("Various vegetables");
rootItem->appendRow({item2, item2Desc});
// 添加子项到 Vegetables
item2->appendRow(new QStandardItem("Carrot"));
item2->appendRow(new QStandardItem("Tomato"));
// 创建 QTreeView
QTreeView *treeView = new QTreeView();
treeView->setModel(model); // 关联模型
// 将组件添加到布局
layout->addWidget(treeView);
window.setLayout(layout);
window.resize(400, 300);
window.show();
return app.exec();
}
代码解析
- 创建 QApplication:初始化 Qt 应用程序。
- 创建主窗口:使用 QWidget 创建窗口,并设置标题。
- 布局:使用 QVBoxLayout 布局。
- 创建模型:
- 实例化 QStandardItemModel ,设置表头。
- 创建根项目:
- 使用 invisibleRootItem 获取根项目,并向其添加子项目。
- 创建子项目:
- 使用 appendRow 方法将项目及描述添加到根项目中。
- 创建 QTreeView:
- 将模型设置给 QTreeView 以展示树形结构。
- 布局添加:将 QTreeView 添加到布局中。
- 显示窗口:设置窗口大小并显示。
运行结果:

QltemSelectionModel类
QItemSelectionModel 是 Qt 6 中用于管理选中项的类,特别是在与模型(如 QAbstractItemModel )和视图(如 QTableView 、 QTreeView )结合使用时非常有用。它允许你选择、取消选择和查询选中的项。
主要特性
- 多项选择:支持选择多个项。
- 选中状态管理:能够管理项目的选中、取消选中状态。
- 信号和槽:提供信号以响应选中变化,例如 selectionChanged 信号。
- 与视图和模型链接:与任何基于模型的视图(如 QTableView 和 QTreeView )兼容。
示例:
以下是一个简单示例,演示如何使用 QItemSelectionModel 来选择和展示项。
cpp
#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QVBoxLayout>
#include <QWidget>
#include <QMessageBox>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口
QWidget window;
window.setWindowTitle("QItemSelectionModel Example");
// 创建布局
QVBoxLayout *layout = new QVBoxLayout(&window);
// 创建 QStandardItemModel
QStandardItemModel *model = new QStandardItemModel(5, 3); // 5行3列
model->setHorizontalHeaderLabels({"Column 1", "Column 2", "Column 3"});
// 填充模型数据
for (int row = 0; row < 5; ++row) {
for (int column = 0; column < 3; ++column) {
model->setItem(row, column, new QStandardItem(QString("Item %1").arg(row * 3 + column + 1)));
}
}
// 创建 QTableView
QTableView *tableView = new QTableView();
tableView->setModel(model); // 关联模型
// 创建 QItemSelectionModel
QItemSelectionModel *selectionModel = new QItemSelectionModel(model);
// 关联选择模型
tableView->setSelectionModel(selectionModel);
// 连接信号以处理选择变化
QObject::connect(selectionModel, &QItemSelectionModel::selectionChanged, [&](const QItemSelection &selected, const QItemSelection &deselected) {
QStringList selectedItems;
for (const QModelIndex &index : selected.indexes()) {
selectedItems << model->item(index.row(), index.column())->text();
}
QMessageBox::information(nullptr, "Selected Items", "You selected:\n" + selectedItems.join("\n"));
});
// 将 QTableView 添加到布局
layout->addWidget(tableView);
window.setLayout(layout);
window.resize(400, 300);
window.show();
return app.exec();
}
代码解析
- 创建 QApplication:初始化 Qt 应用程序。
- 创建主窗口:使用 QWidget 创建窗口,并设置标题。
- 布局:使用 QVBoxLayout 布局。
- 创建模型:
- 实例化 QStandardItemModel ,定义行列数量。
- 使用 setItem 方法填充模型数据。
- 创建 QTableView:
- 将模型设置给 QTableView 以展示数据。
- 创建 QItemSelectionModel:
- 将 QStandardItemModel 传递给 QItemSelectionModel 。
- 设置选择模型:
- 将选择模型关联到 QTableView 。
- 连接信号:
- 连接 selectionChanged 信号,响应选择变化并弹出选择的项。
- 添加 QTableView 到布局:将 QTableView 添加到布局中。
- 显示窗口:设置窗口大小并显示。
运行结果:

自定义代理
在模型/视图结构中,代理的作用可以总结为:
代理的基本功能
- 提供临时编辑器:
- 当视图组件进入编辑状态时,代理创建一个临时编辑器(默认是 QLineEdit )。
- 编辑完成后,将数据提交到数据模型。
自定义编辑器需求
- 根据数据类型定制编辑器:
- 整数列(例如"测深"):
- 使用 QSpinBox 作为编辑器。
- 浮点数列(例如"垂深""方位""总位移"):
- 使用 QDoubleSpinBox 适合浮点数输入。
- 选择列表列(例如"固井质量"):
- 使用 QComboBox 提供选择列表。
- 整数列(例如"测深"):
实现自定义代理
- 创建一个自定义代理类,继承 QStyledItemDelegate 。
- 重写 createEditor() 方法,根据列的数据类型返回适当的编辑器。
- 通过自定义代理,提高数据输入的准确性和效率。
自定义代理的功能
Qt中的QTableView组件默认使用一种代理组件,如果要替换这种默认行为,可以为QTableView的某列或某个单元格设置自定义代理。自定义代理类通常需要从QStyledItemDelegate类继承。
自定义代理类的创建
创建自定义代理类,需要继承自QStyledItemDelegate类。这是创建自定义代理类的基本步骤。
设置自定义代理
设置自定义代理有三种方式:
- setItemDelegate():将自定义代理设置为整个视图组件的代理。
- setItemDelegateForColumn(int column, QAbstractItemDelegate *delegate):为视图组件的某一列设置自定义代理。
- setItemDelegateForRow(int row, QAbstractItemDelegate *delegate):为视图组件的某一行设置自定义代理。
默认代理类
QStyledItemDelegate是视图组件使用的默认代理类。当不设置自定义代理时,视图组件会使用这个默认代理。
目的和意义
- 通过替换默认代理,可以定制QTableView组件的显示和行为,以满足特定的需求。例如,可以自定义单元格的渲染方式、编辑方式等。
QStyledltemDelegate类
QStyledItemDelegate 是 Qt 中用于实现自定义视图组件的代理类,主要用于控制如何绘制和编辑模型中的项。它是 QAbstractItemDelegate 的子类,提供了一些增强的功能。
主要功能:
- 绘制项 :
- paint() 方法用于自定义绘制项的外观,可以设置颜色、字体、对齐方式等。
- 支持使用样式表来调整样式。
- 创建编辑器 :
- createEditor() 方法用于创建适合用户编辑的控件(如 QLineEdit 、 QSpinBox 等)。
- 通过设置自定义编辑器,使数据输入更加符合需求。
- 设置数据 :
- setEditorData() 方法用于将模型中的数据设置到编辑器。
- setModelData() 方法用于将编辑器中的数据保存回模型。
- 更新编辑器 :
- updateEditorGeometry() 方法用于调整编辑器的几何形状,使其适应当前单元格大小。
使用场景:
- 当需要在视图组件(如 QTableView 和 QListView )中使用不同的控件来编辑或显示数据时,可以使用 QStyledItemDelegate 。
- 它适用于希望自定义数据项外观和编辑交互的应用程序。
示例:如何使用 QStyledItemDelegate 创建一个自定义代理,使用 QSpinBox 来编辑整数值。
cpp
#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QSpinBox>
// 自定义代理类
class SpinBoxDelegate : public QStyledItemDelegate {
public:
// 创建编辑器
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
QSpinBox *editor = new QSpinBox(parent);
editor->setMinimum(0); // 设置最小值
editor->setMaximum(100); // 设置最大值
return editor;
}
// 设置编辑器的初始数据
void setEditorData(QWidget *editor, const QModelIndex &index) const override {
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(index.data().toInt());
}
// 提交数据到模型
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override {
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
model->setData(index, spinBox->value());
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QTableView tableView;
QStandardItemModel model(5, 2); // 5行2列
// 填充数据
for (int row = 0; row < 5; ++row) {
for (int col = 0; col < 2; ++col) {
model.setItem(row, col, new QStandardItem(QString::number(row * col)));
}
}
tableView.setModel(&model);
// 设置自定义代理
SpinBoxDelegate *delegate = new SpinBoxDelegate();
tableView.setItemDelegateForColumn(0, delegate); // 为第一列设置自定义代理
tableView.show();
return app.exec();
}
**自定义代理类 SpinBoxDelegate **:
- 继承自 QStyledItemDelegate 。
- 实现了三个主要方法:
- createEditor() :返回 QSpinBox 作为编辑器。
- setEditorData() :将模型数据设置到编辑器。
- setModelData() :将编辑器中的数据提交回模型。
主函数:
- 创建 QTableView 和 QStandardItemModel 。
- 填充模型数据。
- 设置自定义代理并展示表格。
运行结果:

QFileSystemModel和QTreeView
QFileSystemModel 类
- 功能 :
- 为本机文件系统提供模型。
- 可访问和操作本机文件系统。
- 主要接口 :
- setRootPath() : 设置根目录。
- 提供获取文件名、目录名、文件大小及详细信息的方法。
- 支持创建、删除和重命名目录。
QTreeView 类
- 功能 :
- 显示树状模型的视图组件。
- 与 QFileSystemModel 结合用于显示文件系统。
- 特性 :
- 点击目录时,可以触发右侧 QListView 和 QTableView 更新显示该目录下的内容。
- 可定义信号来处理目录和文件节点的交互。
应用结构及交互
- 整体界面 :
- 使用 QTreeView 显示文件系统目录树。
- QListView 和 QTableView 显示选中目录的文件和子目录。
- 下方标签显示当前选中节点的信息。
- 交互流程 :
- 在 QTreeView 上选择目录更新右侧视图。
- 点击目录或文件节点更新标签显示详细信息。
QFileSystemModel
QFileSystemModel 是一个 Qt 模型类,用于表示文件系统的层次结构。
它提供文件和目录的信息,可与视图组件(如 QTreeView 或 QListView )结合使用,以便用户浏览文件系统。
主要功能:
- 文件和目录的表示: 自动更新与文件系统的变化同步。
- 支持多种文件属性: 如文件名、大小、类型和最后修改时间。
- 提供功能: 如添加、删除文件和目录。
示例:
cpp
#include <QApplication>
#include <QFileSystemModel>
#include <QTreeView>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QFileSystemModel model;
model.setRootPath(QDir::rootPath()); // 设置根路径
QTreeView treeView;
treeView.setModel(&model);
treeView.setRootIndex(model.index(QDir::rootPath())); // 设置根索引
treeView.setColumnWidth(0, 250); // 设置列宽
treeView.show();
return app.exec();
}
- QStyledItemDelegate 让你可以自定义视图中项的显示和编辑方式。
- QFileSystemModel 提供了一个强大的文件系统模型,可方便地与视图组件交互,帮助用户浏览和管理文件。
运行结果:

QTreeView
QTreeView 是 Qt 中用于显示分层数据的视图组件,常用于呈现树形结构的数据(如文件系统目录、组织结构等)。它支持展开和折叠节点,允许用户以树形方式查看和组织信息。
主要功能:
- 分层结构显示: 适用于显示具有父子关系的数据。
- 支持模型-视图架构: 可与各种模型(如 QStandardItemModel 、 QFileSystemModel 等)结合使用。
- 自定义项的显示与编辑: 提供改变项外观和行为的能力。
示例:如何使用 QTreeView 来显示分层数据。
cpp
#include <QApplication>
#include <QTreeView>
#include <QStandardItemModel>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建树形视图
QTreeView treeView;
// 创建模型并添加数据
QStandardItemModel model;
model.setHorizontalHeaderLabels({"Item"});
// 添加根节点
QStandardItem *rootItem = model.invisibleRootItem();
QStandardItem *item1 = new QStandardItem("Item 1");
QStandardItem *item2 = new QStandardItem("Item 2");
rootItem->appendRow(item1);
rootItem->appendRow(item2);
// 添加子节点
QStandardItem *subItem1 = new QStandardItem("Sub Item 1.1");
QStandardItem *subItem2 = new QStandardItem("Sub Item 1.2");
item1->appendRow(subItem1);
item1->appendRow(subItem2);
// 设置模型
treeView.setModel(&model);
// 设置列宽
treeView.setColumnWidth(0, 200);
// 展示树视图
treeView.expandAll(); // 展开所有节点
treeView.show();
return app.exec();
}
代码解析
- 应用程序初始化: 创建 QApplication 实例。
- 创建 QTreeView 实例: 用于显示层次结构的数据。
- **创建 QStandardItemModel **: 用于存储树形数据,通过 setHorizontalHeaderLabels() 设置模型头部。
- 构建树结构: 通过 appendRow() 方法构造父子关系。
- 设置树视图模型: 将模型与树视图关联。
- 展开所有节点: 使用 expandAll() 方法使所有节点展开。
- 运行应用程序: 通过 app.exec() 进入事件循环。
运行结果:
