Qt之基础体系

基础体系

信号与槽

1、信号(signal):所谓信号槽(观察者模式),信号本质是事件。信号展现方式就是函数。当某一个事件发生之后,则发出一个信号(signal)。

2、槽(slot):就是对信号响应的函数,槽就是一个函数。 槽函数与普通函数区别:槽函数可以与一个信号关联,当信号被发射的时候,关联的槽函数被自动执行处理。信号与槽关联是使用Q0bject:connect)函数进行实现。

3、信号函数只需要声明(不需要定义(实现)),而槽函数需要定义(实现)信号和槽机制底层是通过函数之间进行相互调用实现的。每个信号都可以用函数来表示,称为信号函数;每个槽也可以用函数表示,称为槽函数。槽函数可以使用 public slots/protected slots/private slots 修饰。signals和 slots 是 Qt 开发当中在 C++语言基础之上扩展的关键词,专门用于指明信号函数和槽函数。

4、在Qt中,connect函数是信号与槽(Signals and Slots)机制的核心,它用于建立对象之间的通信。当某个特定事件发生时(比如用户点击了一个按钮),一个对象会发出一个信号(Signal)。这个信号可以被其他对象的一个槽(Slot)函数接收并处理,从而实现对象之间的通信和解耦。

5、信号与槽机制效率:1增强对象的之间通信的灵活性,但是也会损失一些性能。通过传递一个信号来调用槽函数将会比直接调用非虚函数运行速度慢,主要原因多线程的时候,信号可能需要排队等待;编组/解组传递的参数;安全地遍历所有的关联;需要定位接收信号的对象。

cpp 复制代码
connect(sender, &SenderClass::signalName, receiver, &ReceiverClass::slotName);

sender:发出信号的对象指针。

&SenderClass::signalName:指向发送者类中信号的指针。

receiver:接收信号的对象指针。

&ReceiverClass::slotName:指向接收者类中槽函数的指针。

示例:

c 复制代码
    // 增加标签
    lab1 = new QLabel(this);
    lab1->setText("请输入球的半径:");
    // 标签2
    lab2 = new QLabel(this);
    // 输入框
    lEdit = new QLineEdit(this);
    // 按钮计算
    pbt = new QPushButton(this);
    pbt->setText("计算圆球体积");
    // 布局管理器
    QGridLayout *gl = new QGridLayout(this);
    gl->addWidget(lab1, 0, 0);
    gl->addWidget(lab2, 1, 0);
    gl->addWidget(lEdit, 0, 1);
    gl->addWidget(pbt, 1, 1);

connect的常见用法:

cpp 复制代码
    // 关联槽函数
    // 按钮点击/释放
    connect(pbt, &QPushButton::clicked, this, &Widget::CalcBallVolume);
    // 文本中的变化
    connect(lEdit, SIGNAL(textChanged(QString)), this, SLOT(CalcBallVolume()));
    connect(lEdit, &QLineEdit::textChanged, this, &Widget::CalcBallVolume);

字符串类应用

1. 操作字符串

QString提供一个二元的"+"操作符,主要用于组合两个字符串。QStringstr1= "Hello world"传递给QString一个const char*类型的ASCII字符串"Hello world",它被解释为一个典型的以"\0"结尾的C类型字符串。

QString::append()函数具备与"+="操作符同样的功能,直接在一个字符串末尾添加另一个字符串。

cpp 复制代码
    // +
    QString str1 = "hello";
    str1 += " world!";
    qDebug() << str1;
    str1.append("!");

QString::sprintf 函数是 Qt 框架中 QString 类的一个成员函数,它提供了一种将格式化的数据插入到字符串中的方式。这个函数与 C/C++ 标准库中的 sprintf 函数在功能上类似,但 QString::sprintf 是专为 QString 设计的,因此它完全支持 Unicode 编码,可以处理各种语言的文本。

cpp 复制代码
QString str;  
str.sprintf("%s was born in %d.", "John", 1990);  
// str 现在是 "John was born in 1990."

