基于Qt QML和C++的MQTT测试客户端(CMakeLists实现)

发布于:2025-09-11 ⋅ 阅读:(20) ⋅ 点赞:(0)

1.项目图片

2.项目代码架构

3.源码 C++混合QML

经典的嵌入式C++混合QML学习很好的例子

MQTT C++文件

#ifndef MYMQTTCLIENT_H
#define MYMQTTCLIENT_H

#include <QObject>
#include <QString>
#include <QDateTime>
#include <QtMqtt/qmqttclient.h>
#include <QtMqtt/qmqttsubscription.h>
#include <QtMqtt/qmqttpublishproperties.h>

class mymqttclient : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString brokerUrl READ brokerUrl WRITE setBrokerUrl NOTIFY brokerUrlChanged)
    Q_PROPERTY(QString clientId READ clientId WRITE setClientId NOTIFY clientIdChanged)
    Q_PROPERTY(int mqttPort READ mqttPort WRITE setmqttPort NOTIFY mqttPortChanged)
    Q_PROPERTY(int keepAlive READ keepAlive WRITE setKeepAlive NOTIFY keepAliveChanged)
    Q_PROPERTY(bool cleanSession READ cleanSession WRITE setCleanSession NOTIFY cleanSessionChanged)
    Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged)
    Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
    Q_PROPERTY(QString connectionStatus READ connectionStatus NOTIFY connectionStatusChanged)
    Q_PROPERTY(QString subscribeTopic READ subscribeTopic WRITE setSubscribeTopic NOTIFY subscribeTopicChanged)
    Q_PROPERTY(int subscribeQos READ subscribeQos WRITE setSubscribeQos NOTIFY subscribeQosChanged)
    Q_PROPERTY(QString publishTopic READ publishTopic WRITE setPublishTopic NOTIFY publishTopicChanged)
    Q_PROPERTY(int publishQos READ publishQos WRITE setPublishQos NOTIFY publishQosChanged)
    Q_PROPERTY(bool retainMessage READ retainMessage WRITE setRetainMessage NOTIFY retainMessageChanged)
    Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged)
    Q_PROPERTY(QStringList subscribedTopics READ subscribedTopics NOTIFY subscribedTopicsChanged)
public:
    explicit mymqttclient(QObject *parent = nullptr);
    ~mymqttclient() override;

    // 连接相关属性
    QString brokerUrl() const;
    void setBrokerUrl(const QString &brokerUrl);

    QString clientId() const;
    void setClientId(const QString &clientId);

    int mqttPort() const;
    void setmqttPort(int mqttPort);

    int keepAlive() const;
    void setKeepAlive(int keepAlive);

    bool cleanSession() const;
    void setCleanSession(bool cleanSession);

    QString username() const;
    void setUsername(const QString &username);

    QString password() const;
    void setPassword(const QString &password);

    QString connectionStatus() const;

    // 订阅相关属性
    QString subscribeTopic() const;
    void setSubscribeTopic(const QString &subscribeTopic);

    int subscribeQos() const;
    void setSubscribeQos(int subscribeQos);

    // 发布相关属性
    QString publishTopic() const;
    void setPublishTopic(const QString &publishTopic);

    int publishQos() const;
    void setPublishQos(int publishQos);

    bool retainMessage() const;
    void setRetainMessage(bool retainMessage);

    QString message() const;
    void setMessage(const QString &message);

    QStringList subscribedTopics() const;

public slots:
    // 连接控制
       void connectToBroker();
       void disconnectFromBroker();

       // 订阅控制
       void subscribe();
       void unsubscribe(const QString &topic);

       // 发布消息
       void publishMessage();

       // 日志控制
       void clearLog();
signals:
       // 属性变化信号
      void brokerUrlChanged();
      void clientIdChanged();
      void mqttPortChanged();
      void keepAliveChanged();
      void cleanSessionChanged();
      void usernameChanged();
      void passwordChanged();
      void connectionStatusChanged();
      void subscribeTopicChanged();
      void subscribeQosChanged();
      void publishTopicChanged();
      void publishQosChanged();
      void retainMessageChanged();
      void messageChanged();
      void subscribedTopicsChanged();

      // 日志信号,用于通知QML添加日志条目
      void logAdded(const QString &timestamp, const QString &message, const QString &type);

