‘PyQt5.QtCore.pyqtSignal’ object has no attribute ‘connect’

定义了一个QT线程类,采用信号槽来传递信息,刷新控件,参数func为循环执行的函数名,main为该函数所在的实体类,cla为信号的类型。

这里我希望能自定义信号类型,而以下代码有会报错标题的信息。

class MySerThread(QtCore.QThread):                     #信号槽定义
    # 定义信号,自定义参数为cla类型
    breakSignal = QtCore.pyqtSignal(str)
    def __init__(self,func:str, main, cla, parent=None):
        super().__init__(parent)
        # 下面的初始化方法都可以,有的python版本不支持
        #  super(Mythread, self).__init__()
        self.cla = cla
        self.ss = func
        self.main = main
    def set_class(self):
        self.breakSignal = QtCore.pyqtSignal(self.cla)
    def run(self):
        while True:
            self.ret = ''                                           #使用ret无效,必须加self
            exec("self.ret=self.main.{}()".format(self.ss))         #执行表达式 self.ret=self.main.read_thead()
            self.breakSignal.emit(self.ret)                         #信号槽传递
        self.quit()

原因分析:参考https://fishc.com.cn/thread-60309-1-1.html一个信号(特别是一个未绑定的信号)是类中的一个属性当信号作为属性被实例化后,PyQt5会自动绑定到实例信号并创建一个绑定的信号。这和Python自身创建绑定方法的功能类似。

根据文档,信号得是类的属性才可以。但放在__init__里并不是一个属性,是个啥,不知道,暂且叫他局部变量吧。

以下尝试均失败:

1、重新声明信号类型的

self.t1.breakSignal = QtCore.pyqtSignal(str)

2、利用 @property 装饰器将函数声明为属性的

     @property
     def breakSignal(self)
         return QtCore.pyqtSignal(int)

3、利用lambda 关键字

breakSignal = lambda a,b: QtCore.pyqtSignal(b)

4、property

    def breakSignal_(self):
        return QtCore.pyqtSignal(int)
breakSignal = property(breakSignal_)

曲线救国:

1、定义多个信号类型,使用if判断类型

breakSignal_int = QtCore.pyqtSignal(int)
    breakSignal_str = QtCore.pyqtSignal(str)
    def __init__(self,func:str, main, cla, parent=None):
        super().__init__(parent)
        # 下面的初始化方法都可以,有的python版本不支持
        #  super(Mythread, self).__init__()
        self.cla = cla
        self.ss = func
        self.main = main
    @property
    def my_code(self):
        if self.cla == int:
            return self.breakSignal_int
        elif self.cla == str:
            return self.breakSignal_str
    def my_emit(self, ret):
        if self.cla == int:
            self.breakSignal_int.emit(self.ret)
        elif self.cla == str:
            self.breakSignal_str.emit(self.ret)
    def run(self):
        while True:
            self.ret = ''                                           #使用ret无效,必须加self
            exec("self.ret=self.main.{}()".format(self.ss))         #执行表达式 self.ret=self.main.read_thead()
            self.my_emit(self.ret)                                  #信号槽传递
        self.quit()                                                 #线程退出

2、object支持任意类型

QtCore.pyqtSignal('PyQt_PyObject')

分析:

在qt线程实例化时已经完成信号的绑定,对应breakSignal 的地址,当重新赋值时self.breakSignal = QtCore.pyqtSignal(self.cla) 重新赋python将创建一个新的内存地址并赋值,这将导致信号未绑定,找不到connect。

验证:在init中加入:

        print(self.breakSignal_str)
        self.breakSignal_str = QtCore.pyqtSignal(str)
        print(self.breakSignal_str)

输出结果:

<bound PYQT_SIGNAL breakSignal_str of MySerThread object at 0x000001B4043CA828>

<unbound PYQT_SIGNAL [str]>

未绑定,结果显而易见了

那么有没有办法手动绑定呢?

没办法!!

手册中:

信号(特别是未绑定的信号)是类属性。当信号被引用为该类实例的属性时,PyQt5会自动将该实例绑定到该信号,以创建绑定信号。这与Python本身用于从类函数创建绑定方法的机制相同。

一个绑定信号具有connect(),disconnect()和emit()实现相关联的功能的方法。

https://stackoverflow.com/questions/50294652/how-to-create-pyqtsignals-dynamically

此坑待填!!!!!!!!!

同时记录一下,pyqt中不能使用sleep等延时函数,会造成GUI卡主,切无法定位原因!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

如果必须sleep,建议使用线程加信号槽的形式。

moller_1
moller_1
文章: 16

留下评论

您的电子邮箱地址不会被公开。 必填项已用*标注