QT非交互式UI值更新

时间:2015-06-23 20:04:08

标签: qt valuechangelistener

我设计了一个非常简单的qt应用程序(UI小部件),它在文本框中显示3个浮点值。有一个主要功能(类似于QT初学者tutorial)执行所有处理,QMainWindow类有3个文本框,通过此QMainWindow中的setter方法设置;从主函数调用这些方法,我只需传递传感器读数。它应该做的就是在后台进程发生变化时不断更新UI上的值。 此后台进程是一个c ++项目可执行文件,它处理传感器硬件,并由QProcess对象调用;这个可执行文件在20赫兹左右不断地发出3个数字(这些是传感器读数并且它们保持波动)。我在QApplication的main函数中有所有逻辑正常工作,我可以qDebug()并看到正在输出正确的值。

我唯一的问题是更新UI小部件中显示的值。我昨天开始研究QT,所以我不熟悉它,我读到了插槽和信号,但我并不需要事件处理。我只需要textEdit值来更新。

实际值处理在传感器读取处理循环中完成;它是一个无限的while循环,它将保留可执行文件的喷出值,直到我逃避循环:

1)如果我在这个while循环中调用app.exec()(起初听起来真的很糟糕,因为我认为它会继续创建新的窗口),没有任何反应;用户界面会显示,这些值会在后台生成,但不会显示在用户界面中。

2)如果我在while循环之前调用app.exec(),这是正确的方法,UI中不会显示任何值,而是继续由可执行文件在后台生成(类似于(1))。这是我真正的问题;如何在调用app.exec()后刷新UI中的值?

3)如果我在此循环后调用app.exec(),它将只显示一组值,因为我已经转义了循环。

为此,我在google上阅读了有关使用广告位和信号进行事件处理的内容(大多数论坛都建议这样做)。虽然我没有真正拥有多个对象的复杂应用程序。 我也尝试过使用指针但在完成所有运行时异常后,值仍然没有得到更新。我无法在此处发布代码,因为代码位于嵌入式设备上,而且目前无法连接到互联网。

我使用process.start(programPath, arguments)启动进程,p.waitForReadyRead()p.readLine()从可执行文件的控制台输出中读取数据 有没有简单的想法让我这样做。提前致谢

2 个答案:

答案 0 :(得分:1)

Qt使用MVC方法构建GUI。 信号/插槽触发视图的更新,而模型(您的textEdit)由控制器(您的类,另一个组件)更新。 您应该始终使用信号/插槽来获得响应式GUI并更好地处理应用程序

答案 1 :(得分:0)

作为一个新手,忘记任何名为waitFor...的方法都会有所帮助。它们会阻塞,并且在gui应用程序中,这通常会使事情无效。您不需要这些方法,因此请不要使用它们。

QProcess提供新输入时,您需要做出反应。下面是Qt 5和C ++ 11的一个简单的独立示例。

如果使用任何命令行参数调用应用程序,它将充当生成器以模拟数据源进程。当不带参数调用时,它将以仿真模式启动,并显示实时反映传入数据的用户界面。