public slots:
      void onConnected();
      void onDisconnected();
      void onErrorOccurred(QMqttClient::ClientError error);
      void onMessageReceived(const QByteArray &message, const QMqttTopicName &topic);
      void onSubscriptionStateChanged(QMqttSubscription::SubscriptionState state);
      void onPingResponse();
      void onStateChanged();

private:
      QMqttClient *m_client;
      QHash<QString, QMqttSubscription*> m_subscriptions;

      // 连接属性
      QString m_brokerUrl;
      QString m_clientId;
      int m_keepAlive;
      int m_mqttPort;
      bool m_cleanSession;
      QString m_username;
      QString m_password;
      QString m_connectionStatus;

      // 订阅属性
      QString m_subscribeTopic;
      int m_subscribeQos;

      // 发布属性
      QString m_publishTopic;
      int m_publishQos;
      bool m_retainMessage;
      QString m_message;

      // 已订阅主题列表
      QStringList m_subscribedTopics;

      // 添加日志
      void addLog(const QString &message, const QString &type);

};

#endif // MYMQTTCLIENT_H



CPP

#include "mymqttclient.h"
#include <QDebug>
#include <QUuid>

mymqttclient::mymqttclient(QObject *parent) : QObject(parent),
    m_keepAlive(60),
    m_cleanSession(true),
    m_connectionStatus("未连接"),
    m_subscribeQos(1),
    m_publishQos(1),
    m_retainMessage(false)
{
    // 初始化MQTT客户端
    m_client = new QMqttClient(this);

    // 生成随机客户端ID
    m_clientId = QString("mqtt-test-client-%1").arg(QUuid::createUuid().toString().left(8));

    // 设置默认主题
    m_subscribeTopic = "test/#";
    m_publishTopic = "test/message";
    m_message = "{\"hello\": \"world\"}";

    // 连接信号与槽
    // 连接核心信号槽(参考官方示例,补充 ping 响应)
    connect(m_client, &QMqttClient::connected, this, &mymqttclient::onConnected);
    connect(m_client, &QMqttClient::disconnected, this, &mymqttclient::onDisconnected);
    connect(m_client, &QMqttClient::errorChanged, this, &mymqttclient::onErrorOccurred);
    connect(m_client, &QMqttClient::messageReceived, this, &mymqttclient::onMessageReceived);
    connect(m_client, &QMqttClient::pingResponseReceived, this, &mymqttclient::onPingResponse);
    connect(m_client, &QMqttClient::stateChanged, this, &mymqttclient::onStateChanged);
    addLog("初始化完成,请连接到MQTT Broker", "info");
}

mymqttclient::~mymqttclient()
{
    disconnectFromBroker();
    delete m_client;
}

// 连接属性的getter和setter
QString mymqttclient::brokerUrl() const
{
    return m_brokerUrl;
}

void mymqttclient::setBrokerUrl(const QString &brokerUrl)
{
    if (m_brokerUrl != brokerUrl) {
        m_brokerUrl = brokerUrl;
        emit brokerUrlChanged();
    }
}

QString mymqttclient::clientId() const
{
    return m_clientId;
}

void mymqttclient::setClientId(const QString &clientId)
{
    if (m_clientId != clientId) {
        m_clientId = clientId;
        emit clientIdChanged();
    }
}

int mymqttclient::mqttPort() const
{
    return m_mqttPort;
}

void mymqttclient::setmqttPort(int mqttPort)
{
    if (m_mqttPort != mqttPort && mqttPort > 0) {
        m_mqttPort = mqttPort;
        emit mqttPortChanged();
    }
}


int mymqttclient::keepAlive() const
{
    return m_keepAlive;
}

void mymqttclient::setKeepAlive(int keepAlive)
{
    if (m_keepAlive != keepAlive && keepAlive > 0) {
        m_keepAlive = keepAlive;
        emit keepAliveChanged();
    }
}

bool mymqttclient::cleanSession() const
{
    return m_cleanSession;
}

void mymqttclient::setCleanSession(bool cleanSession)
{
    if (m_cleanSession != cleanSession) {
        m_cleanSession = cleanSession;
        emit cleanSessionChanged();
    }
}

QString mymqttclient::username() const
{
    return m_username;
}

void mymqttclient::setUsername(const QString &username)
{
    if (m_username != username) {
        m_username = username;
        emit usernameChanged();
    }
}

QString mymqttclient::password() const
{
    return m_password;
}

void mymqttclient::setPassword(const QString &password)
{
    if (m_password != password) {
        m_password = password;
        emit passwordChanged();
    }
}

