PySide Signal不能重载Python类

时间:2013-07-30 08:33:55

标签: python qt signals pyside slot

PySide声称Signals can be defined using the QtCore.Signal() class. Python types and C types can be passed as parameters to it. If you need to overload it just pass the types as tuples or lists。从PySide Doc Signals and Slots in PySide开始,他们展示了一种创建多个信号的方法。那条线是:

# create two new signals on the fly: one will handle
# int type, the other will handle strings
speak = QtCore.Signal((int,), (str,))

我走得有点远,创造了这样的东西(用于学习目的):

speak = QtCore.Signal((int,), (str,), (tuple,), (list,), (A,), (B,), (Exception,), (unicode,), (float,))

AB是我创建的两个不同的虚拟新样式类。然后我通过打印它们来调查实际创建的信号数量:

print someone.speak
print someone.speak[int]
print someone.speak[str]
print someone.speak[tuple]
print someone.speak[list]
print someone.speak[A]
print someone.speak[B]
print someone.speak[Exception]
print someone.speak[unicode]
print someone.speak[float]

我得到了这些:

<PySide.QtCore.SignalInstance object at 0x02179BA0>
<PySide.QtCore.SignalInstance object at 0x02179BA0>
<PySide.QtCore.SignalInstance object at 0x02179BB0>
<PySide.QtCore.SignalInstance object at 0x02179BC0>
<PySide.QtCore.SignalInstance object at 0x02179BC0>
<PySide.QtCore.SignalInstance object at 0x02179BC0>
<PySide.QtCore.SignalInstance object at 0x02179BC0>
<PySide.QtCore.SignalInstance object at 0x02179BC0>
<PySide.QtCore.SignalInstance object at 0x02179BB0>
<PySide.QtCore.SignalInstance object at 0x02179C00>

Obersevation:tuplelistException和我的自定义AB获得相同的信号。我知道元组和列表有点普遍,PySide使用它来重载内容。但为什么我的AB也会获得相同的信号?看起来只有像Python中的intfloatstr这样的原始类型才能获得新的信号。

有人可以解释这种奇怪的行为吗?

提前非常感谢!

[UPDATE]

当我在真正的PySide项目中遇到问题时,我做了上述探索。我将真实版本简化为:

#!/usr/bin/env python
import sys
from PySide import QtCore

class A(object):
    def __init__(self, msg):
        self.msg = msg

class B(object):
    def __init__(self, msg):
        self.msg = msg

@QtCore.Slot(A)
def sayA(a):
    print 'From sayA:', a.msg

@QtCore.Slot(B)
def sayB(b):
    print 'From sayB:', b.msg

class Communicate(QtCore.QObject):
    speak = QtCore.Signal((A,), (B,))

someone = Communicate()

someone.speak[A].connect(sayA)
someone.speak[B].connect(sayB)

someone.speak[A].emit(A('A is good'))
someone.speak[B].emit(B('B is bad'))

它会打印出来:

From sayA: A is good
From sayB: A is good
From sayA: B is bad
From sayB: B is bad

我预计只会从sayA打印A is good

2 个答案:

答案 0 :(得分:1)

请参阅this answer与您的问题相关的问题:

  

是可以用python对象定义信号,你可以使用:

     

signal_node_selected = QtCore.Signal(object)

我假设传递任何自定义Python类被视为传递object。没有办法让信号区分它们。

答案 1 :(得分:0)

感谢您的研究!我遇到了同样的问题,并通过链接信号和使用备用名来携带不同的数据来解决这个问题:

class King(QtGui.QWidget):
    summon = QtCore.Signal(str)
    summon_knights = QtCore.Signal(object)

    def __init__(self, parent=None):
        super(King, self).__init__(parent=parent)

        summon.connect(lambda x: self.summon_knights.emit(self.get_available_knights()))

    def get_available_knights(self):
        return ["Lancelot", "Galahad"]

lambda是为了处理或忽略召唤信号所携带的str。

这是我不那么优雅的划痕工作,向我自己证明它不像我想要的那样。由于异步信号/插槽行为导致它变得非常混乱(这对速度有利,但难以解释),因此睡眠会强制结果按时间顺序排列。

from PySide import QtCore
from PySide import QtGui
import sys
from collections import OrderedDict
from time import sleep

class Analyst(QtCore.QObject):

    finished = QtCore.Signal((object,), (list,))

    def __init__(self, parent=None):
        super(Analyst, self).__init__(parent=parent)

        self.number = 10000.0

    def analyze(self):
        print "Analyst working!"
        result = OrderedDict()
        result["a"] = self.number / 100.0
        result["b"] = self.number / 200.0

        sleep(1)

        report = ['Analysis Report',
                  ' a: {0}'.format(result["a"]),
                  ' b: {0}'.format(result["b"])
                  ]

        print "Analyst done!"

        self.finished[object].emit(result)
        sleep(1)
        self.finished[list].emit(report)