QString::arg 是 Qt 框架中 QString 类的一个非常有用的成员函数,它允许开发者将变量或值动态地插入到字符串模板中,从而构建出包含动态内容的字符串。这个函数非常灵活,支持多种数据类型,包括整数、浮点数、字符串等,并且允许自定义格式化选项,如字段宽度、基数(进制)和填充字符。

cpp 复制代码
QString str = QString("%1 %2 %3").arg("Hello").arg("world").arg("!");  
// 输出: Hello world !

当需要插入多个参数时,可以连续调用 arg 函数,参数的替换顺序是按照 %1、%2、%3...的顺序进行的。

QString::insert 是 Qt 框架中 QString 类的一个成员函数,它允许在字符串的指定位置插入另一个字符串。这个函数提供了一种灵活的方式来修改字符串的内容,而不需要重新创建整个字符串。

cpp 复制代码
QString &QString::insert(int position, const QString &str)

position:要插入新字符串的位置索引。索引从 0 开始,即字符串的第一个字符位于索引 0 处。

str:要插入的字符串。

该函数会修改调用它的 QString 对象,将 str 插入到 position 指定的位置,并返回对修改后的字符串的引用。

cpp 复制代码
QString str = "Hello";  
str.insert(5, " World"); // 在索引 5 的位置插入 " World"  
// 现在 str 的值为 "Hello World"

在这个例子中," World" 被插入到 "Hello" 的末尾(因为索引 5 实际上是 "Hello" 字符串的末尾之后的位置)。如果 position 的值超出了原字符串的长度,则 str 会被添加到原字符串的末尾.

2. 查询字符串

QString::startsWith 是 Qt 框架中 QString 类的一个成员函数,用于判断一个字符串是否以指定的前缀开头。这个函数非常有用,特别是在处理字符串匹配和条件判断时。