QString mymqttclient::connectionStatus() const
{
    return m_connectionStatus;
}

// 订阅属性的getter和setter
QString mymqttclient::subscribeTopic() const
{
    return m_subscribeTopic;
}

void mymqttclient::setSubscribeTopic(const QString &subscribeTopic)
{
    if (m_subscribeTopic != subscribeTopic) {
        m_subscribeTopic = subscribeTopic;
        emit subscribeTopicChanged();
    }
}

int mymqttclient::subscribeQos() const
{
    return m_subscribeQos;
}

void mymqttclient::setSubscribeQos(int subscribeQos)
{
    if (m_subscribeQos != subscribeQos && subscribeQos >= 0 && subscribeQos <= 2) {
        m_subscribeQos = subscribeQos;
        emit subscribeQosChanged();
    }
}

// 发布属性的getter和setter
QString mymqttclient::publishTopic() const
{
    return m_publishTopic;
}

void mymqttclient::setPublishTopic(const QString &publishTopic)
{
    if (m_publishTopic != publishTopic) {
        m_publishTopic = publishTopic;
        emit publishTopicChanged();
    }
}

int mymqttclient::publishQos() const
{
    return m_publishQos;
}

void mymqttclient::setPublishQos(int publishQos)
{
    if (m_publishQos != publishQos && publishQos >= 0 && publishQos <= 2) {
        m_publishQos = publishQos;
        emit publishQosChanged();
    }
}

bool mymqttclient::retainMessage() const
{
    return m_retainMessage;
}

void mymqttclient::setRetainMessage(bool retainMessage)
{
    if (m_retainMessage != retainMessage) {
        m_retainMessage = retainMessage;
        emit retainMessageChanged();
    }
}

QString mymqttclient::message() const
{
    return m_message;
}

void mymqttclient::setMessage(const QString &message)
{
    if (m_message != message) {
        m_message = message;
        emit messageChanged();
    }
}

QStringList mymqttclient::subscribedTopics() const
{
    return m_subscribedTopics;
}

// 连接控制槽函数
void mymqttclient::connectToBroker()
{
    if (m_brokerUrl.isEmpty()) {
        addLog("Broker地址不能为空", "error");
        return;
    }

    if (m_client->state() == QMqttClient::Connected) {
        addLog("已经处于连接状态", "info");
        return;
    }

    // 设置MQTT客户端参数
    m_client->setHostname(m_brokerUrl);
    m_client->setPort(m_mqttPort); // 默认MQTT端口
    m_client->setClientId(m_clientId);
    m_client->setKeepAlive(m_keepAlive);
    m_client->setCleanSession(m_cleanSession);

    if (!m_username.isEmpty()) {
        m_client->setUsername(m_username);
    }

    if (!m_password.isEmpty()) {
        m_client->setPassword(m_password);
    }

    // 连接到Broker
    m_client->connectToHost();
    addLog(QString("正在连接到 %1...").arg(m_brokerUrl), "info");
    m_connectionStatus = "连接中";
    emit connectionStatusChanged();
}

void mymqttclient::disconnectFromBroker()
{
    if (m_client->state() == QMqttClient::Connected) {
        m_client->disconnectFromHost();
        addLog("正在断开连接...", "info");
    } else {
        addLog("未处于连接状态", "info");
    }
}

// 订阅控制槽函数
void mymqttclient::subscribe()
{
    if (m_client->state() != QMqttClient::Connected) {
        addLog("请先连接到Broker", "error");
        return;
    }

    if (m_subscribeTopic.isEmpty()) {
        addLog("订阅主题不能为空", "error");
        return;
    }

    // 检查是否已经订阅
    if (m_subscriptions.contains(m_subscribeTopic)) {
        addLog(QString("已经订阅过主题: %1").arg(m_subscribeTopic), "info");
        return;
    }

    // 订阅主题
    auto subscription = m_client->subscribe(m_subscribeTopic, m_subscribeQos);
    if (subscription) {
        m_subscriptions[m_subscribeTopic] = subscription;
        connect(subscription, &QMqttSubscription::stateChanged,
                this, &mymqttclient::onSubscriptionStateChanged);
        addLog(QString("正在订阅主题: %1 (QoS: %2)").arg(m_subscribeTopic).arg(m_subscribeQos), "info");
    } else {
        addLog(QString("订阅主题失败: %1").arg(m_subscribeTopic), "error");
    }
}

