当我使用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
答案 0 :(得分:2)
推理原因:Qt主线程事件循环永远不会处理应用程序事件,因为它太忙于传递排队信号。信号排队,因为它们位于线程之间,因此在正确的线程中调用slot,与发送线程无关(在这种情况下,它们必须排队,因为slot操作GUI对象,这是只允许来自主线程)
有几种方法可以解决这个问题。我不太了解Ruby或它的Qt绑定,所以这只是一个粗略的大纲:
创建一个原子变量。要么使用一些Ruby类型,要么QAtomicInt
(我假设可以使用Ruby Qt绑定)。
在你的线程循环中,只需增加原子变量,而不是发出信号。
添加QTimer
以按期望的时间间隔更新@label.text
。如果用户应该能够读取该号码,我建议像500毫秒间隔。对于~60 fps的更新速率,最小敏感间隔大约为16 ms。
将计时器超时连接到on_test
并获取原子整数的值以更新文本。
这样,数值的更新与显示无关。
使用连接类型BlockingQueuedConnection(注意:不要与单线程一起使用)。将该连接类型添加到信号连接语句(但是您使用Ruby Qt执行此操作)。然后发射线程将阻塞,直到实际调用目标槽,因此信号将仅以它们可以处理的速率发射,不会更快。
答案 1 :(得分:0)
你的应用程序冻结导致你在无限循环中发出信号但不是发射的原因