当前位置: 首页 > news >正文

QT学习笔记-QStringList,QTimer

QStringList-存储和管理一系列的字符串

在Qt框架中,QStringList 是一个模板类 QList<QString> 的特化,专门用于处理 QString 对象(即Qt中的字符串)的列表。当你看到这样的声明:

QStringList m_rec_topicList;

这里,m_rec_topicList 是一个 QStringList 类型的变量,用于存储和管理一系列的字符串(QString 对象)。以下是对 QStringList 在这个上下文中的详细讲解:

一、基本特性

  • 类型QStringList 是 QList<QString> 的一个特化,因此它继承了 QList 的所有功能,并针对字符串进行了优化。
  • 存储QStringList 内部使用动态数组来存储字符串,这意味着它可以根据需要自动调整大小。
  • 线程安全QStringList 本身并不是线程安全的。如果在多线程环境中使用,需要采取适当的同步措施。

二、主要功能

  1. 添加和移除字符串
    • append(const QString &str):在列表末尾添加一个字符串。
    • prepend(const QString &str):在列表开头添加一个字符串。
    • insert(int i, const QString &str):在指定位置插入一个字符串。
    • removeAt(int i):移除指定位置的字符串。
    • removeOne(const QString &str):移除列表中第一次出现的指定字符串。
    • removeAll(const QString &str):移除列表中所有出现的指定字符串。
  2. 访问字符串
    • at(int i) const:返回指定位置的字符串(带边界检查)。
    • operator[](int i) const:返回指定位置的字符串(不带边界检查,如果索引超出范围,结果未定义)。
    • first() const:返回列表中的第一个字符串。
    • last() const:返回列表中的最后一个字符串。
    • value(int i, const QString &defaultValue = QString()) const:返回指定位置的字符串,如果索引超出范围,则返回默认值。
  3. 遍历
    • 可以使用 foreach 循环(Qt特有的语法糖)或基于范围的 for 循环(C++11及以后)来遍历 QStringList
  4. 排序
    • sort(Qt::SortOrder order = Qt::AscendingOrder):对列表进行排序,可以指定升序或降序。
  5. 查找
    • indexOf(const QString &str, int from = 0) const:返回指定字符串在列表中第一次出现的索引,从指定位置开始搜索。
    • lastIndexOf(const QString &str, int from = -1) const:返回指定字符串在列表中最后一次出现的索引,从指定位置开始向后搜索(如果 from 为 -1,则从列表末尾开始搜索)。
    • contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const:检查列表中是否包含指定字符串,可以指定是否区分大小写。
  6. 连接和分割
    • join(const QString &separator) const:将列表中的字符串连接成一个字符串,使用指定的分隔符。
    • (注意:分割操作通常使用 QString 的 split() 方法,而不是 QStringList 的方法,因为分割的结果可以直接赋值给 QStringList。)

三、使用示例

#include <QStringList>
#include <QDebug>int main() {
QStringList topicList;
topicList.append("Qt");
topicList.append("C++");
topicList.prepend("Programming");qDebug() << "Topic list:" << topicList;// 排序
topicList.sort();
qDebug() << "Sorted topic list:" << topicList;// 查找
int index = topicList.indexOf("C++");
if (index != -1) {
qDebug() << "C++ found at index:" << index;
}// 连接
QString joinedList = topicList.join(", ");
qDebug() << "Joined list:" << joinedList;return 0;
}

 

在这个示例中,我们创建了一个 QStringList 变量 topicList,并向其中添加了一些字符串。然后,我们对列表进行了排序、查找和连接操作。

QTimer-指定的时间间隔后发出信号

在C++中,特别是使用Qt框架时,QTimer 是一个常用的类,它用于在指定的时间间隔后发出信号。当你看到这样的声明:

QTimer *publishTimer = nullptr;

 

这里,publishTimer 是一个指向 QTimer 对象的指针,并且它被初始化为 nullptr,意味着它当前不指向任何有效的 QTimer 对象。以下是对这个声明的详细讲解:

一、QTimer 类

  • 功能QTimer 类提供了定时器功能,它可以在指定的时间间隔后发出 timeout() 信号。这个信号可以被连接到任何槽函数,以实现定时执行某些操作的目的。
  • 继承QTimer 继承自 QObject 类,因此它拥有 QObject 的所有功能和特性,比如信号和槽机制、对象树管理等。
  • 精度QTimer 的精度取决于底层操作系统的定时器机制,通常对于毫秒级别的定时是足够的,但对于更精确的定时(比如微秒级别),可能需要使用其他方法。

二、指针和nullptr

  • 指针:在C++中,指针是一种变量类型,它存储了另一个变量的内存地址。通过指针,你可以直接访问和操作内存中的数据。
  • nullptrnullptr 是C++11及以后版本中引入的一个字面常量,用于表示空指针。它取代了旧的 NULL 宏(通常定义为 0 或 (void*)0),提供了更好的类型安全性和可读性。
  • 初始化:将指针初始化为 nullptr 是一种良好的编程习惯,它可以防止指针在未经初始化的情况下被使用,从而避免潜在的内存访问错误。