void mymqttclient::unsubscribe(const QString &topic)
{
    if (m_client->state() != QMqttClient::Connected) {
        addLog("请先连接到Broker", "error");
        return;
    }

    if (topic.isEmpty()) {
        addLog("主题不能为空", "error");
        return;
    }

    if (!m_subscriptions.contains(topic)) {
        addLog(QString("未订阅主题: %1").arg(topic), "info");
        return;
    }

    // 取消订阅
    m_client->unsubscribe(topic);
    auto subscription = m_subscriptions.take(topic);
    if (subscription) {
        subscription->deleteLater();
    }

    m_subscribedTopics.removeAll(topic);
    emit subscribedTopicsChanged();
    addLog(QString("已取消订阅主题: %1").arg(topic), "info");
}

// 发布消息槽函数
void mymqttclient::publishMessage()
{
    if (m_client->state() != QMqttClient::Connected) {
        addLog("请先连接到Broker", "error");
        return;
    }

    if (m_publishTopic.isEmpty()) {
        addLog("发布主题不能为空", "error");
        return;
    }

    if (m_message.isEmpty()) {
        addLog("消息内容不能为空", "error");
        return;
    }


    // 直接调用 publish 重载方法,无需手动创建 QMqttMessage
    qint64 msgId = m_client->publish(
        m_publishTopic,       // 主题(QString 类型)
        m_message.toUtf8(),   // 消息内容(QByteArray)
        m_publishQos,         // QoS 等级
        m_retainMessage       // 保留位
    );

    if (msgId != -1) {
        addLog(QString("已发布消息到主题 [%1] (QoS: %2, 保留: %3): %4")
               .arg(m_publishTopic)
               .arg(m_publishQos)
               .arg(m_retainMessage ? "是" : "否")
               .arg(m_message), "send");
    } else {
        addLog(QString("发布消息到主题 [%1] 失败").arg(m_publishTopic), "error");
    }
}

// 日志控制
void mymqttclient::clearLog()
{
    emit logAdded(QDateTime::currentDateTime().toString("HH:mm:ss"),
                 "日志已清空", "info");
}

// 内部槽函数
void mymqttclient::onConnected()
{
    m_connectionStatus = "已连接";
    emit connectionStatusChanged();
    addLog(QString("已成功连接到 %1").arg(m_brokerUrl), "success");
}

void mymqttclient::onDisconnected()
{
    m_connectionStatus = "未连接";
    emit connectionStatusChanged();

    // 清空订阅列表
    qDeleteAll(m_subscriptions.values());
    m_subscriptions.clear();
    m_subscribedTopics.clear();
    emit subscribedTopicsChanged();

    addLog("已与Broker断开连接", "info");
}

void mymqttclient::onErrorOccurred(QMqttClient::ClientError error)
{
    QString errorMsg;
    switch (error) {
    case QMqttClient::NoError:
        errorMsg = "正常通信";
        break;
    case QMqttClient::InvalidProtocolVersion:
        errorMsg = "协议版本不兼容";
        break;
    case QMqttClient::IdRejected:
        errorMsg = "客户端ID被拒绝";
        break;
    case QMqttClient::ServerUnavailable:
        errorMsg = "服务器不可用";
        break;
    case QMqttClient::BadUsernameOrPassword:
        errorMsg = "用户或密码错误";
        break;
    case QMqttClient::NotAuthorized:
        errorMsg = "权限不足";
        break;
    default:
        errorMsg = QString("发生错误 (代码: %1)").arg(error);
    }

    m_connectionStatus = "未连接";
    emit connectionStatusChanged();
    addLog(errorMsg, "error");
}

void mymqttclient::onPingResponse()
{
    const QString content = QDateTime::currentDateTime().toString()
                + QLatin1String(" PingResponse")
                + QLatin1Char('\n');
    addLog(content,"onPingResponse");
}

void mymqttclient::onStateChanged()
{
    const QString content = QDateTime::currentDateTime().toString()
                    + QLatin1String(": State Change")
                    + QString::number(m_client->state())
                    + QLatin1Char('\n');
    //ui->editLog->insertPlainText(content);
    addLog(content,"onStateChanged");
}

void mymqttclient::onMessageReceived(const QByteArray &message, const QMqttTopicName &topic)
{
    addLog(QString("收到主题 [%1] 的消息: %2").arg(topic.name()).arg(QString(message)), "receive");
}

