【问题标题】:Python PyQt callback never runs - how to debug?Python PyQt 回调从不运行 - 如何调试?
【发布时间】:2016-01-09 23:25:39
【问题描述】:

我有一段使用 PyQt4 的相当复杂的代码,有时我的信号回调根本不会运行。

这似乎与我注册回调的地点/时间有关,即。 self.someobj.somesig.connect(self.callback).

我可以在调试器中看到回调已连接并且发出了信号。

代码太大,这里就不贴了,不过我尽量总结一下:

class RC(QtCore.QObject):
  render_ready = QtCore.pyqtSignal(object)
  def __init__(self, pc, ...):
    super(RC, self).__init__()
    self.pc = pc
    self.pc.rr.new_render.connect(self.insert)
  def check(self):
    ...
    if a: self.pc.replot_request.emit()
    else: self.pc.render_request.emit()
  def insert(self, r):
    ...
    if b: self.render_ready.emit(r)
    self.check()

class RR(QtCore.QObject):
  new_render = QtCore.pyqtSignal(object)
  def __init__(self, pc, app,...):
    super(RR, self).__init__()
    self.app = app
    self.pc = pc
  def run(self):
    self.pc.replot_request.connect(self.on_replot_request)
    self.pc.render_request.connect(self.render)
  ...
  def render(self, scale):
    ...
    r = R(i)
    r.moveToThread(QtGui.QApplication.instance().thread())
    r.new_render.emit(r)

class R(QtCore.QObject):
  def __init__(self, i):
    super(R, self).__init__()
    ...
  ...

class PC(QtCore.QObject):
  render_request = QtCore.pyqtSignal(int)
  replot_request = QtCore.pyqtSignal(object)
  def __init__(self, container, app):
    super(PC, self).__init__()
    ...
    self.rr = RR(self.app)
    self.rr_thread = QtCore.QThread()
    self.rr.moveToThread(self.rr_thread)
    self.connect(self.rr_thread, QtCore.SIGNAL("started()"), self.rr.run)
    self.c = RC(self)
    ...
    self.c.render_ready.connect(self.on_nr)
  def start(self):
    self.rr_thread.start()
  def on_nr(self, r):
    print "on_nr(...)"

class App(QtCore.QObject):
  ...
  def __init__(self):
    ..
    self.pc = PC(container, app)
    ...
    self.pc.start(self)  # Last thing in constructor

X = QtGui.QApplication(sys.argv)
a = App()
sys.exit(X.exec_())

我看到render_ready 连接到on_nr 并且render_ready 正在发出。但是on_nr 永远不会运行。信号序列很复杂,它跨越线程,但有问题的信号和回调在同一个线程中。此外,事件循环显然正在运行。我怎样才能开始深入挖掘?还是我犯了一些明显的错误?谢谢。

【问题讨论】:

  • 我认为您需要创建一个minimal reproducible example。现在你的代码有太多未知数(例如在RC类中你引用self.pc.r但我看不到任何地方的定义。在RR.render中你创建一个R的新实例并发出一个信号,但您在任何地方都没有R 的定义)
  • @three_pineapples 如果我可以创建一个MVCE,那将意味着我几乎可以自己解决问题。现在我对可能导致这种情况的原因一无所知,所以我真的不知道如何创建一个独立的问题。顺便说一句,R 只是QtCore.QObject 的一个简单子类。我现在正在更新示例。
  • 好吧,我还是不明白RR.render。你创建了一个R 的实例,将它移动到另一个线程(为什么?)并发出一个似乎没有连接到任何东西的信号。同时,在调用RC.insert 之前不会发出RC.render_ready,当发出PC.r.new_render 时会发生这种情况,但您的代码中似乎不存在该对象(PC.r)。所以我不确定你是否过于简化了你的代码,或者这是否是你问题的根本原因。我知道创建minimal reproducible example 意味着您可能会解决您的问题,但坦率地说,这就是重点。
  • 所以我对标题“如何调试?”中问题的回答是制作一个minimal reproducible example。你要么意识到你做了一些愚蠢的事情,要么设法重现问题,在这种情况下,这里的人将能够解释你发现的信号、插槽和线程的任何微妙之处。
  • @three_pineapples 我修复了代码。 PC.r 更改为 PC.rr。我能够解决这个问题,不幸的是它与 PyQt 和信号的使用无关。我尝试了一个 MVCE,但正如我所怀疑的那样,问题没有出现,因为我没有包括原因......我还没有查明它。请看下面我的回答。无论如何,谢谢。

标签: python events pyqt signals pyqt4


【解决方案1】:

不幸的是,正如 cmets 对问题的建议,这是一个愚蠢的错误。它与 PyQt 或信号的使用无关。我发布了问题所在以及我如何调试它,希望它仍然可以帮助某人。

问题出在哪里

我正在用一个新的对象覆盖发出信号的对象(尝试重置状态),因此它的信号不再连接到回调。

如何检测到

在调试器中,我注意到a.pp.rr 的地址在我将信号连接到它时有一个值,而当信号发出时,它的地址是不同的。两个不同的对象。

所以代码很干净,PyQt 信号的使用是正确的。也许吸取的教训是在替换实例时要小心。确保重新连接所有信号到/来自新实例,或者在对象中创建一个方法来重置它的状态(这就是我所做的)以避免破坏原始实例。

其他选项

关于如前所述创建Minimal, Complete, and Verifiable example,这可能是在本论坛中格式化问题的最合适方式,也是识别问题根源的好方法。通过巧妙地使用调试器,同样有效,也许更适合更晦涩和复杂的问题。如果您将 A 编码为连接到 B 并且 A 对 B 没有影响,那么 A 可能与“连接”时的“A”不同或 B 与“B”不同,或者连接在某个时候被删除。当您遗漏某些东西时,也许您想要更多地了解正在发生的事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 2012-06-18
    • 2018-02-26
    • 2013-11-08
    • 1970-01-01
    相关资源
    最近更新 更多