cpp 复制代码
bool QString::startsWith(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

str:要检查的前缀字符串。

cs:一个枚举值,指定比较时是否区分大小写。默认值为 Qt::CaseSensitive(区分大小写),也可以设置为 Qt::CaseInsensitive(不区分大小写)。

返回值:如果字符串以指定的前缀开头,则返回 true;否则返回 false。

cpp 复制代码
QString str = "Hello, world!";  
bool result1 = str.startsWith("Hello", Qt::CaseSensitive); // 返回 true  
bool result2 = str.startsWith("hello", Qt::CaseSensitive); // 返回 false  
bool result3 = str.startsWith("hello", Qt::CaseInsensitive); // 返回 true

QString::contains 用于判断一个字符串是否包含另一个指定的子串。这个函数在处理字符串匹配、搜索和条件判断时非常有用。

cpp 复制代码
bool QString::contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

str:要查找的子串。

cs:一个枚举值,指定搜索时是否区分大小写。默认值为 Qt::CaseSensitive(区分大小写),也可以设置为 Qt::CaseInsensitive(不区分大小写)。

返回值:如果字符串中包含与 str 相等的子串(根据 cs 参数确定大小写敏感性),则返回 true;否则返回 false。

cpp 复制代码
QString str = "Hello, World!";  
QString sub = "World";  
bool result1 = str.contains(sub); // 返回 true,区分大小写  
bool result2 = str.contains("world", Qt::CaseInsensitive); // 返回 true,不区分大小写  
bool result3 = str.contains("Qt"); // 返回 false

QString::compare 是用于比较两个字符串。这个函数可以按照字典序对字符串进行比较,并返回一个整数来表示比较的结果。

cpp 复制代码
int QString::compare(const QString &other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

other:要与之比较的字符串。

cs:一个枚举值,指定比较时是否区分大小写。默认值为 Qt::CaseSensitive(区分大小写),也可以设置为 Qt::CaseInsensitive(不区分大小写)。

返回值:

如果两个字符串相等(根据 cs 参数确定大小写敏感性),则返回 0。

如果调用字符串(即调用 compare 函数的字符串)在字典序上小于 other 字符串,则返回一个小于 0 的值。

如果调用字符串在字典序上大于 other 字符串,则返回一个大于 0 的值。

cpp 复制代码
QString str1 = "Hello";  
QString str2 = "hello";  
QString str3 = "World";  
  
int result1 = str1.compare(str2, Qt::CaseSensitive); // 返回大于0的值,因为区分大小写  
int result2 = str1.compare(str2, Qt::CaseInsensitive); // 返回0,因为不区分大小写  
int result3 = str1.compare(str3); // 返回小于0的值,因为"Hello"在字典序上小于"World"

QMap & QHash & QVector

QMap

QMap是Qt框架中的一个关联容器类,用于存储键值对(key-value pairs)并提供基于键的快速查找功能。

基本特性

模板类:QMap是模板类,可以存储任意类型的数据作为键和值。

红黑树实现:QMap基于红黑树实现,因此查找、插入和删除操作都具有O(log n)的时间复杂度,保证了高效的性能。

自动排序:QMap可以自动对键进行排序,并且支持自定义排序函数。默认情况下,键是按照升序排序的。

存储多个值:QMap支持一个键对应多个值,这可以通过insertMulti方法实现,或者使用QMultiMap类。

迭代器支持:QMap支持迭代器,可以方便地遍历所有元素。Qt提供了Java风格的迭代器(QMapIterator和QMutableMapIterator)和STL风格的迭代器(QMap::const_iterator和QMap::iterator)。

二、使用方法

cpp 复制代码
实例化QMap对象:
QMap<QString, int> map;
插入数据:
使用operator[]:

map["math"] = 100;
使用insert方法:

map.insert("English", 98);
使用insertMulti方法插入多个值(针对同一键):
map.insertMulti("Math", 100);  
map.insertMulti("Math", 150);
查找数据:
使用value方法通过键查找对应的值:

int value = map.value("Math"); // 返回与"Math"键关联的最后一个插入的值
使用values方法获取与特定键关联的所有值(如果使用了insertMulti):

QList<int> values = map.values("Math");
遍历数据:
使用Java风格的迭代器:

QMapIterator<QString, int> iterator(map);  
while (iterator.hasNext()) {  
    iterator.next();  
    qDebug() << iterator.key() << ":" << iterator.value();  
}
使用STL风格的迭代器:
for (QMap<QString, int>::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) {  
    qDebug() << it.key() << ": " << it.value();  
}
删除数据:
使用remove方法删除具有指定键的项:

map.remove("math");
使用clear方法清除QMap中的所有项:

map.clear();
检查键是否存在:
使用contains方法检查QMap中是否包含某个键:

bool isOk = map.contains("Math");

注意事项

QMap的键类型必须提供operator<()来指定一个全序,以便QMap能够对其进行排序。

当使用QMap时,如果键类型没有提供operator<(),但提供了比较函数或可以自定义比较函数,也可以通过QMap的构造函数或qSort函数等方式来指定排序规则。

在使用QMap时,如果只需要存储一个键对应一个值的映射关系,并且不关心键的排序,可以考虑使用QHash,因为QHash在平均情况下具有更快的查找速度。

QHash

QHash是Qt框架中的一个基于哈希表的模板类,用于存储键值对,并提供了快速的查找、插入和删除操作。

基本特性

数据结构:QHash基于哈希表数据结构,实现了常数时间复杂度的查找、插入和删除操作(平均情况下为O(1),最坏情况下为O(n))。

键值对存储:QHash存储的是键值对,键和值可以是任意Qt支持的数据类型(包括自定义的类型),前提是键必须支持哈希函数和比较操作。

自动调整:QHash会根据元素的数量自动调整内部存储的大小,以保持高效的操作。

迭代器接口:QHash提供了迭代器接口,可以方便地遍历所有存储的键值对。

无序性:QHash存储的元素是无序的,即不保证元素的顺序与插入顺序一致。

主要操作

cpp 复制代码
创建和初始化
创建一个空的QHash:QHash<KeyType, ValueType> hash;
使用初始值创建QHash:QHash<KeyType, ValueType> hash = {{key1, value1}, {key2, value2}, ...};
插入元素
使用insert()函数:hash.insert(key, value);
使用下标操作符(如果键已存在,则替换其值):hash[key] = value;
删除元素
使用remove()函数:hash.remove(key);
使用迭代器(如果需要):hash.erase(iterator);
查找元素
使用contains()函数检查是否包含特定键:bool contains = hash.contains(key);
使用value()函数获取键对应的值(如果不存在,则返回默认值):ValueType value = hash.value(key, defaultValue);
遍历哈希表
使用范围循环遍历:for (auto key : hash.keys()) { qDebug() << key << ":" << hash[key]; }
使用迭代器遍历:QHash<KeyType, ValueType>::const_iterator it; for (it = hash.constBegin(); it != hash.constEnd(); ++it) { qDebug() << it.key() << ":" << it.value(); }
其他操作
获取哈希表的大小:int size = hash.size();
检查哈希表是否为空:bool isEmpty = hash.isEmpty();
获取所有的键和值:QList<KeyType> keys = hash.keys(); QList<ValueType> values = hash.values();

自定义类型支持

如果要在QHash中使用自定义类型作为键,需要提供该类型的qHash()函数和operator==()操作符。这样,QHash才能正确地计算哈希值和比较键的相等性。

线程安全性

QHash不是线程安全的。如果在多线程环境中使用,需要自行加锁以保证线程安全。可以使用Qt提供的互斥锁(QMutex)、读写锁(QReadWriteLock)等同步机制。

高级用法

insertMulti():允许插入多个具有相同键的值(但QHash本身不直接支持此功能,通常使用QMultiHash)。

自定义哈希函数和比较函数:对于复杂的自定义类型,可以通过特化qHash()函数和operator==()操作符来支持。

容量管理:可以使用reserve()函数预分配哈希表的容量,以减少后续插入操作时的内存分配次数。

QVector

QVector是Qt框架中提供的一个动态数组类,用于存储和操作动态大小的对象。它类似于C++标准库中的std::vector,但提供了更多的功能和便利性。以下是对QVector的详细介绍:

基本特性

动态大小:QVector可以根据需要自动调整大小,无需手动管理内存。

高效访问:QVector提供了快速的随机访问,可以通过索引直接访问元素。

插入和删除:QVector支持在任意位置插入和删除元素,自动调整数组大小。

自动复制:QVector在插入和复制元素时会自动进行深拷贝,确保数据的独立性。

内存优化:QVector会根据需要自动分配和释放内存,减少内存占用。

使用场景

QVector可以用于存储和管理一组数据,如数字、字符串、自定义对象等。

它也可以作为其他容器类的基础,如栈、队列、堆等。

在图形界面编程中,QVector可以用于存储和管理图形界面元素,如控件、图像等。

QVector还可以用于实现各种算法,如排序、查找、过滤等。

定义与初始化

使用QVector前,需要包含其头文件#include 。QVector可以通过多种方式进行定义和初始化:

使用默认构造函数,创建一个空的QVector对象。

使用带有初始大小参数的构造函数,创建一个指定大小的QVector对象,元素初始化为默认值。

使用带有初始值和大小参数的构造函数,创建一个指定大小并初始化所有元素的QVector对象。

使用拷贝构造函数,创建一个与已有QVector相同的新QVector对象。

使用列表初始化语法,创建一个包含指定元素的QVector对象。

主要操作

QVector提供了一系列方便的操作函数,可用于对元素进行增删改查等操作:

添加元素:可以使用append()、push_back()等方法在QVector尾部添加元素,也可以使用prepend()、push_front()等方法在头部添加元素。

插入元素:可以使用insert()方法在QVector的任意位置插入元素。

删除元素:可以使用remove()方法删除指定位置的元素,或者使用pop_back()、pop_front()方法删除最后一个或第一个元素。

访问元素:可以使用at()、operator[]等方法通过索引访问元素。

替换元素:可以使用replace()方法替换QVector中指定下标的元素。

查找元素:可以使用indexOf()方法查找元素在QVector中的位置。

容量与迭代器

容量:QVector的容量是指其内部可以存储的元素的数量,这不一定等于其当前存储的元素数量。可以使用capacity()方法获取QVector的容量,使用reserve()方法预留足够的空间。

迭代器:QVector提供了STL风格的迭代器,可以使用begin()和end()方法获取指向第一个元素和最后一个元素之后位置的迭代器。

注意事项

在使用QVector时,需要注意其自动内存管理的特性,避免内存泄漏等问题。

QVector在插入和删除元素时可能会重新分配内存,这可能会影响性能。因此,在需要频繁进行插入和删除操作的场景下,需要谨慎使用QVector。

QVariant

QVariant是Qt框架中一个非常强大的类,它提供了一种通用的方式来存储和处理各种不同类型的数据。

基本概述

定义:QVariant是Qt中用于处理各种数据类型的通用类。它可以存储几乎任何类型的数据,包括基本数据类型(如整数、浮点数、布尔值等)、字符串、自定义数据类型、以及Qt的各种对象类型。

功能:QVariant在Qt中被广泛用于处理不同的数据类型,支持自动类型转换,提供了类型安全的操作,支持跨线程操作,并且可以用于信号和槽、属性系统、数据模型等多种场景。

主要特性

通用性:QVariant可以存储各种不同的数据类型,包括基本数据类型、对象类型、自定义类型等。

自动类型转换:QVariant具有自动类型转换的功能,可以在需要时将存储的数据自动转换为目标类型。

类型安全:QVariant提供了类型安全的接口,可以在运行时检查数据类型,并在类型不匹配时进行错误处理。

跨线程支持:QVariant支持在不同线程之间安全地传递和操作数据,适合多线程应用程序的开发。

容器支持:QVariant可以作为QMap和QList等容器的数据类型,支持复杂的数据结构。

支持的数据类型

QVariant支持多种数据类型,包括但不限于:

基本数据类型:int、double、bool等。

字符串:QString。

日期和时间:QDate、QTime、QDateTime。

颜色和图形:QColor、QImage、QPixmap等。

字节数组:QByteArray。

容器类型:QList、QMap、QVariantList、QVariantMap等。

自定义类型:通过QDataStream的插入和提取操作符实现存储和恢复。

使用方法

QVariant的使用非常灵活,以下是一些基本的使用方法:

存储数据:可以使用QVariant的构造函数或setValue()方法存储数据。

获取数据:可以使用toXXX()系列方法(如toInt()、toDouble()、toString()等)将QVariant中的数据转换为特定类型。

类型检查:可以使用type()方法检查QVariant当前存储的数据类型,或使用canConvert()方法检查是否可以转换为特定类型。

注意事项

性能问题:QVariant不同于其他基础数据类型,其存储和转换操作可能涉及一定的性能开销。因此,在性能要求较高的场景下,应谨慎使用QVariant。

类型安全:虽然QVariant提供了类型安全的接口,但在进行类型转换时仍需注意类型匹配问题。如果转换类型与目标类型不匹配,可能会引发运行时错误。

内存占用:QVariant的存储需要占用一定的内存空间。因此,在存储大量数据或复杂数据结构时,应关注内存使用情况。

相关推荐
qq_433554549 分钟前
C++ 面向对象编程:+号运算符重载,左移运算符重载
开发语言·c++
数据小爬虫@28 分钟前
如何高效利用Python爬虫按关键字搜索苏宁商品
开发语言·爬虫·python
ZJ_.30 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
Narutolxy35 分钟前
深入探讨 Go 中的高级表单验证与翻译:Gin 与 Validator 的实践之道20241223
开发语言·golang·gin
Hello.Reader42 分钟前
全面解析 Golang Gin 框架
开发语言·golang·gin
禁默1 小时前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Code哈哈笑1 小时前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
程序猿进阶1 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
qq_433618441 小时前
shell 编程(二)
开发语言·bash·shell
charlie1145141911 小时前
C++ STL CookBook
开发语言·c++·stl·c++20