三、publishTimer 的使用

  1. 创建 QTimer 对象
    在使用 publishTimer 之前,你需要为它分配一个有效的 QTimer 对象。这通常通过 new 关键字来完成:

publishTimer = new QTimer(this); // 假设当前代码在 QObject 的子类中,且 this 指向该对象
  1. 这里,this 参数指定了 QTimer 对象的父对象。在Qt中,将对象设置为另一个对象的子对象意味着子对象的生命周期将由父对象管理。当父对象被销毁时,它的所有子对象也会被自动销毁。

  2. 连接信号和槽
    创建 QTimer 对象后,你通常需要连接它的 timeout() 信号到一个槽函数,以便在定时器超时时执行特定的操作:

    connect(publishTimer, &QTimer::timeout, this, &YourClass::yourSlotFunction);

    这里,YourClass 是包含槽函数的类名,yourSlotFunction 是要在定时器超时时调用的槽函数名。

  3. 启动定时器
    使用 start() 方法来启动定时器,并指定时间间隔(以毫秒为单位):

    publishTimer->start(1000); // 每1000毫秒(即1秒)发出一次timeout信号
  4. 停止定时器
    使用 stop() 方法来停止定时器:

    publishTimer->stop();
  5. 清理
    如果你不再需要 publishTimer,并且想要释放它占用的内存,你应该先停止定时器(如果它正在运行),然后删除指针指向的对象。但是,由于 publishTimer 是父对象的子对象,在父对象被销毁时,publishTimer 也会被自动销毁。因此,在大多数情况下,你不需要手动删除它。然而,如果你将 publishTimer 设置为 nullptr(例如,在对象被销毁之前),这可以作为一种防御性编程措施,以防止在对象生命周期的后期意外地使用该指针。

    publishTimer->stop();
    publishTimer = nullptr; // 可选,但推荐作为防御性编程措施

请注意,在现代C++中(特别是使用Qt框架时),通常建议使用智能指针(如 QScopedPointer 或 QSharedPointer)来管理动态分配的对象,以避免手动管理内存和指针带来的复杂性。然而,在Qt中,由于对象树和父子关系的存在,以及 deleteLater() 方法的提供,手动管理内存的情况并不常见。

QScopedPointer /QSharedPointer-自动管理动态分配的内存,从而避免内存泄漏和悬挂指针

QScopedPointer-独占所有权-局部变量

  • 所有权QScopedPointer 提供了严格的独占所有权语义。这意味着一个 QScopedPointer 实例在其生命周期内拥有它所指向的对象,并且该对象不能被其他 QScopedPointer 或裸指针(raw pointer)共享。
  • 生命周期QScopedPointer 的生命周期与其所在的作用域(scope)紧密相关。当 QScopedPointer 超出其作用域时,它所指向的对象会被自动删除。
  • 用途QScopedPointer 通常用于局部变量,特别是当对象的生命周期应该严格局限于某个函数或代码块时。
  • 转移所有权:虽然 QScopedPointer 不支持复制,但它可以通过 QScopedPointer<T>::take() 方法转移所有权给另一个 QScopedPointer 或裸指针,并重置自身为 nullptr
#include <QScopedPointer>
#include <iostream>int main() {// 使用 QScopedPointer 管理一个动态分配的整数数组QScopedPointer<int[]> scopedArray(new int[10]);// 初始化数组for (int i = 0; i < 10; ++i) {scopedArray[i] = i * i; // 例如,存储平方值}// 打印数组内容for (int i = 0; i < 10; ++i) {std::cout << scopedArray[i] << " ";}std::cout << std::endl;// 不需要手动删除数组,QScopedPointer 会在作用域结束时自动删除它return 0;
}

QSharedPointer-共享所有权-多个对象或线程

  • 所有权QSharedPointer 提供了共享所有权语义。这意味着多个 QSharedPointer 实例可以共享同一个对象,并且只有当最后一个 QSharedPointer 被销毁或重置时,对象才会被删除。
  • 生命周期QSharedPointer 的生命周期与其自身的生命周期以及它所指向的对象的共享计数有关。只要至少有一个 QSharedPointer 指向对象,对象就会保持存活。
  • 用途QSharedPointer 通常用于需要在多个对象或线程之间共享数据的场景。
  • 线程安全QSharedPointer 是线程安全的,可以在多个线程之间安全地共享和传递。

注意事项

  • 避免循环引用:在使用 QSharedPointer 时,要注意避免循环引用,这可能会导致内存泄漏。循环引用发生在两个或多个对象相互持有对方的 QSharedPointer 时。
  • 性能考虑:虽然 QSharedPointer 提供了方便的共享所有权管理,但它也引入了额外的开销,包括维护共享计数和可能的线程同步。因此,在性能敏感的场景中,要谨慎使用 QSharedPointer
  • 裸指针的使用:尽量避免使用裸指针来管理动态内存,而是使用智能指针来确保内存的正确释放。如果必须使用裸指针,请确保在适当的时候手动删除对象,并避免悬挂指针的问题。
