从 Singleton 接收 pyqtSignal

2022-01-12 00:00:00 python pyqt5 signals-slots

问题描述

python中有单例类:

There's singleton class in python:

from PyQt5.QtCore import QObject, pyqtSignal
import logging

class Singleton(QObject):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not isinstance(cls._instance, cls):
            cls._instance = QObject.__new__(cls, *args, **kwargs)
        return cls._instance


class DataStatus(Singleton, QObject):
    '''
    '''
    dataChanged = pyqtSignal(str)
    __val = 'init'

    def __init__(self):
        super().__init__()

    def setVal(self, val):
        self.dataChanged.emit('emit: ' + val)
        logging.debug('emit: ' + val)
        self.__val = val

    def getVal(self):
        return self.__val

我们的想法是让整个程序都可以访问一个单一的数据存储.每次调用 set Method 时,都应该发出一个信号,告诉所有实例数据从某个地方发生了更改,应该重新读取.

The idea is to have one single data store accessible from allover the program. Every time a set Method is called, a signal should be emitted telling all instances that from somewhere the data was changed and should be re-read.

很酷的计划,但是如果你看一下测试代码

Cool plan, but if you look at the test code

def test(self):     
    self.ds1 = DataStatus()
    self.ds1.dataChanged.connect(self.windowaction)
    print(self.ds1)
    print(self.ds1.getVal())

    self.ds1.setVal('ds1.first')

    self.ds2 = DataStatus()
    #self.ds2.dataChanged.connect(self.windowaction)
    print(self.ds2)
    print(self.ds2.getVal())

    self.ds2.setVal('ds2.second')

    print(self.ds1.getVal())

def windowaction(self, q):
    print(q)

而且控制台输出很奇怪(至少对我来说):

And the console output it get's strange (at least for me):

<DataStatus.DataStatus.DataStatus object at 0x03207580>
init
emit: ds1.first
<DataStatus.DataStatus.DataStatus object at 0x03207580>
ds1.first
ds2.second

两个实例确实有相同的地址,很酷的单身人士可以完成它的工作.到 ds1 如果已连接dataChange"信号,如果从 ds1 更新数据,该信号将正常工作.但是如果我用 ds2.set 更改数据,ds1 没有收到信号......

Both instances do have the same address, cool the singleton does it's job. To ds1 if've connected the "dataChange" signal which works properly if from ds1 data is updated. BUT no signal is received by ds1 if I change the data with ds2.set......

有人对这里发生的事情有解释吗?数据在实例之间正确共享,但不是信号:-/

Does anybody have an explanation about what happens here. Data is shared properly across the instances, but not the signals:-/


解决方案

虽然您的 Singleton 类遵守始终返回相同的对象,但这并不意味着它已正确实现,在您的情况下,在 new 中创建了新对象但是您返回创建的第一个对象(满足您显然想要的)但信号dataChanged"属于新对象而不是导致问题的第一个对象.这种情况下的解决方案是使用元类,因为这个库指出:

Although your Singleton class complies that the same object is always returned but that does not imply that it is correctly implemented, in your case in new the new object is created but you return the first object created (fulfilling what you apparently want) but the signal "dataChanged "belongs to the new object and not to the first object causing the problem. The solution in this case is to use metaclasses as this library points out:

class Singleton(type(QObject), type):
    def __init__(cls, name, bases, dict):
        super().__init__(name, bases, dict)
        cls._instance = None

    def __call__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__call__(*args, **kwargs)
        return cls._instance


class DataStatus(QObject, metaclass=Singleton):
    dataChanged = pyqtSignal(str)
    __val = "init"

    def __init__(self):
        super().__init__()

    def setVal(self, val):
        self.dataChanged.emit("emit: " + val)
        logging.debug("emit: " + val)
        self.__val = val

    def getVal(self):
        return self.__val

相关文章