ruby gem qtbindings'发射使应用冻结

时间:2014-07-15 14:55:01

标签: ruby qt signals freeze emit

当我使用emit来更新GUI上的状态时,我的应用程序会冻结。

我想知道原因或如何避免这种冻结。感谢您的评论。

我的测试环境

演示应用程序位于下方。

#!/usr/bin/env ruby
# encoding: UTF-8
#

require 'Qt'

class App < Qt::MainWindow
    signals 'test()'
    slots   'on_test()'

    def initialize
        super

        @label = Qt::Label.new
        self.centralWidget = @label

        self.show

        connect self, SIGNAL('test()'), SLOT('on_test()')
        start_count
    end

    def start_count
        Thread.new do
            loop {
                emit test()
            }
        end
    end

    def on_test()
        @label.text = @label.text.to_i + 1
    end
end

app = Qt::Application.new(ARGV)
App.new
app.exec

@hyde 谢谢你的回答。

qtbindings的解决方案2似乎没有帮助。

connect self, SIGNAL('test()'), SLOT('on_test()')
=> 
connect self, SIGNAL('test()'), SLOT('on_test()'), Qt::BlockingQueuedConnection

解决方案1已经过测试,应用程序运行流畅。

解决方案1的代码:

#!/usr/bin/env ruby
# encoding: UTF-8
#

require 'Qt'

class App < Qt::MainWindow
    slots   'on_test()'

    def initialize
        super

        @label = Qt::Label.new
        self.centralWidget = @label

        self.show

        @c = Qt::AtomicInt.new

        start_count
        start_timer
    end

    def start_count
        Thread.new do
            loop {
                @c.fetchAndAddRelaxed(1)
            }
        end
    end

    def start_timer
        t = Qt::Timer.new(self)
        t.start(16)
        connect t, SIGNAL('timeout()'), SLOT('on_test()')
    end

    def on_test()
        @label.text = @c.fetchAndAddRelaxed(0) + 1
    end
end

app = Qt::Application.new(ARGV)
App.new
app.exec

2 个答案:

答案 0 :(得分:2)

推理原因:Qt主线程事件循环永远不会处理应用程序事件,因为它太忙于传递排队信号。信号排队,因为它们位于线程之间,因此在正确的线程中调用slot,与发送线程无关(在这种情况下,它们必须排队,因为slot操作GUI对象,这是只允许来自主线程)


有几种方法可以解决这个问题。我不太了解Ruby或它的Qt绑定,所以这只是一个粗略的大纲:

解决方案1:让线程循环尽可能快地遍历:

  1. 创建一个原子变量。要么使用一些Ruby类型,要么QAtomicInt(我假设可以使用Ruby Qt绑定)。

  2. 在你的线程循环中,只需增加原子变量,而不是发出信号。

  3. 添加QTimer以按期望的时间间隔更新@label.text。如果用户应该能够读取该号码,我建议像500毫秒间隔。对于~60 fps的更新速率,最小敏感间隔大约为16 ms。

  4. 将计时器超时连接到on_test并获取原子整数的值以更新文本。

  5. 这样,数值的更新与显示无关。

    解决方案2:使线程阻塞,直到实际发出发出的信号:

    使用连接类型BlockingQueuedConnection(注意:不要与单线程一起使用)。将该连接类型添加到信号连接语句(但是您使用Ruby Qt执行此操作)。然后发射线程将阻塞,直到实际调用目标槽,因此信号将仅以它们可以处理的速率发射,不会更快。

答案 1 :(得分:0)

你的应用程序冻结导致你在无限循环中发出信号但不是发射的原因