#include <QSharedPointer>
#include <iostream>class MyString {
public:MyString(const std::string &str) : data(new std::string(str)) {}~MyString() {std::cout << "MyString destructor called, data: " << *data << std::endl;delete data;}std::string* getData() const {return data;}
private:std::string *data;
};int main() {// 使用 QSharedPointer 管理一个动态分配的 MyString 对象QSharedPointer<MyString> sharedString1(new MyString("Hello, World!"));{// 创建另一个 QSharedPointer,它共享同一个 MyString 对象QSharedPointer<MyString> sharedString2 = sharedString1;// 打印字符串内容std::cout << *sharedString2->getData() << std::endl;// 在这个作用域结束时,sharedString2 会被销毁,但它不会删除 MyString 对象,// 因为还有 sharedString1 在共享它。}// 打印字符串内容(再次证明对象仍然存在)std::cout << *sharedString1->getData() << std::endl;// 当 sharedString1 被销毁时,它是最后一个共享 MyString 对象的 QSharedPointer,// 因此 MyString 对象会被删除,并且其析构函数会被调用。return 0;
}

QFile-创建、读取、写入和查询文件

在C++中,特别是当使用Qt框架时,QFile 类是一个用于文件操作的类。它提供了创建、读取、写入和查询文件的方法。当你看到这样的声明:

QFile *logFile;

这里,logFile 是一个指向 QFile 对象的指针。以下是对这个声明的详细讲解:

一、QFile 类

  • 功能QFile 类提供了对文件的读写访问。它继承自 QIODevice,因此具有所有基本的输入输出功能。
  • 创建文件:你可以使用 QFile 的构造函数来创建一个指向文件的指针,但此时文件并不会被立即打开。要打开文件,你需要调用 open() 方法。
  • 读写操作:一旦文件被打开,你可以使用 read()readLine()write() 等方法来读取和写入文件内容。
  • 错误处理QFile 提供了 error() 和 errorString() 方法来报告和处理文件操作中发生的错误。
  • 文件信息:你可以使用 size()exists()isReadable()isWritable() 等方法来查询文件的属性。

二、指针的使用

  • 动态分配:通常,你会使用 new 关键字来动态分配一个 QFile 对象,并将返回的指针赋值给 logFile

    logFile = new QFile("path/to/your/logfile.txt");
     

    这里,"path/to/your/logfile.txt" 是你想要操作的文件的路径。

  • 初始化:在声明 logFile 时,它并没有被初始化为指向任何有效的 QFile 对象。因此,在使用它之前,你需要确保它已经被正确地初始化和分配了内存。

  • 生命周期管理:由于 logFile 是一个指针,你需要负责它的生命周期管理。这包括在适当的时候删除它以避免内存泄漏:

    delete logFile;
    logFile = nullptr; // 可选,但推荐作为防御性编程措施
     

    然而,在Qt中,更常见的做法是使用智能指针(如 QScopedPointer 或 QSharedPointer)来自动管理内存。但请注意,QFile 通常不需要共享所有权,因此 QScopedPointer 可能是更合适的选择。然而,由于 QFile 的生命周期通常与它的使用场景紧密相关(例如,在打开和关闭文件期间),并且 QFile 对象通常不会很大,因此在实际应用中,直接使用裸指针并手动管理其生命周期也是常见的做法。

  • 使用RAII:在Qt中,更推荐的做法是使用RAII(Resource Acquisition Is Initialization)原则来管理资源。这意味着你应该在对象的构造函数中获取资源(如打开文件),并在析构函数中释放资源(如关闭文件)。这可以通过将 QFile 对象作为类的成员变量来实现,而不是使用指针。这样,当对象被销毁时,它的析构函数会自动被调用,从而释放资源。

三、示例代码

以下是一个使用 QFile 的简单示例,演示了如何打开文件、写入内容、关闭文件:

#include <QFile>
#include <QTextStream>
#include <QDebug>int main() {
QFile logFile("logfile.txt");
if (!logFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "Cannot open file for writing:" << logFile.errorString();
return -1;
}QTextStream out(&logFile);
out << "This is a log message.\n";logFile.close();
return 0;
}

 

在这个例子中,logFile 是一个 QFile 对象(而不是指针),它在作用域结束时会自动被销毁,从而关闭文件并释放相关资源。这是Qt中管理文件和其他资源的推荐方式之一。如果你确实需要使用指针(例如,因为你需要将 QFile 对象传递给多个函数或类,并且不想在每个地方都复制它),请确保你正确地管理了指针的生命周期。

QTextStream-基于文本的输入/输出功能

