QSlider仍然卡住了仍然发出了sliderMoved

时间:2014-07-16 08:05:22

标签: pyqt

在我的基于PyQt4的程序中,QSliders(信号sliderMoved和sliderReleased连接到callables)有时"冻结",即当他们试图用鼠标拖动它们时它们不再移动,甚至虽然仍然发出了sliderMoved和sliderReleased。

这种行为似乎是随机发生的,有时是在运行程序数小时之后 - 使其或多或少无法重现和测试。

欢迎任何有助于解决此问题的帮助。

编辑:这是在Python 3.4和Windows 7上使用PyQt 4.10.4。

1 个答案:

答案 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