Qt-invokeMethod+QEvent实现同步访问QIODevice

1.子类封装

头文件

#include <QObject>
#include <QTcpSocket>
#include <QThread>

class Device01 : public QObject
{
    Q_OBJECT
public:
    explicit DeviceS01(QObject *parent = nullptr);


public slots:
    void connet(const QString& ip, int port);void setFreq(const QString& scpi);
    QString getTemp(int timeout);


private slots:
    void on_stateChanged(QTcpSocket::SocketState state);        //状态变更

signals:
    void sig_timeOutQuery();


private:
    std::atomic_bool            m_inited    = { false };
    std::shared_ptr<QTcpSocket> m_tcpSocket = nullptr;          //socket对象
};

注意:需要定义成槽函数

源文件

void Device01::connet(const QString &ip, int port)
{
    qDebug()<<"connet";
    do {
        if (m_inited)
        {
            break;
        }
        m_tcpSocket = std::make_shared<QTcpSocket>(this);  //socket初始化
        QObject::connect(m_tcpSocket.get(), &QTcpSocket::stateChanged, this, &Device01::on_stateChanged);//socket状态变更
        m_tcpSocket->connectToHost(ip, port);
    }while(0);
}



void Device01::setFreq(const QString &freq)
{
    if (!m_inited)
    {
        return;
    }

    QString scpi = "FREQ "+freq;
    m_tcpSocket->write(scpi.toLatin1());
}

QString Device01::getTemp(int timeout)
{
  qDebug() << "getTemp:" << QThread::currentThreadId();
  QString ret = "";
  //[1] 状态判断
  if (!m_inited) {
    return ret;
    }

    //[2] 写指令
    QString scpi = "TEMP?";
    m_tcpSocket->write(scpi.toLatin1());

    //[2] 查询结果
    QEventLoop loop; // 创建事件循环
    QObject::connect(this, &Device01::sig_timeOutQuery, &loop, &QEventLoop::quit);
    QTimer::singleShot(timeout, this, [&](){
        emit sig_timeOutQuery();
    });

    auto async = QObject::connect(m_tcpSocket.get(), &QTcpSocket::readyRead, this, [&](){
        auto rsp = m_tcpSocket->readAll();
        ret = rsp;
        emit sig_timeOutQuery();
    });

    loop.exec(); // 进入事件循环,等待服务器响应
    QObject::disconnect(async);
    return ret;
}

void Device01::on_stateChanged(QAbstractSocket::SocketState state)
{
    qDebug()<<"state"<<state;
    //[1] 正在连接状态
    if (QAbstractSocket::ConnectingState == state)
    {
        m_inited = false;
    }

    //[2] 连接成功状态
    else if (QAbstractSocket::ConnectedState == state)
    {
        m_inited = true;
    }

    //[3] 已断开状态
    else if (QAbstractSocket::UnconnectedState == state)
    {
        m_inited = false;
    }
}

 

 

2.初始化

m_deviceThread  = std::make_shared<QThread>();      //线程对象
m_device01     = std::make_shared<Device01>();    //01设备
m_device01->moveToThread(m_deviceThread.get());

m_deviceThread->start();

 

3.使用

QMetaObject::invokeMethod(m_device01.get(), "setFreq", Qt::QueuedConnection,
                              Q_ARG(QString, "100"));

QString temp;
QMetaObject::invokeMethod(m_device01.get(), "getTemp", Qt::BlockingQueuedConnection,
                              Q_RETURN_ARG(QString, temp),
                              Q_ARG(int, 3000));

注意没有返回值和引用参数的用QueuedConnection;

有返回值或者参数是引用用BlockingQueuedConnection,会保证invoke的地方会等槽函数执行完成再往下走;

两者调用的槽函数都在子线程中运行

 

posted @ 2025-04-08 17:58  朱小勇  阅读(46)  评论(0)    收藏  举报