有几点值得一提:

  1. 这是一个单文件示例,它只调用一次:)
  2. 没有一个明确的内存分配。应避免手动内存管理。所有对象的正确生命周期由C ++ 11和Qt的语义处理。
  3. QCoreApplication::applicationFilePath()用于指代可执行文件。
  4. 当进程指示新数据可用时,只要可以读取整行,我们就会读取任何数据。只要您使用readLine就必须这样做。 QProcess可以指示任何块中的数据 - 无法保证可以使用任意数量的行。发出readyRead时,您可以看到任意数量的行,包括零!所有readyRead意味着至少要读取一个字节的数据。就是这样。
  5. Lambdas用于保持代码简洁。 Qt 4样式代码至少需要一个QObject派生类来提供必要的插槽。
  6. 要正确关闭进程,应用程序不会在最后一个窗口关闭时退出 - 默认情况下会这样做。当最后一个窗口关闭时,请求进程终止,当它完成时,应用程序退出。
  7. 同样,这是C ++ 11代码,它与Python或其他高级脚本语言一样简洁。这就是Qt带来的C ++ 11。它不应该像C一样读,它不应该:)
  8. screenshot of the example

    #include <QApplication>
    #include <QGridLayout>
    #include <QProcess>
    #include <QLabel>
    #include <QTimer>
    #include <QTextStream>
    #include <QRegExp>
    #include <cstdio>
    
    // QT 5, C++11
    int main(int argc, char *argv[])
    {
       if (argc > 1) {
          QCoreApplication app(argc, argv);
          // output 3 random values per line at ~20Hz
          QTextStream out(stdout);
          QTimer timer;
          timer.start(50);
          QObject::connect(&timer, &QTimer::timeout, [&out]{
             out << qrand() << " " << qrand() << " " << qrand() << endl;
          });
          return app.exec();
       }
       QApplication app(argc, argv);
       QWidget w;
       QGridLayout layout(&w);
       QLabel l1, l2, l3;
       layout.addWidget(&l1, 0, 0);
       layout.addWidget(&l2, 0, 1);
       layout.addWidget(&l3, 0, 2);
       QProcess process;
       process.start(QCoreApplication::applicationFilePath(), QStringList("foo"));
       QObject::connect(&process, &QProcess::readyRead, [&]{
          static QRegExp sep("\\W+");
          while (process.canReadLine()) {
             QStringList data = QString::fromLocal8Bit(process.readLine()).split(sep, QString::SkipEmptyParts);
             if (data.length() != 3) continue;
             l1.setText(data.at(0));
             l2.setText(data.at(1));
             l3.setText(data.at(2));
          }
       });
       app.setQuitOnLastWindowClosed(false);
       process.connect(&app, SIGNAL(lastWindowClosed()), SLOT(terminate()));
       app.connect(&process, SIGNAL(finished(int)), SLOT(quit()));
       w.show();
       return app.exec();
    }
    
    #include <QApplication>
    #include <QGridLayout>
    #include <QProcess>
    #include <QLabel>
    #include <QTimer>
    #include <QTextStream>
    #include <QRegExp>
    #include <QPointer>
    #include <cstdio>
    
    // QT 4, C++98
    class Emulator : public QObject {
       Q_OBJECT
       QTextStream m_out;
       QTimer m_timer;
       Q_SLOT void on_timeout() {
          m_out << qrand() << " " << qrand() << " " << qrand() << endl;
       }
    public:
       Emulator() : m_out(stdout) {
          m_timer.start(50);
          connect(&m_timer, SIGNAL(timeout()), SLOT(on_timeout()));
       }
    };
    
    class Widget : public QWidget {
       Q_OBJECT
       QGridLayout m_layout;
       QLabel m_l1, m_l2, m_l3;
       QPointer<QProcess> m_process;
       Q_SLOT void on_readyRead() {
          static QRegExp sep("\\W+");
          while (m_process->canReadLine()) {
             QStringList data = QString::fromLocal8Bit(m_process->readLine()).split(sep, QString::SkipEmptyParts);
             if (data.length() != 3) continue;
             m_l1.setText(data.at(0));
             m_l2.setText(data.at(1));
             m_l3.setText(data.at(2));
          }
       }
    public:
       Widget(QProcess * process) : m_layout(this), m_process(process) {
          m_layout.addWidget(&m_l1, 0, 0);
          m_layout.addWidget(&m_l2, 0, 1);
          m_layout.addWidget(&m_l3, 0, 2);
          connect(m_process, SIGNAL(readyRead()), SLOT(on_readyRead()));
       }
    };
    
    int main(int argc, char *argv[])
    {
       if (argc > 1) {
          // output 3 random values per line at ~20Hz
          QCoreApplication app(argc, argv);
          Emulator emulator;
          return app.exec();
       }
       QApplication app(argc, argv);
       QProcess process;
       Widget w(&process);
       process.start(QCoreApplication::applicationFilePath(), QStringList("foo"));
       app.setQuitOnLastWindowClosed(false);
       process.connect(&app, SIGNAL(lastWindowClosed()), SLOT(terminate()));
       app.connect(&process, SIGNAL(finished(int)), SLOT(quit()));
       w.show();
       return app.exec();
    }
    #include "main.moc"