我设计了一个非常简单的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()
从可执行文件的控制台输出中读取数据
有没有简单的想法让我这样做。提前致谢
答案 0 :(得分:1)
Qt使用MVC方法构建GUI。 信号/插槽触发视图的更新,而模型(您的textEdit)由控制器(您的类,另一个组件)更新。 您应该始终使用信号/插槽来获得响应式GUI并更好地处理应用程序
答案 1 :(得分:0)
作为一个新手,忘记任何名为waitFor...
的方法都会有所帮助。它们会阻塞,并且在gui应用程序中,这通常会使事情无效。您不需要这些方法,因此请不要使用它们。
当QProcess
提供新输入时,您需要做出反应。下面是Qt 5和C ++ 11的一个简单的独立示例。
如果使用任何命令行参数调用应用程序,它将充当生成器以模拟数据源进程。当不带参数调用时,它将以仿真模式启动,并显示实时反映传入数据的用户界面。
有几点值得一提:
QCoreApplication::applicationFilePath()
用于指代可执行文件。readLine
,就必须这样做。 QProcess
可以指示任何块中的数据 - 无法保证可以使用任意数量的行。发出readyRead
时,您可以看到任意数量的行,包括零!所有readyRead
意味着至少要读取一个字节的数据。就是这样。QObject
派生类来提供必要的插槽。
#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"