void mymqttclient::onSubscriptionStateChanged(QMqttSubscription::SubscriptionState state)
{
    auto subscription = qobject_cast<QMqttSubscription*>(sender());
    QString topic = subscription->topic().filter();

    if (state == QMqttSubscription::Subscribed) {
        if (!m_subscribedTopics.contains(topic)) {
            m_subscribedTopics.append(topic);
            emit subscribedTopicsChanged();
        }
        addLog(QString("已成功订阅主题: %1 (QoS: %2)")
               .arg(topic)
               .arg(subscription->qos()), "success");
    } else if (state == QMqttSubscription::Unsubscribed) {
        m_subscribedTopics.removeAll(topic);
        m_subscriptions.remove(topic);
        emit subscribedTopicsChanged();
        addLog(QString("已取消订阅主题: %1").arg(topic), "info");
    } else if (state == QMqttSubscription::Error) {
//        QMqttSubscription::Error err = subscription->error();
//               addLog(QString("订阅主题 %1 失败:错误代码 %2")
//                      .arg(topic)
//                      .arg(static_cast<int>(err)),
//                      "error");
//               m_subscriptions.remove(topic);
        addLog(QString("订阅主题 %1 失败:订阅状态错误")
                      .arg(topic), "error");
               m_subscriptions.remove(topic);
    }
}

// 添加日志
void mymqttclient::addLog(const QString &message, const QString &type)
{
    QString timestamp = QDateTime::currentDateTime().toString("HH:mm:ss");
    emit logAdded(timestamp, message, type);
}



QML
 

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.3
//import "."