在Qt框架中,QTextStream 类是一个提供基于文本的输入/输出功能的类。它既可以用于读取数据(如从文件或字符串中),也可以用于写入数据(如到文件或字符串中)。当你看到这样的声明:

QTextStream *logStream;

 

这里,logStream 是一个指向 QTextStream 对象的指针。以下是对这个声明的详细讲解:

一、QTextStream 类

  • 功能QTextStream 类提供了基于文本的输入/输出操作。它支持多种编码格式,并可以自动处理平台相关的换行符。
  • 构造函数QTextStream 可以与多种类型的设备关联,包括 QFileQIODeviceQString 和 QByteArray。构造函数需要传入一个指向这些设备的指针。
  • 读写操作:一旦与设备关联,你可以使用 QTextStream 的 << 和 >> 运算符来写入和读取文本数据。
  • 格式化QTextStream 提供了多种格式化选项,如设置字段宽度、精度和对齐方式。
  • 编码:你可以指定 QTextStream 使用的编码格式,例如 UTF-8、Latin1 等。

二、指针的使用

  • 动态分配:通常,你会使用 new 关键字来动态分配一个 QTextStream 对象,并将返回的指针赋值给 logStream。但是,请注意,QTextStream 对象通常不需要动态分配,因为它们通常与特定的输入/输出设备相关联,并且这些设备的生命周期通常与 QTextStream 的使用场景紧密相关。

    QFile logFile("logfile.txt");
    if (logFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
    QTextStream logStream(&logFile); // 直接与 QFile 对象关联,无需动态分配
    logStream << "This is a log message.\n";
    logFile.close();
    }
  • QTextStream out(&logFile); 创建了一个 QTextStream 对象 out,并将其与已经打开的 QFile 对象 logFile 关联起来。
  • 通过 out 对象,你可以使用流操作符(如 <<)将文本数据写入到 logFile 指定的文件中。
  • 一旦 QTextStream 对象 out 与 QFile 对象 logFile 关联起来,你就可以使用 out 来输出文本了。
  • 例如,out << "This is a log message.\n"; 将字符串 "This is a log message.\n" 写入到文件中,并在末尾添加一个换行符。
  • 在这个例子中,logStream 是一个局部 QTextStream 对象,它直接与 logFile 对象关联。当 logFile 对象被销毁时(例如,当离开作用域时),它会自动关闭文件,并且与 logFile 关联的 QTextStream 对象也会自动失效。

  • 生命周期管理:如果你确实需要使用指针(例如,因为你需要将 QTextStream 对象传递给多个函数或类,并且不想在每个地方都复制它),请确保你正确地管理了指针的生命周期。但是,请注意,由于 QTextStream 通常与特定的输入/输出设备相关联,并且这些设备的生命周期通常是可以预测的,因此直接使用局部对象而不是指针通常是更好的选择。

  • 避免内存泄漏:如果你选择使用指针,并且动态分配了 QTextStream 对象,请确保在适当的时候删除它以避免内存泄漏。然而,由于 QTextStream 通常不需要动态分配,因此这种情况很少发生。

  • 使用智能指针:虽然 QTextStream 通常不需要动态分配,但如果你确实需要这样做,并且想要自动管理内存,你可以考虑使用 QScopedPointer(对于独占所有权的场景)或 QSharedPointer(对于共享所有权的场景)。但是,请注意,由于 QTextStream 的生命周期通常与它所关联的输入/输出设备的生命周期紧密相关,因此使用智能指针可能是不必要的,甚至可能导致不必要的复杂性。

三、推荐做法

在大多数情况下,建议直接使用局部 QTextStream 对象,并将它们与特定的输入/输出设备(如 QFileQString 等)直接关联。这样做可以简化代码,并减少内存管理的复杂性。如果你需要将 QTextStream 对象传递给多个函数或类,并且不想在每个地方都复制它,请考虑传递对输入/输出设备的引用或指针,并在需要的地方创建局部的 QTextStream 对象。

QMutex 

在Qt框架中,QMutex 是一个互斥锁(Mutex)类,它用于在多线程环境中保护共享数据或代码段,以防止同时访问导致的竞争条件(race conditions)或数据损坏。当你看到这样的声明:

QMutex logMutex;

 

这里,logMutex 是一个 QMutex 对象,它可以用作一个同步原语来确保只有一个线程可以访问特定的资源或代码段。以下是对这个声明的详细讲解:

一、QMutex 的作用

  • 互斥性QMutex 提供了互斥性,确保同一时间只有一个线程可以持有锁。
  • 保护共享资源:在多线程应用中,多个线程可能会尝试同时访问和修改共享资源(如全局变量、数据结构或文件)。QMutex 可以用来保护这些资源,防止数据竞争和不一致性。
  • 代码同步:除了保护数据外,QMutex 还可以用于同步代码的执行顺序,确保特定的操作按预期的顺序执行。