class Manager(QtCore.QObject):

    announceStartWork = QtCore.Signal()
    allDone = QtCore.Signal()

    def __init__(self, parent=None):
        super(Manager, self).__init__(parent=parent)

        self.analyst = Analyst(self)
        self.analyst.finished[object].connect(self.post_process)
        self.analyst.finished[list].connect(self.report_result)
        self.announceStartWork.connect(self.analyst.analyze)
        self.reportsDone = False
        self.resultsDone = False
        self.allDone.connect(self.exitWhenReady)

    def directAnalyst(self):
        print "Telling analyst to start"
        self.announceStartWork.emit()

    def post_process(self, results):

        print "Results type (expecting OrderedDict): {0}".format(type(results))

        if issubclass(type(results), dict):
            summation = 0
            for value in results.values():
                summation += value

            print "Sum of Results: {0}".format(summation)
            self.resultsDone = True
            self.allDone.emit()
        else:
            print "*** WRONG TYPE! DICT slot got the LIST!"


    def report_result(self, report):

        print "Report type (expecting list): {0}".format(type(report))

        if issubclass(type(report), list):
            report_str = '\n'.join(report)
            print "Report of original result: \n{0}".format(report_str)

            self.reportsDone = True
            self.allDone.emit()
        else:
            print "*** WRONG TYPE! LIST slot got the DICT!"


    def exitWhenReady(self):
        tasksCompleted = [self.reportsDone, self.resultsDone]
        if all(tasksCompleted):
            print "All tasks completed"
            app.exit()
        else:
            print "Not all tasks completed yet"


if __name__ == "__main__":

    app = QtCore.QCoreApplication([])
    manager = Manager()
    manager.directAnalyst()
    sys.exit(app.exec_())

这是输出:

Telling analyst to start
Analyst working!
Analyst done!
Results type (expecting OrderedDict): <class 'collections.OrderedDict'>
Sum of Results: 150.0
Not all tasks completed yet
Report type (expecting list): <class 'collections.OrderedDict'>
*** WRONG TYPE! LIST slot got the DICT!
Results type (expecting OrderedDict): <type 'list'>
*** WRONG TYPE! DICT slot got the LIST!
Report type (expecting list): <type 'list'>
Report of original result: 
Analysis Report
 a: 100.0
 b: 50.0
All tasks completed

好的,所以我在上面的管理器,分析师示例中实现了我自己的“修复”,并结束了这个:

from PySide import QtCore
from PySide import QtGui
import sys
from collections import OrderedDict
from time import sleep

class Analyst(QtCore.QObject):

    finished_result = QtCore.Signal(object)
    finished_report = QtCore.Signal(object)
    _finished = QtCore.Signal(object)

    def __init__(self, parent=None):
        super(Analyst, self).__init__(parent=parent)

        self.number = 10000.0
        self._finished.connect(self._make_signal)

    def analyze(self):
        print "Analyst working!"
        result = OrderedDict()
        result["a"] = self.number / 100.0
        result["b"] = self.number / 200.0

        sleep(1)

        report = ['Analysis Report',
                  ' a: {0}'.format(result["a"]),
                  ' b: {0}'.format(result["b"])
                  ]

        print "Analyst done!"

        self._finished.emit(("result", result))
        sleep(1)
        self._finished.emit(("report", report))

    def _make_signal(self, data):

        if data[0] == "result":
            self.finished_result.emit(data[1])
        elif data[0] == "report":
            self.finished_report.emit(data[1])


class Manager(QtCore.QObject):

    announceStartWork = QtCore.Signal()
    allDone = QtCore.Signal()

    def __init__(self, parent=None):
        super(Manager, self).__init__(parent=parent)

        self.analyst = Analyst(self)
        self.analyst.finished_result.connect(self.post_process)
        self.analyst.finished_report.connect(self.report_result)
        self.announceStartWork.connect(self.analyst.analyze)
        self.reportsDone = False
        self.resultsDone = False
        self.allDone.connect(self.exitWhenReady)

    def directAnalyst(self):
        print "Telling analyst to start"
        self.announceStartWork.emit()

    def post_process(self, results):

        print "Results type (expecting OrderedDict): {0}".format(type(results))

        if issubclass(type(results), dict):
            summation = 0
            for value in results.values():
                summation += value

            print "Sum of Results: {0}".format(summation)
            self.resultsDone = True
            self.allDone.emit()
        else:
            print "*** WRONG TYPE! DICT slot got the LIST!"

    def report_result(self, report):

        print "Report type (expecting list): {0}".format(type(report))

        if issubclass(type(report), list):
            report_str = '\n'.join(report)
            print "Report of original result: \n{0}".format(report_str)

            self.reportsDone = True
            self.allDone.emit()
        else:
            print "*** WRONG TYPE! LIST slot got the DICT!"


    def exitWhenReady(self):
        tasksCompleted = [self.reportsDone, self.resultsDone]
        if all(tasksCompleted):
            print "All tasks completed"
            app.exit()
        else:
            print "Not all tasks completed yet"


if __name__ == "__main__":

    app = QtCore.QCoreApplication([])
    manager = Manager()
    manager.directAnalyst()
    sys.exit(app.exec_())

具有以下输出:

Telling analyst to start
Analyst working!
Analyst done!
Results type (expecting OrderedDict): <class 'collections.OrderedDict'>
Sum of Results: 150.0
Not all tasks completed yet
Report type (expecting list): <type 'list'>
Report of original result: 
Analysis Report
 a: 100.0
 b: 50.0
All tasks completed