在我的基于PyQt4的程序中,QSliders(信号sliderMoved和sliderReleased连接到callables)有时"冻结",即当他们试图用鼠标拖动它们时它们不再移动,甚至虽然仍然发出了sliderMoved和sliderReleased。
这种行为似乎是随机发生的,有时是在运行程序数小时之后 - 使其或多或少无法重现和测试。
欢迎任何有助于解决此问题的帮助。
编辑:这是在Python 3.4和Windows 7上使用PyQt 4.10.4。
答案 0 :(得分:0)
经过一些调试后,我很确定这是因为从一个单独的线程调用一个GUI插槽,我知道这是禁止的。修复此问题以使用正确的信号槽方法似乎解决了这个问题。
在调用下面定义的patch
函数后,所有槽调用都被一个包装器包装,该包装器检查它们是否仅从GUI线程调用 - 否则会打印一个警告。这就是我找到罪魁祸首的方法。
import functools
import sys
import threading
import traceback
from PyQt4.QtCore import QMetaMethod
from PyQt4.QtGui import QWidget
SLOT_CACHE = {}
def patch():
"""Check for calls to widget slots outside of the main thread.
"""
qwidget_getattribute = QWidget.__getattribute__
def getattribute(obj, name):
attr = qwidget_getattribute(obj, name)
if type(obj) not in SLOT_CACHE:
meta = qwidget_getattribute(obj, "metaObject")()
SLOT_CACHE[type(obj)] = [
method.signature().split("(", 1)[0]
for method in map(meta.method, range(meta.methodCount()))
if method.methodType() == QMetaMethod.Slot]
if (isinstance(attr, type(print)) and # Wrap builtin functions only.
attr.__name__ in SLOT_CACHE[type(obj)]):
@functools.wraps(
attr, assigned=functools.WRAPPER_ASSIGNMENTS + ("__self__",))
def wrapper(*args, **kwargs):
if threading.current_thread() is not threading.main_thread():
print("{}.{} was called out of main thread:".format(
type(obj), name), file=sys.stderr)
traceback.print_stack()
return attr(*args, **kwargs)
return wrapper
else:
return attr
QWidget.__getattribute__ = getattribute