Inheriting QSerialPort

Inheriting QSerialPort

本文关键字:QSerialPort Inheriting      更新时间:2023-10-16

也许是一个相当愚蠢和新手的问题,但我一直在努力保持我的QSerialPort serial;在我正在制作的整个应用程序中使用。(呃,这解释起来令人沮丧)

为了更清楚,我已经在我的MainWindow.cpp中建立了上述QSerialPort serial;,但是当我过渡到另一种具有不同类的形式(例如operations.cpp)时,我不确定如何保留和使用我的serial.*函数。我的主窗口.cpp表单只是一个连接设置表单,允许您选择要设置的端口、波特率、数据位、奇偶校验等,一旦我按下"打开连接"按钮,我就会隐藏表单(this->hide();)并出现操作.cpp表单。

有什么线索吗?

---

我曾尝试对类使用父子关系,但是,它只启动了一个新的QSerialPort serial;并且连接丢失了。

您应该分解出一个执行通信的单独QObject类,并将其他类连接到该类。

一个设计良好的系统永远不会拥有UI类并直接使用串行端口。例如,请参阅此答案,了解如何分离通信和UI。

让我们看看你可以对代码执行哪些转换。目前,您可能有类似于以下内容的内容:

// https://github.com/KubaO/stackoverflown/tree/master/questions/serial-owner-41715726
#include <QtWidgets>
#include <QtSerialPort>
class Operations1 : public QWidget {
    Q_OBJECT
    QVBoxLayout m_layout{this};
    QPushButton m_send{"Send"};
    QPointer<QSerialPort> m_serial;
public:
    Operations1() {
        m_layout.addWidget(&m_send);
        connect(&m_send, &QPushButton::clicked, this, &Operations1::sendRequest);
    }
    void sendRequest() {
        QByteArray request;
        QDataStream ds(&request, QIODevice::WriteOnly);
        ds << qint32(44);
        m_serial->write(request);
    }
    void setSerial(QSerialPort * port) {
        m_serial = port;
    }
};
class MainWindow1 : public QWidget {
    Q_OBJECT
    QVBoxLayout m_layout{this};
    QPushButton m_open{"Open"};
    QSerialPort m_serial;
    QScopedPointer<Operations1> m_operations;
    Operations1 * operations() {
        if (!m_operations)
            m_operations.reset(new Operations1);
        return m_operations.data();
    }
public:
    MainWindow1() {
        m_layout.addWidget(&m_open);
        connect(&m_open, &QPushButton::clicked, this, &MainWindow1::open);
    }
    void open() {
        m_serial.setBaudRate(38400);
        m_serial.setPortName("/dev/tty.usbserial-PX9A3C3B");
        if (!m_serial.open(QIODevice::ReadWrite))
            return;
        operations()->show();
        operations()->setSerial(&m_serial);
    }
};
int main1(int argc, char ** argv) {
    QApplication app{argc, argv};
    MainWindow1 ui;
    ui.show();
    return app.exec();
}

使用串行端口的功能分布在 UI 类中,将它们与端口紧密耦合。让我们通过分解端口操作来解决这个问题:

class Controller2 : public QObject {
    Q_OBJECT
    QSerialPort m_port;
public:
    Controller2(QObject * parent = nullptr) : QObject{parent} {
        connect(&m_port, &QIODevice::bytesWritten, this, [this]{
            if (m_port.bytesToWrite() == 0)
                emit allDataSent();
        });
    }
    Q_SLOT void open() {
        m_port.setBaudRate(38400);
        m_port.setPortName("/dev/tty.usbserial-PX9A3C3B");
        if (!m_port.open(QIODevice::ReadWrite))
            return;
        emit opened();
    }
    Q_SIGNAL void opened();
    Q_SLOT void sendRequest() {
        QByteArray request;
        QDataStream ds(&request, QIODevice::WriteOnly);
        ds << qint32(44);
        m_port.write(request);
    }
    Q_SIGNAL void allDataSent();
};
class Operations2 : public QWidget {
    Q_OBJECT
    QVBoxLayout m_layout{this};
    QPushButton m_send{"Send"};
    QPointer<Controller2> m_ctl;
public:
    Operations2(Controller2 * ctl, QWidget * parent = nullptr) :
        QWidget{parent},
        m_ctl{ctl}
    {
        m_layout.addWidget(&m_send);
        connect(&m_send, &QPushButton::clicked, m_ctl, &Controller2::sendRequest);
    }
};
class MainWindow2 : public QWidget {
    Q_OBJECT
    QVBoxLayout m_layout{this};
    QPushButton m_open{"Open"};
    QPointer<Controller2> m_ctl;
    QScopedPointer<Operations2> m_operations;
    Operations2 * operations() {
        if (!m_operations)
            m_operations.reset(new Operations2{m_ctl});
        return m_operations.data();
    }
public:
    MainWindow2(Controller2 * ctl, QWidget * parent = nullptr) :
        QWidget{parent},
        m_ctl{ctl}
    {
        m_layout.addWidget(&m_open);
        connect(&m_open, &QPushButton::clicked, m_ctl, &Controller2::open);
        connect(m_ctl, &Controller2::opened, this, [this]{
            operations()->show();
        });
    }
};
int main2(int argc, char ** argv) {
    QApplication app{argc, argv};
    Controller2 controller;
    MainWindow2 ui(&controller);
    ui.show();
    return app.exec();
}

最后,如果您厌倦了显式传递控制器,我们可以实现一种类似于 QCoreApplication::instance 的方法来访问唯一的控制器实例:

class Controller3 : public QObject {
    Q_OBJECT
    QSerialPort m_port;
    static Controller3 * instance(bool assign, Controller3 * newInstance = nullptr) {
        static Controller3 * instance;
        if (assign)
            instance = newInstance;
        return instance;
    }
public:
    Controller3(QObject * parent = nullptr) : QObject{parent} {
        connect(&m_port, &QIODevice::bytesWritten, this, [this]{
            if (m_port.bytesToWrite() == 0)
                emit allDataSent();
        });
        instance(true, this);
    }
    ~Controller3() {
        instance(true);
    }
    Q_SLOT void open() {
        m_port.setBaudRate(38400);
        m_port.setPortName("/dev/tty.usbserial-PX9A3C3B");
        if (!m_port.open(QIODevice::ReadWrite))
            return;
        emit opened();
    }
    Q_SIGNAL void opened();
    Q_SLOT void sendRequest() {
        QByteArray request;
        QDataStream ds(&request, QIODevice::WriteOnly);
        ds << qint32(44);
        m_port.write(request);
    }
    Q_SIGNAL void allDataSent();
    static Controller3 * instance() {
        return instance(false);
    }
};
class Operations3 : public QWidget {
    Q_OBJECT
    QVBoxLayout m_layout{this};
    QPushButton m_send{"Send"};
public:
    Operations3(QWidget * parent = nullptr) : QWidget{parent}
    {
        m_layout.addWidget(&m_send);
        connect(&m_send, &QPushButton::clicked, Controller3::instance(), &Controller3::sendRequest);
    }
};
class MainWindow3 : public QWidget {
    Q_OBJECT
    QVBoxLayout m_layout{this};
    QPushButton m_open{"Open"};
    QScopedPointer<Operations3> m_operations;
    Operations3 * operations() {
        if (!m_operations)
            m_operations.reset(new Operations3);
        return m_operations.data();
    }
public:
    MainWindow3(QWidget * parent = nullptr) : QWidget{parent}
    {
        m_layout.addWidget(&m_open);
        connect(&m_open, &QPushButton::clicked, Controller3::instance(), &Controller3::open);
        connect(Controller3::instance(), &Controller3::opened, this, [this]{
            operations()->show();
        });
    }
};
int main3(int argc, char ** argv) {
    QApplication app{argc, argv};
    Controller3 controller;
    MainWindow3 ui;
    ui.show();
    return app.exec();
}