二、QMutex 的使用

  • 锁定和解锁:要使用 QMutex,你需要在访问共享资源之前调用 lock() 方法来获取锁。在访问完成后,你应该调用 unlock() 方法来释放锁。重要的是要确保在每条执行路径上都能释放锁,以避免死锁(deadlock)的发生。

    QMutex logMutex;// 在线程函数或某个方法中
    logMutex.lock();
    // 访问和修改共享资源
    // ...
    logMutex.unlock();
  • RAII 风格的锁管理:为了避免忘记解锁或由于异常导致的解锁失败,Qt 提供了 QMutexLocker 类。这是一个基于 RAII(Resource Acquisition Is Initialization)原则的锁管理器,它在构造时自动获取锁,并在析构时自动释放锁。

    QMutex logMutex;// 在线程函数或某个方法中
    {
    QMutexLocker locker(&logMutex);
    // 访问和修改共享资源
    // ...
    // 当 locker 对象离开作用域时,它会自动调用 unlock()
    }
  • 尝试锁定QMutex 还提供了 tryLock() 方法,它尝试获取锁但不阻塞。如果锁可用,tryLock() 将返回 true 并获取锁;如果锁不可用,它将立即返回 false 而不等待。

三、注意事项

  • 避免死锁:确保在每条执行路径上都能释放锁,特别是在使用异常处理时。
  • 性能考虑:频繁地锁定和解锁可能会影响性能,特别是在高并发环境中。因此,应该尽量减小锁的作用范围,并考虑使用其他同步机制(如读写锁、信号量)来优化性能。
  • 递归锁QMutex 默认不支持递归锁定(即同一个线程不能多次获取同一个锁)。如果需要递归锁定,请使用 QRecursiveMutex

四、应用场景

  • 日志记录:如变量名 logMutex 所暗示的,互斥锁常用于保护日志记录操作,确保多个线程不会同时写入日志文件,从而导致日志混乱。
  • 线程间通信:在多线程应用中,QMutex 可以与其他同步机制(如条件变量、信号槽)结合使用,以实现线程间的协调和通信。
  • 保护共享数据结构:当多个线程需要访问和修改同一个数据结构时(如链表、树、哈希表等),QMutex 可以用来确保数据的一致性和完整性。

 MQTT

在Qt框架中,QMqttClient 类是用于与MQTT协议服务器进行通信的一个客户端类。MQTT(Message Queuing Telemetry Transport)是一个轻量级的、基于发布/订阅模式的消息传输协议,广泛应用于物联网(IoT)场景中,以实现设备之间的可靠通信。当你看到这样的声明:

QMqttClient m_client;

这里,m_client 是一个 QMqttClient 对象,它表示一个MQTT客户端实例。以下是对这个声明的详细讲解:

一、QMqttClient 的作用

  • 连接服务器QMqttClient 允许你连接到MQTT协议的消息代理(broker)服务器。
  • 发布消息:一旦连接成功,你可以使用 QMqttClient 来发布(publish)消息到特定的主题(topic)。
  • 订阅主题:你还可以订阅(subscribe)一个或多个主题,以便接收这些主题上的消息。
  • 处理消息:当订阅的主题上有新消息发布时,QMqttClient 会通过信号和槽机制将消息传递给应用程序进行处理。

二、QMqttClient 的使用

  • 设置服务器地址和端口:在使用 QMqttClient 之前,你需要设置MQTT服务器的地址和端口。这通常通过调用 setHostname() 和 setPort() 方法来完成。

  • 设置客户端ID:每个MQTT客户端都需要一个唯一的客户端ID来标识自己。你可以通过调用 setClientId() 方法来设置它。

  • 建立连接:使用 connectToHost() 方法尝试连接到MQTT服务器。连接成功后,QMqttClient 会发出 connected 信号。

  • 发布消息:使用 publish() 方法发布消息到指定的主题。你可以指定消息的质量服务等级(QoS)和是否保留消息。

  • 订阅主题:使用 subscribe() 方法订阅一个或多个主题。当这些主题上有新消息时,QMqttClient 会发出 messageReceived() 信号。

  • 处理断开连接:如果连接断开,QMqttClient 会发出 disconnected 信号。你可以通过重新连接来处理这种情况。

三、信号和槽

QMqttClient 提供了多个信号来通知应用程序关于连接状态、消息接收等事件。你可以使用Qt的信号和槽机制来连接这些信号到你的槽函数中,以便处理这些事件。