ApplicationWindow {
    id: mainWindow
    visible: true
    width: 1024
    height: 768
    title: qsTr("MQTT客户端测试工具")
    background: Rectangle{
        color: "#2c3e47"
    }

    // 主题颜色
    // 替换原有的颜色定义
    property color primaryColor: "#4361EE" // 更柔和的蓝色
    property color secondaryColor: "#3A86FF" // 明亮的蓝色
    property color successColor: "#4CC9F0" // 清新的蓝绿色
    property color warningColor: "#F8961E" // 温暖的橙色
    property color dangerColor: "#F94144" // 柔和的红色
    property color darkColor: "#2B2D42" // 深蓝灰
    property color lightColor: "#F8F9FA" // 更白的背景
    property color textPrimary: "#212529" // 主文本颜色
    property color textSecondary: "#495057" // 次文本颜色

    // 自动滚动日志
    property bool autoScroll: true

    // 连接状态样式
    property string statusStyle: {
        switch (myMqttClient.connectionStatus) {
            case "已连接": return "background-color: " + successColor + "; color: white";
            case "连接中": return "background-color: " + warningColor + "; color: white";
            default: return "background-color: #e0e0e0; color: #666666";
        }
    }

    // 网格布局主布局
    GridLayout {
        anchors.fill: parent
        columns: 3 //3列
        rowSpacing: 10
        columnSpacing: 10
        anchors.margins: 10
        // 连接配置面板
        GroupBox {
            id: connectionGroup
            title: qsTr("连接配置")
            label: GroupBoxTitleLabel {
                    text: connectionGroup.title
            }
            Layout.column: 0
            Layout.row: 0
            Layout.columnSpan:1
            Layout.rowSpan: 2
            Layout.fillHeight: true
            Layout.fillWidth: true
            Layout.maximumWidth: 300
            Layout.minimumWidth: parent.width/3
            background: Rectangle{
                color: "#fafafa"
                radius: 5
            }
            //滚动试图
            ScrollView {
                id: connScrollView //不加 id 时,parent 指向 ScrollView 内部的 viewport,而 viewport 宽度依赖内容,导致循环依赖
                anchors.fill: parent
                Column {//从上到下的垂直方向依次排列
                    anchors.margins: 10
                    spacing: 15
                    width: connScrollView.width - 20
                    // 连接状态
                    Row {
                        spacing: 10
                        width: parent.width
                        Label {
                            text: qsTr("连接状态:")
                            Layout.alignment: Qt.AlignVCenter
                        }
                        Label {
                            text: myMqttClient.connectionStatus
                            color: statusStyle.substring(statusStyle.indexOf("color:") + 6)   // 文字颜色

                            background: Rectangle {
                                radius: 4
                                implicitWidth: parent.implicitWidth + 10   // 等价于之前的 text.implicitWidth + 10
                                implicitHeight: 20
                                color: statusStyle.substring(
                                           statusStyle.indexOf("background-color:") + 19,
                                           statusStyle.indexOf(";")
                                       )
                            }

                            Layout.alignment: Qt.AlignVCenter
                        }

                    }

                    // Broker地址
                    Column {
                        spacing: 10
                        width: parent.width
                        Label {
                            text: qsTr("Broker地址")
                            font.bold: true
                            font.pointSize: 10
                        }
                        RoundedTextField  {
                            id: brokerUrlField
                            text: myMqttClient.brokerUrl
                            placeholderText: qsTr("mqtt://host:port")
                            onTextChanged: myMqttClient.brokerUrl = text
                            width: parent.width
                        }
                    }

                    // 端口
                    Column {
                        spacing: 10
                        width: parent.width

                        Label {
                            text: qsTr("端口")
                            font.bold: true
                            font.pointSize: 10
                            color: textPrimary
                        }

                        RoundedTextField {
                            id: portTextField
                            text: myMqttClient.mqttPort
                            inputMethodHints: Qt.ImhDigitsOnly
                            onTextChanged: myMqttClient.mqttPort = text ? parseInt(text) : 0
                            width: parent.width / 2
                        }

                    }

                    Column {
                        spacing: 5
                        width: parent.width
                        Label {
                            text: qsTr("客户端ID")
                            font.bold: true
                            font.pointSize: 10
                            color: textPrimary
                        }
                        RoundedTextField {
                            id: clientIdField
                            text: myMqttClient.clientId
                            onTextChanged: myMqttClient.clientId = text
                            width: parent.width
                        }
                    }
                    Column {
                        width: parent.width
                        spacing: 5
                        Label {
                            text: qsTr("心跳间隔(秒):")
                            font.bold: true
                            font.pointSize: 10
                            color: textPrimary
                        }
                        RoundedTextField {
                            id: keepAliveField
                            text: myMqttClient.keepAlive
                            inputMethodHints: Qt.ImhDigitsOnly
                            onTextChanged: myMqttClient.keepAlive = text ? parseInt(text) : 0
                            width: parent.width / 2
                        }

                    }

                    //清除会话
                    Row {
                        spacing: 5
                        width: parent.width

                        Label {
                            text: qsTr("清除会话")
                            font.bold: true
                            font.pointSize: 10
                            anchors.verticalCenter: parent.verticalCenter
                            color: textPrimary
                        }

                        CheckBox {
                            id: cleanSessionCheck
                            checked: myMqttClient.cleanSession
                            onCheckedChanged: myMqttClient.cleanSession = checked
                            anchors.verticalCenter: parent.verticalCenter
                        }
                    }


                    // 账号
                    Column {
                        spacing: 10
                        width: parent.width
                        Label {
                            text: qsTr("账号")
                            font.bold: true
                            font.pointSize: 10
                            color: textPrimary
                        }
                        RoundedTextField {
                            id: usernameField
                            placeholderText: qsTr("lock-mqtt")
                            text: myMqttClient.username
                            onTextChanged: myMqttClient.username = text
                            width: parent.width
                        }

                    }
                    //密码
                    Column {
                        spacing: 10
                        width: parent.width
                        Label {
                            text: qsTr("密码")
                            font.bold: true
                            font.pointSize: 10
                            color: textPrimary
                        }
                        RoundedTextField {
                            id: passwordField
                            placeholderText: qsTr("123456")
                            echoMode: TextField.Password
                            text: myMqttClient.password
                            onTextChanged: myMqttClient.password = text
                            width: parent.width
                        }
                    }
                    // 连接按钮
                    Row {
                        spacing: 10
                        width: parent.width
                        RoundedButton {
                            id: connectButton
                            text: qsTr("连接")
                            primaryColor: control.pressed ? "#36D08A" : "#cccccc"
                            enabled: myMqttClient.connectionStatus !== "已连接" && myMqttClient.connectionStatus !== "连接中"
                            width: parent.width / 2
                            onClicked: myMqttClient.connectToBroker()
                        }

                        RoundedButton {
                            id: disconnectButton
                            text: qsTr("断开")
                            enabled: myMqttClient.connectionStatus === "已连接"
                            onClicked: myMqttClient.disconnectFromBroker()
                            width: parent.width / 2
                            primaryColor: control.pressed ? "#36D08A" : "#cccccc"


                            contentItem: Text {//重写文字
                                text: control.text
                                color: "white"
                                horizontalAlignment: Text.AlignHCenter
                                verticalAlignment: Text.AlignVCenter
                                anchors.fill: parent
                            }
                        }
                    }
                }
            }
        }

         // 订阅面板
        GroupBox {
               id: subscribeGroup
               title: qsTr("订阅主题")
               label: GroupBoxTitleLabel {
                   text: subscribeGroup.title
               }
               Layout.column: 0
               Layout.row: 2
               Layout.columnSpan:1
               Layout.rowSpan: 1
               Layout.fillHeight: true
               Layout.fillWidth: true
               Layout.maximumWidth: 300
               Layout.minimumWidth: parent.width/3
               background: Rectangle {
                   color: "#fafafa"
                   radius: 5
               }

               Column {
                   anchors.fill: parent
                   anchors.margins: 10
                   spacing: 10

                   // 订阅主题输入
                   Column {
                       width: parent.width
                       spacing: 5

                       Label {
                           text: qsTr("订阅主题:")
                           font.bold: true
                           font.pointSize: 10
                       }

                       TextField {
                           id: subscribeTopicField
                           width: parent.width
                           text: myMqttClient.subscribeTopic
                           placeholderText: qsTr("例如: test/#")
                           onTextChanged: myMqttClient.subscribeTopic = text
                       }
                   }

                   // QoS级别选择
                   Column {
                       width: parent.width
                       spacing: 5

                       Label {
                           text: qsTr("QoS级别:")
                           font.bold: true
                           font.pointSize: 10
                       }

                       ComboBox {
                           id: subscribeQosCombo
                           width: parent.width
                           model: [0, 1, 2]
                           currentIndex: 1 // 默认QoS 1
                           onCurrentIndexChanged: myMqttClient.subscribeQos = currentIndex
                       }
                   }

                   // 订阅按钮
                   RoundedButton {
                       id: subscribeButton
                       text: qsTr("订阅")
                       enabled: myMqttClient.connectionStatus === "已连接" && subscribeTopicField.text !== ""
                       onClicked: myMqttClient.subscribe()
                   }

                   // 已订阅主题列表
                   Column {
                       width: parent.width
                       spacing: 5

                       Label {
                           text: qsTr("已订阅主题:")
                           font.bold: true
                           font.pointSize: 10
                       }

                       // 已订阅主题列表视图
                       ListView {
                           id: subscribedTopicsList
                           width: parent.width
                           height: 150
                           model: myMqttClient.subscribedTopics
                           clip: true

                           delegate: Item {
                               width: parent.width
                               height: 30

                               Row {
                                   spacing: 10
                                   width: parent.width

                                   Text {
                                       text: modelData
                                       width: parent.width - 40
                                       elide: Text.ElideRight
                                       verticalAlignment: Text.AlignVCenter
                                   }

                                   RoundedButton {
                                       text: "取消"
                                       onClicked: myMqttClient.unsubscribe(modelData)
                                   }
                               }
                           }

                           // 空列表提示
                           Label {
                               anchors.centerIn: parent
                               text: qsTr("未订阅任何主题")
                               visible: subscribedTopicsList.count === 0
                               color: "#999999"
                               font.italic: true
                           }
                       }
                   }
               }
           }

        // 发布消息面板
        GroupBox {
                id: publishGroup
                title: qsTr("发布消息")
                Layout.column: 1
                Layout.row: 2
                Layout.columnSpan: 2
                Layout.rowSpan: 1
                Layout.fillWidth: true
                Layout.fillHeight: true
               label: GroupBoxTitleLabel {
                       text: publishGroup.title
               }
               background: Rectangle{
                   color: "#fafafa"
                   radius: 5
               }
                Column {
                    anchors.margins: 10
                    spacing: 10
                    width: parent.width - 20

                    // 发布主题
                    TextField {
                        id: publishTopicField
                        text: myMqttClient.publishTopic
                        placeholderText: qsTr("例如: test/message")
                        onTextChanged: myMqttClient.publishTopic = text
                        width: parent.width
                    }

                    // QoS和保留消息设置
                    Row {
                        spacing: 20
                        width: parent.width
                        Column {
                            spacing: 5
                            Label {
                                text: qsTr("QoS级别:")
                                font.pointSize: 10
                            }
                            ComboBox {
                                id: publishQosCombo
                                model: [0, 1, 2]
                                currentIndex: 1 // 默认QoS 1
                                onCurrentIndexChanged: myMqttClient.publishQos = currentValue
                                width: 100
                            }
                        }
                        Column {
                            spacing: 5
                            Label {
                                text: qsTr("保留消息:")
                                font.pointSize: 10
                            }
                            ComboBox {
                                id: retainCombo
                                model: [qsTr("否"), qsTr("是")]
                                currentIndex: 0 // 默认不保留
                                onCurrentIndexChanged: myMqttClient.retainMessage = currentIndex === 1
                                width: 100
                            }
                        }
                    }

                    // 消息内容
                    TextArea {
                        id: messageArea
                        text: myMqttClient.message
                        placeholderText: qsTr('例如: {"temperature": 25.5, "humidity": 60}')
                        onTextChanged: myMqttClient.message = text
                        width: parent.width
                        height: 100
                    }

                    // 发布按钮
                    Row {
                        spacing: 10
                        width: parent.width
                        RoundedButton {
                            text: qsTr("清空")
                            onClicked: messageArea.text = ""
                            primaryColor: "#36D08A"
                        }

                        RoundedButton {
                            text: qsTr("发布")
                            enabled: myMqttClient.connectionStatus === "已连接" && myMqttClient.publishTopic && myMqttClient.message
                            onClicked: myMqttClient.publishMessage()
                            primaryColor: "#36D08A"
                        }
                    }
                }
           }

        GroupBox {
               id: logGroup
               title: qsTr("消息日志")
                label: GroupBoxTitleLabel {
                      text: logGroup.title
                }
               Layout.column: 1
               Layout.row: 0
               Layout.rowSpan: 2
               Layout.columnSpan: 2
               Layout.fillWidth: true
               Layout.fillHeight: true
               background: Rectangle{
                   color: "#fafafa"
                   radius: 5
               }
               ColumnLayout {
                   anchors.fill: parent
                   anchors.margins: 10
                   spacing: 10

                   Row{
                       spacing: 10
                       width: parent.width
                       // 清空日志按钮
                       RoundedButton {
                           text: qsTr("清空日志")
                           primaryColor: "#333333"
                       }

                       // 自动滚动按钮
                       RoundedButton {
                           primaryColor: mouseAreaAuto.pressed
                                  ? (autoScroll ? "#4CAF5080" : "#cccccc")
                                  : (autoScroll ? "#4CAF50" : "#e0e0e0")
                           text: autoScroll ? qsTr("自动滚动: 开启") : qsTr("自动滚动: 关闭")
                       }
                   }


                   // 日志内容
                   ScrollView {
                       id: logScrollView
                       Layout.fillWidth: true
                       Layout.fillHeight: true
                       clip: true

                       ListView {
                           id: logListView
                           anchors.fill: parent
                           model: ListModel { id: logModel }

                           delegate: Item {
                               width: parent.width
                               height: textItem.implicitHeight + 8

                               Column {
                                   anchors.fill: parent
                                   anchors.margins: 4
                                   spacing: 2

                                   Text {
                                       id: textItem
                                       text: "[" + timestamp + "] " + message
                                       font.family: "Courier New, monospace"
                                       font.pointSize: 10
                                       color: {
                                           switch (type) {
                                               case "success": return "green";
                                               case "error": return "red";
                                               case "receive": return "#7B68EE";
                                               case "send": return "#FF8C00";
                                               default: return "#333333";
                                           }
                                       }
                                       wrapMode: Text.WordWrap
                                   }

                                   Rectangle {
                                       width: parent.width
                                       height: 1
                                       color: "#f0f0f0"
                                   }
                               }
                           }
                       }
                   }
               }

               // 处理日志添加
               Connections {
                   target: myMqttClient
                   onLogAdded: {
                       logModel.append({
                           timestamp: timestamp,
                           message: message,
                           type: type
                       });

                       // 限制日志数量
                       if (logModel.count > 1000) {
                           logModel.remove(0, logModel.count - 1000);
                       }

                       // 自动滚动到底部
                       if (autoScroll) {
                           logListView.positionViewAtEnd();
                       }
                   }
               }
           }
        }
}

不太好贴出来,大家可以学习,要完整源码可到下面连接
https://download.csdn.net/download/weixin_57695658/91911445


网站公告

今日签到

点亮在社区的每一天
去签到