qt - 在paint事件之外的setText不行吗?

时间:2015-12-28 00:13:21

标签: c++ qt

根据Qt 4.7.1,Qt Creator 2.1.0,OS X 10.6.8:

我在主窗口ui中有一个QLabel,它使用Courier New / 13,可以容纳四行文本。

我创建了四行文本,比水平标签短得多,一般格式:

“我的文字\ r \ n”

我在发送之前过滤了文本。 cstring中唯一的字符将是0x0D,0x0A,0x20(空格),从那里到小写z(0x7A'),当然还有终止零。没有其他控制字符 - 如果从源接收它们,我将它们替换为'*'

我通过setText()

将四行文本作为单个零终止的cstring发送到QLabel

我有时会以相当高的速度执行此操作,至少每秒几次 - 这是来自FM电台的RDBS数据,因此它会实时更改:

qDebug() << rbl;                    // data keeps coming to console
ui->fourLineLabel->setText(rbl);    // add this, display soon stops updating

这很有效。一阵子。然后显示停止更新。这是有争议的领域:

4-line QLabel http://fyngyrz.com/images/RDSarea.png

如果我将其他所有内容保留,但取出setText(),则问题不会发生。

我知道,对于某些事情,Qt希望在绘画活动中完成绘画。对于setText()

也是如此

阅读关于qt小部件的文档,它说小部件在他们自己的绘画事件中做自己的绘画......但这里的行为非常类似于当一个人真正试图在外面使用画家时发生的那种错误一个油漆事件。它肯定与setText()有关,所以......嘟。。

在我写这篇文章时,应用程序已经运行了几个小时而没有任何显示锁定,通过qDebug()将相同的文本输出到控制台。如果我取消注释setText(),则问题大约需要5分钟。它是100%可重复的。

我应该做些什么,我不做,画画或类似的?

感谢您的帮助。

2 个答案:

答案 0 :(得分:8)

一般情况下,你不应该从非UI线程更新Qt控件,只允许少量事情与非UI线程中的绘画有关 - http://doc.qt.io/qt-4.8/threads-modules.html

如果您需要从非UI线程更新UI - 请使用信号和插槽(QueuedConnectionBlockingQueuedConnection连接,但请确保不要使用BlockingQueuedConnection创建死锁。或者,如果您不想创建额外的信号和插槽以进行一些简单的更新 - 使用invokeMethod(它甚至可以返回值,如果您使用BlockingQueuedConnection连接类型,您的线程将等到UI已更新)。

一般建议 - 如果您有可能 - 请拨打一个电话,对UI进行大量更新,而不是进行少量小调用。

答案 1 :(得分:0)

始终建议GUI线程通过 signal-slot 机制与所有其他对象连接。实际上,不会直接调用主线程和主线程。以这种方式,GUI将响应,我们不会等待它回来。当然,民意调查解决方案并不理想,应该避免,因为他们最终无缘无故地使用杯子资源。

如果只使用QThread类型的线程,那么应该使用 signal-slot 机制来更新GUI。当需要使用Qt::QueuedConnection序列化所呈现的数据事件时就足够了。在你的情况下是真的。

如果不使用,则可能无法按照发出的顺序处理信号。仅当我们想要在接收器上的插槽完成之前限制呼叫者继续处理时,才应使用Qt::BlockingQueuedConnection。在GUI线程上进行处理的情况非常少见。

当我们想要从非qt线程连接时,必须特别小心,例如一个std线程,因为创建了对象,例如在本机线程中将不会在接收器端知道。

ui线程更新non-ui的一种方法是序列化和复制邮件。执行以下操作(甚至适用于非QThreads,例如boost::thread):

  • 设置单个QObject,为 force-emit 提供公共方法 包含您要发送的数据的信号,例如单身人士
  • 在仅接受
  • 参数的对象中设置插槽
  • 将信号连接到 ui-thread
  • 中对象的插槽
  • 连接必须为Qt::QueuedConnection

    class timer : public QObject
    { 
    Q_OBJECT
    //... write a singleton here
    
    std::mutex mut;
    
    public signals:
    signal_tic(QString const );
    
    public: 
    void force_emit_tic(QString const s )
    {
       std::lock_guard<std::mutex> l(mut);
       emit signal_tic(s);
    }
    
    timer & ref() 
    {
      static timer This;
      return This;
    }
    private:
    timer(){}
    };
    
    // in a main thread object setup this connection
    
    connect(&timer::ref(),SIGNAL(signal_tic(Qstring 
    const)),this,SLOT(slot_accept_tic(QString const ), Qt::QueuedConnection)
    
    // In any other thread
    timer::ref()::force_emit_tic( string_when_this_happened )
    

直接调用singleton force-emit 方法会产生所需的行为。 (当然对象必须是可以正常复制的才能工作)

按值发送的原因是,如果将const引用传递给临时驻留在另一个线程中,则不能保证其生命周期。此外,您需要在实际到达之前将消息序列化到 ui-thread ,否则您最终会收到一个不存在的数据或一个SIGSEGV。 Qt::QueuedConnection保证连接仅在QThreads已知的内存空间内序列化。