【问题标题】:Qt - get data and forward them on serial connectionQt - 获取数据并通过串行连接转发它们
【发布时间】:2014-03-27 17:33:26
【问题描述】:

我正在尝试开发一个简单的 Qt 应用程序。 在我按下“开始”按钮后,应用程序应该不断地从设备中检索数据(使用第三方库)并尽快通过串行连接转发它们。

到目前为止,我使用的(丑陋的)软件是一个控制台应用程序,它以顺序方式运行,并在主机提供数据帧后立即获取数据帧,使用以下循环:

    while(1)
    {
          [...]
        while( MyClient.GetFrame().Result != Result::Success )
        {
            Sleep( 200 );
            std::cout << ".";
        }

          [... pack and send on serial]
    }

我想知道在 Qt 中实现这一点的哪种方式更方便,以保持 GUI 响应,同时也尽可能减少 getFrame 和串行写入函数之间的延迟。

我应该使用 定时器触发的 SLOT 吗? QtConcurrent 命名空间QRunnable? 这些方法各自的主要优点和缺点是什么?

谢谢 求您的帮助!

【问题讨论】:

    标签: c++ qt qtconcurrent


    【解决方案1】:

    由于现有库强制您轮询数据,因此唯一要做的就是在计时器上运行它。您可以选择执行此工作的对象是在主线程中运行,还是在工作线程中运行。无需使用 Qt Concurrent 或 QRunnable - 使用 QObject 让生活变得更简单,因为您可以轻松地向 GUI 提供反馈。

    例如,对客户的 API 做出一些假设:

    class Worker : public QObject {
      Client m_client;
      QSerialPort m_port;
      QBasicTimer m_timer;
    
      void processFrame() {
        if (m_client.GetFrame().Result != Result::Success) return;
        QByteArray frame = QByteArray::fromRawData(
          m_client.GetFrame().Data, m_client.GetFrame().Size);
        ... process the frame
        if (m_port.write(frame) != frame.size()) {
          ... process the error
        }
      }
      void timerEvent(QTimerEvent * ev) {
        if (ev->timerId() == m_timer.timerId()) processFrame();
      }
    public:
      Worker(QObject * parent = 0) : QObject(parent) {}
      Q_SLOT bool open(const QString & name) {
        m_port.close();
        m_port.setPortName(name);
        if (!m_port.open(name)) return false;
        if (!m_port.setBaudRate(9600)) return false;
        if (!m_port.setDataBits(QSerialPort::Data8)) return false;
        ... other settings go here
        return true;
      }
      Q_SLOT void start() { m_timer.start(200, this); }
      Q_SLOT void stop() { m_timer.stop(); }
      ...
    }
    
    /// A thread that's always safe to destruct
    class Thread : public QThread {
      using QThread::run; // lock the default implementation
    public:
      Thread(QObject * parent = 0) : QThread(parent) {}
      ~Thread() { quit(); wait(); }
    };
    
    int main(int argc, char ** argv) {
      QApplication app(argc, argv);
      Worker worker;
      Thread thread; // worker must be declared before thread!
      if (true) {
        // this code is optional, disabling it should not change things
        // too much unless the client implementation blocks too much
        thread.start();
        worker.moveToThread(&thread);
      }
    
      QPushButton button("Start");
      QObject::connect(&button, &QPushButton::clicked, [&worker]{
        // Those are cross-thread calls, they can't be done directly
        QMetaObject::invoke(&worker, "open", Q_ARG(QString, "COM1");
        QMetaObject::invoke(&worker, "start");
      });
      button.show();
    
      return app.exec(argc, argv);
    }
    

    【讨论】:

      猜你喜欢
      • 2016-07-19
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      • 1970-01-01
      • 2012-02-09
      • 2021-04-18
      • 2020-11-14
      • 1970-01-01
      相关资源
      最近更新 更多