四、注意事项

  • 线程安全QMqttClient 不是线程安全的。你应该确保在一个线程中创建和使用 QMqttClient 对象,并避免在多个线程之间共享它。
  • 错误处理:在处理MQTT连接和消息时,你应该添加适当的错误处理代码来处理可能的失败情况,如连接失败、发布消息失败等。
  • 资源释放:在不再需要 QMqttClient 对象时,你应该确保正确释放它所占用的资源。这通常意味着调用 disconnectFromHost() 方法来断开与MQTT服务器的连接,并删除 QMqttClient 对象。
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QMqttClient>
#include <QDebug>class MqttWidget : public QWidget {Q_OBJECTpublic:MqttWidget(QWidget *parent = nullptr) : QWidget(parent), mqttClient(new QMqttClient(this)) {QVBoxLayout *layout = new QVBoxLayout(this);connectButton = new QPushButton("Connect to MQTT", this);publishButton = new QPushButton("Publish Message", this);subscribeButton = new QPushButton("Subscribe to Topic", this);textEdit = new QTextEdit(this);textEdit->setReadOnly(true);layout->addWidget(connectButton);layout->addWidget(publishButton);layout->addWidget(subscribeButton);layout->addWidget(textEdit);// 设置MQTT服务器地址和端口mqttClient->setHostname("mqtt.example.com"); // 替换为你的MQTT服务器地址mqttClient->setPort(1883); // 替换为你的MQTT服务器端口// 设置客户端IDmqttClient->setClientId("myUniqueId"); // 替换为一个唯一的客户端ID// 连接信号和槽connect(mqttClient, &QMqttClient::connected, this, &MqttWidget::onConnected);connect(mqttClient, QOverload<QAbstractSocket::SocketError>::of(&QMqttClient::disconnected),this, &MqttWidget::onDisconnected);connect(mqttClient, &QMqttClient::messageReceived, this, &MqttWidget::onMessageReceived);connect(connectButton, &QPushButton::clicked, this, &MqttWidget::onConnectClicked);connect(publishButton, &QPushButton::clicked, this, &MqttWidget::onPublishClicked);connect(subscribeButton, &QPushButton::clicked, this, &MqttWidget::onSubscribeClicked);}private slots:void onConnectClicked() {mqttClient->connectToHost();}void onDisconnected(QAbstractSocket::SocketError error) {qDebug() << "Disconnected from MQTT server with error:" << error;textEdit->append("Disconnected from MQTT server.");}void onConnected() {qDebug() << "Connected to MQTT server.";textEdit->append("Connected to MQTT server.");}void onMessageReceived(const QByteArray &message, const QMqttTopicName &topic) {qDebug() << "Received message on topic:" << topic.name() << "Message:" << message;textEdit->append(QString("Received message on topic: %1\nMessage: %2").arg(topic.name()).arg(message));}void onPublishClicked() {// 这里应该添加发布消息的代码,例如:// QByteArray payload = "Hello MQTT";// mqttClient->publish("my/topic", payload, QMqttQualityOfService::AtMostOnce);// 但为了简化示例,这里暂时不发布消息。qDebug() << "Publish button clicked, but no message is published in this example.";}void onSubscribeClicked() {mqttClient->subscribe("my/topic");textEdit->append("Subscribed to topic 'my/topic'.");}private:QMqttClient *mqttClient;

先到这里吧,请多指教

相关文章:

QT学习笔记-QStringList,QTimer

QStringList-存储和管理一系列的字符串 在Qt框架中&#xff0c;QStringList 是一个模板类 QList<QString> 的特化&#xff0c;专门用于处理 QString 对象&#xff08;即Qt中的字符串&#xff09;的列表。当你看到这样的声明&#xff1a; QStringList m_rec_topicList; …...

如何使用brew安装phpredis扩展?

如何使用brew安装phpredis扩展&#xff1f; phpredis扩展是一个用于PHP语言的Redis客户端扩展&#xff0c;它提供了一组PHP函数&#xff0c;用于与Redis服务器进行交互。 1、cd到php某一版本的bin下 /usr/local/opt/php8.1/bin 2、下载 phpredis git clone https://githu…...

游戏引擎学习第25天

Git: https://gitee.com/mrxiao_com/2d_game 今天的计划 总结和复述&#xff1a; 这段时间的工作已经接近尾声&#xff0c;虽然每次编程的时间只有一个小时&#xff0c;但每一天的进展都带来不少收获。尽管看起来似乎花费了很多时间&#xff0c;实际上这些日积月累的时间并未…...

多线程运行时,JVM(Java虚拟机)的内存模型

在多线程运行时&#xff0c;JVM&#xff08;Java虚拟机&#xff09;的内存模型主要涉及以下几个方面&#xff1a; 1. 主内存和工作内存 JVM内存模型定义了主内存和工作内存的概念。主内存是所有线程共享的内存区域&#xff0c;而工作内存是每个线程私有的内存区域。线程对变量…...

kernel crash数据解析

crash数据解析 crash解析工具下载和编译方法如下&#xff1a; git clone https://github.com/crash-utility/crash.git cd crash; make targetARM64 crash工具解析ramdump文件&#xff1a; 1. 将dump 出来的ramdump 文件拷贝到 Linux 系统 2. 找到当前Linux 内核对应的vm…...

CLIP模型也能处理点云信息

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…...

利用若依代码生成器实现课程管理模块开发

