Qt 每秒更新一次值

Posted

技术标签:

【中文标题】Qt 每秒更新一次值【英文标题】:Qt update value every second 【发布时间】:2014-06-26 16:35:20 【问题描述】:

我想从命令中每隔一秒更新一次标签的值,所以一直在尝试通过 while 循环显示它...但是 UI 无法加载且无法工作...

任何建议/帮助将不胜感激...

下面是测试代码...

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QProcess>
#include <QString>
#include <QtCore/QTextStream>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QRegularExpressionValidator>

#include <iostream>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)

    ui->setupUi(this);
    txMessage();


MainWindow::~MainWindow()

    delete ui;


void MainWindow::txMessage()

    QString command = "bash -c \"netstat -i | grep ens33 | awk \'print $3\'\"";
    int temp = 0;
    droc = new QProcess;
    while (temp != 1)
    
        droc->start(command);
        droc->waitForFinished();
        QString value = droc->readAllStandardOutput();
        ui->label_3->setText(value);
    

【问题讨论】:

您的代码将永远停留在 MainWindow 构造函数中。您可以改用 QTimer。 【参考方案1】:
    您必须始终将控制权交还给事件循环。您的 while 循环将使您的应用程序无响应。 您正在泄漏流程实例。 至少您可以充分利用awknetstat -i | awk '/ens33/ print $3; exit 0 '。无论如何,您的命令字符串都是无效的,因为 \' 不是有效的 C/C++ 转义序列。您无需转义单引号。 您无缘无故地调用了三个额外的进程(bash、grep 和 awk)。 Qt 完全能够提取您想要的数据。 您在堆上分配东西也没有充分的理由。请注意下面的代码中没有任何显式的newdelete。至少,您应该使用QScopedPointerstd::unique_ptr(但从不 std::auto_ptr!)。

以下独立示例适用于 Qt 4 和 Qt 5。

#include <QLabel>
#include <QHBoxLayout>
#include <QBasicTimer>
#include <QProcess>
#include <QApplication>

class Widget : public QWidget 
    Q_OBJECT
    QHBoxLayout m_layout;
    QLabel m_label;
    QBasicTimer m_timer;
    QProcess m_process;
    void timerEvent(QTimerEvent * ev) 
        if (ev->timerId() == m_timer.timerId()) txMessage();
    
    void txMessage() 
        m_timer.stop();
        m_process.start("netstat", QStringList() << "-i", QProcess::ReadOnly);
    
    Q_SLOT void finished(int rc) 
        startTimer();
        if (rc != 0) 
            m_label.setText("Error");
         else 
            QString output = QString::fromLocal8Bit(m_process.readAll());
            QStringList lines = output.split('\n', QString::SkipEmptyParts);
            foreach (QString line, lines) 
                if (!line.contains("ens33")) continue;
                QStringList args = line.split(' ', QString::SkipEmptyParts);
                if (args.count() >= 3) 
                    m_label.setText(args.at(3));
                    return;
                
            
        
        m_label.setText("...");
    
    void startTimer() 
#if QT_VERSION>=QT_VERSION_CHECK(5,0,0)
        m_timer.start(1000, Qt::CoarseTimer, this);
#else
        m_timer.start(1000, this);
#endif
    
public:
    Widget(QWidget * parent = 0) : QWidget(parent), m_layout(this), m_label("...") 
        m_layout.addWidget(&m_label);
        startTimer();
        connect(&m_process, SIGNAL(finished(int)), SLOT(finished(int)));
    
;

int main(int argc, char ** argv)

    QApplication app(argc, argv);
    Widget w;
    w.show();
    return app.exec();


#include "main.moc"

【讨论】:

你是对的。我忘记了在 Qt 中,孩子们在销毁时会从他们的父母身上移除自己。 @IvanGrynko 这与 Qt 无关,它是 C++ 的工作原理。当您拥有class C : public D A a; B b; ; 时,以下析构函数按顺序运行:B::~B, A::~A, C::~C, D::~D。现在想象DQObject 我很震惊这个答案被否决了两次。它不仅清楚地解释了问题,而且提供了一个完整的工作示例。 @KubaOber,最让我沮丧的是,在不解释原因的情况下投反对票肯定会适得其反。我希望看到强行投票是合理的,但我想这永远不会发生。 @Merlin069 对其中一个反对票进行了解释。这是错误的,已被删除。由于我同时没有编辑问题,因此无法删除不赞成票(而且我不会仅仅处理反对票,目前我没有太多要添加的内容)。问题仍然是净 16 代表,所以谁在乎 :)【参考方案2】:

问题 1. 你的循环是无限的,因为 tmp 的值在循环内没有改变。

问题 2。您阻塞了 UI 线程。最简单的解决方案是添加

while( true ) 
    ...
    QCoreApplication::processEvents();
    if( droc->waitForFinished( 10 ) )
        break;

在你的循环中。但它不是“qt 风格”,可能会导致难以检测的错误。

最好的解决方案是connectQProcess::finished 向一个方法发送信号并在那里读取标准输出。

注意:异步编程的黄金法则——永远不要长时间阻塞主线程。

【讨论】:

这是个坏建议。 processEvents(和exec)递归到事件循环中并且是难以跟踪的错误的来源。不要使用它们。

以上是关于Qt 每秒更新一次值的主要内容,如果未能解决你的问题,请参考以下文章

使用 qt 中的信号/插槽更新 gui [关闭]

每秒更新一次通知中的 RemoteViews

UIButton 文本内容每秒更新一次

对数组中出现的值进行计数,返回一次值

SQL Server:每月循环一次值到整个月

生成器