目录 前言1. 环境准备1.1 数据库表设计与导入 2. 使用若依代码生成器生成模块代码2.1 导入数据库表2.2 配置生成规则2.2.1 基本信息配置2.2.2 字段信息配置2.2.3 生成信息配置 3. 下载与集成生成代码3.1 解压与集成3.2 启动项目并验证 4. 优化与扩展4.1 前端优化4.2 后端扩展 结…...

用Python做数据分析环境搭建及工具使用(Jupyter)

目录 一、Anaconda下载、安装 二、Jupyter 打开 三、Jupyter 常用快捷键 3.1 创建控制台 3.2 命令行模式下的快捷键 3.3 运行模式下快捷键 3.4 代码模式和笔记模式 3.5 编写Python代码 一、Anaconda下载、安装 【最新最全】Anaconda安装python环境_anaconda配置python…...

SpringBoot实战(三十二)集成 ofdrw,实现 PDF 和 OFD 的转换、SM2 签署OFD

目录 一、OFD 简介1.1 什么是 OFD&#xff1f;1.2 什么是 版式文档&#xff1f;1.3 为什么要用 OFD 而不是PDF&#xff1f; 二、ofdrw 简介2.1 定义2.2 Maven 依赖2.3 ofdrw 的 13 个模块 三、PDF/文本/图片 转 OFD&#xff08;ofdrw-conterver&#xff09;3.1 介绍&#xff1a…...

linux环境人大金仓数据库修改密码

1.进入人大金仓安装目录 cd /home/opt/Kingbase/ES/V9/Server/bin2.连接数据库 ./ksql -U system -d mydb -h 127.0.0.1 -p 54321-u 用户名 -d 数据库名 -h ip地址 -p 端口号 3.修改密码 ALTER USER system WITH PASSWORD 密码;...

使用ESP32通过Arduino IDE点亮1.8寸TFT显示屏

开发板选择 本次使用开发板模块丝印为ESP32-WROOM-32E 开发板库选择 Arduino IDE上型号选择为ESP32-WROOM-DA Module 显示屏选择 使用显示屏为8针SPI接口显示屏 驱动IC为ST7735S 使用库 使用三个Arduino平台库 分别是 Adafruit_GFXAdafruit_ST7735SPI 代码详解 首…...

Spring Cloud Alibaba(六)

目录&#xff1a; 分布式链路追踪-SkyWalking为什么需要链路追踪什么是SkyWalkingSkyWalking核心概念什么是探针Java AgentJava探针日志监控实现之环境搭建Java探针日志监控实现之探针实现编写探针类TestAgent搭建 ElasticsearchSkyWalking服务环境搭建搭建微服务微服务接入Sky…...

【包教包会】CocosCreator3.x——重写Sprite,圆角、3D翻转、纹理循环、可合批调色板、不影响子节点的位移旋转缩放透明度

一、效果演示 重写Sprite组件&#xff0c;做了以下优化&#xff1a; 1、新增自变换&#xff0c;在不影响子节点的前提下位移、旋转、缩放、改变透明度 新增可合批调色板&#xff0c;支持色相、明暗调节 新增圆角矩形、3D透视旋转、纹理循环 所有功能均支持合批、原生平台&…...

jupyter-lab 环境构建

我平时用来调试各种代码的。 创建环境&#xff0c;安装库 conda create --name jupyterlab python3.12 -y conda activate jupyterlab conda install -c conda-forge jupyterlab nodejs之前用的是3.10的&#xff0c;但是最近安装的时候&#xff0c;发现3.10的python里面的jup…...

【C++】LeetCode:LCR 026. 重排链表

题干 LCR 026. 重排链表 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln-1 → Ln 请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → … 不能只是单纯的改变节点内部的值&#xff0c;而是需要实…...

【Linux】vim编辑器

vim是什么&#xff1f; vim就是命令行模式下的文本编辑器&#xff0c;相当于windows中的记事本&#xff0c;可以用来进行文本编辑。 vim有三种运行模式&#xff0c;分别可以执行不同的操作&#xff1a; 普通模式&#xff08;Normal Mode&#xff09;&#xff1a;用于浏览和编辑…...

delphi 12 idhttpsever(S)+idhttp(C) 实现简单的JSON API服务

这篇博客展示了如何使用Delphi创建一个简单的HTTP服务器&#xff0c;并处理GET和POST请求。服务器监听6600端口&#xff0c;响应JSON格式的数据。客户端通过IdHttp组件进行GET和POST请求&#xff0c;获取并显示服务器响应的内容。 http服务器测试代码 procedure TForm1.FormSh…...

JVM 主副内存 详解

在 JVM (Java Virtual Machine) 中&#xff0c;内存的设计主要分为主内存和工作内存&#xff08;又称为线程内存&#xff09;。这种设计是基于 Java 内存模型&#xff08;Java Memory Model, JMM&#xff09; 的规定&#xff0c;它确保了多线程环境下数据的一致性和线程间的通信…...

sscanf与sprintf函数

本期介绍&#x1f356; 主要介绍&#xff1a;sscanf()、sprintf()这对输入/输出函数&#xff0c;并详细讲解了这两个函数的应用场景。 概述&#x1f356; 在C语言的输出和输入库中&#xff0c;有三对及其相似的库函数&#xff1a;printf()、scanf()、fprintf()、fscanf()、spri…...

【k8s】创建基于sa的token的kubeconfig

需求 创建一个基于sa的token的kubeconfig文件&#xff0c;并用这个文件来访问集群。 具体创建sa 和sa的token请参考文章: 【k8s】给ServiceAccount 创建关联的 Secrets-CSDN博客 创建sa apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata:namespace: jtkjdevnam…...

Gentoo Linux部署LNMP

一、安装nginx 1.gentoo-chxf ~ # emerge -av nginx 提示配置文件需更新 2.gentoo-chxf ~ # etc-update 3.gentoo-chxf ~ # emerge -av nginx 4.查看并启动nginx gentoo-chxf ~ # systemctl status nginx gentoo-chxf ~ # systemctl start nginx gentoo-chxf ~ # syst…...

2411C++,CXImage简单使用

介绍 CxImage是一个可非常简单快速的加载,保存,显示和转换图像的C类. 文件格式和链接的C库 Cximage对象基本上是加了一些成员变量来保存有用信息的一个位图: class CxImage{...protected:void* pDib; //包含标题,调色板,像素BITMAPINFOHEADER head; //标准头文件CXIMAGEINFO…...

什么是 Kubernetes(K8s)?

什么是 Kubernetes&#xff08;K8s&#xff09;&#xff1f; Kubernetes&#xff08;简称 K8s&#xff09; 是一个用来管理容器的开源工具&#xff0c;它可以自动化部署、扩展和管理容器化应用。简单来说&#xff0c;K8s 就是一个“容器管家”&#xff0c;负责确保你的应用程序…...

深入解析:TypeScript 与 Vue 的完美结合

文章目录 前言一、准备工作二、基本用法三、进阶主题结语 前言 Vue.js 是一款流行的渐进式 JavaScript 框架&#xff0c;它以易于学习和灵活的特性而闻名。TypeScript 则是 JavaScript 的一个超集&#xff0c;它引入了静态类型检查等高级功能&#xff0c;有助于构建更大型且复…...

机器学习周志华学习笔记-第13章<半监督学习>

机器学习周志华学习笔记-第13章&#xff1c;半监督学习&#xff1e; 卷王&#xff0c;请看目录 13半监督学习13.1 生成式方法13.2 半监督SVM13.3 基于分歧的方法13.4 半监督聚类 13半监督学习 前面我们一直围绕的都是监督学习与无监督学习&#xff0c;监督学习指的是训练样本包…...

软件工程——期末复习(1)

名词解释&#xff1a; 名词解释--人月 答案&#xff1a;人月是软件开发工作量的单位&#xff0c;1人月表示1个程序员1个月的工作时间所开发的代码量。 请解释软件缺陷、错误和失败&#xff0c;并简单举例说明。 答案&#xff1a;缺陷&#xff08;defect&#xff09;指系统代…...

【JavaEE初阶 — 网络编程】实现基于TCP协议的Echo服务

TCP流套接字编程 1. TCP &#xff06; UDP 的区别 TCP 的核心特点是面向字节流&#xff0c;读写数据的基本单位是字节 byte 2 API介绍 2.1 ServerSocket 定义 ServerSocket 是创建 TCP 服务端 Socket 的API。 构造方法 方法签名 方法说明 ServerS…...

vue结合canvas动态生成水印效果

在 Vue 项目中添加水印可以通过以下几种方式实现&#xff1a; 方法一&#xff1a;使用 CSS 直接通过 CSS 的 background 属性实现水印&#xff1a; 实现步骤 在需要添加水印的容器中设置背景。使用 rgba 设置透明度&#xff0c;并通过 background-repeat 和 background-size…...

Qt 5 中的 QTextStream 使用指南

文章目录 Qt 5 中的 QTextStream 使用指南介绍基本概念读取文件注意事项结论 Qt 5 中的 QTextStream 使用指南 介绍 QTextStream 是 Qt 框架中用于处理文本数据的类。它提供了方便的接口来读写文本文件或字符串&#xff0c;支持多种编码格式&#xff0c;并且可以与 QIODevice…...

中安证件OCR识别技术助力鸿蒙生态:智能化证件识别新体验

在数字化和智能化的浪潮中&#xff0c;伴随国产化战略的深入推进&#xff0c;国产操作系统和软件生态的建设逐渐走向成熟。鸿蒙操作系统&#xff08;HarmonyOS Next&#xff09;作为华为推出的重要操作系统&#xff0c;凭借其开放、灵活和高效的特点&#xff0c;正在加速在多个…...