使用PyQt在窗口小部件之间共享数据的最佳方法是什么?

时间:2017-05-29 07:48:15

标签: python qt numpy pyqt

目标

我正在使用Python与PyQt,Numpy和Matplotlib进行数据处理和可视化程序。数据从csv或二进制文件(使用np.genfromtxt和np.fromfile函数)导入为Numpy数组中主窗口的成员变量。我希望能够从父(或子父)窗口小部件访问此数据,该窗口小部件在Matplotlib画布中绘制曲线。

我的想法

  • 我考虑使用QApplication.topLevelWidgets(),但它返回一个包含4个小部件的列表:主窗口和3个意外的QMenu小部件。
  • 我知道我可以在Matplotlib画布上多次使用getParent(),但我正在寻找一个更强大的解决方案:我不希望它依赖于小部件层次结构。
  • 我想知道全局变量是否是一个明智的解决方案?我从未在Python中使用它们。

提前感谢您的任何建议。

1 个答案:

答案 0 :(得分:0)

似乎你需要一个集中的地方来存储你的数据,这些数据可以被任意数量的不同对象访问(Qt对象,numpy对象,它没有区别)。我的建议是Singleton模式。我将使用Alex Martelli Borg 实施一个小实验,但请查看this resource (Python 3 Patterns, Recipes and Idioms)以查看几个不同的示例。

我认为解释Singleton的最简单方法如下:当您多次实例化同一个对象时(例如QWidget),每个实例都会引用一个不同的对象。因此,如果您在一个实例中进行更改,则不会影响其他实例(一般而言)。 Singleton的工作方式不同。您创建的每个实例都指向同一个对象。请检查以下示例:

import numpy as np


class Singleton:
    """Alex Martelli implementation of Singleton (Borg)
    http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Singleton.html"""
    _shared_state = {}

    def __init__(self):
        self.__dict__ = self._shared_state


class Database(Singleton):
    def __init__(self):
        Singleton.__init__(self)

    def get(self):
        return self._data

    def change(self):
        # Just arbitrary experiment of changing the data
        self.load()

    def load(self):
        # For example from csv or binary files using
        # np.genfromtxt or np.fromfile
        self._data = np.random.randint(0, 10, (3, 3))

通过上面的代码,我刚刚创建了我的数据库"宾语。每次我调用这个数据库并询问它的数据时,它都会返回给我。请注意我如何将随机numpy数组作为数据。让我们说我创建了两个新对象:

class SomeObject:
    def __init__(self):
        self._something = None

    def doSomething(self):
        db = Database()
        print(db.get())


class OtherObject:
    def __init__(self):
        self._othersomething = None

    def doOtherSomething(self):
        db = Database()
        print(db.get())

两者都调用数据库的实例。但他们会引用相同的数据吗?让我们检查:

# Loading data into Singleton
db = Database()
db.load()

# Creating a couple of different objects
so = SomeObject()
oo = OtherObject()

# Making sure each object is calling the database
print("Original data in database:")
so.doSomething()
oo.doOtherSomething()

# Changing data in database
db.change()

# Checking the changes in both objects.
print("Changed data in database:")
so.doSomething()
oo.doOtherSomething()

结果如下:

Original data in database:
[[7 4 7]
 [3 4 1]
 [9 5 6]]
[[7 4 7]
 [3 4 1]
 [9 5 6]]
Changed data in database:
[[3 8 8]
 [7 2 8]
 [1 5 1]]
[[3 8 8]
 [7 2 8]
 [1 5 1]]

因此,创建自己的Database实例的两个对象都获得完全相同的数据(在调用load或change方法时随机化)。这可能是在不同对象之间共享数据的最平易近人(且可维护)的方式。

编辑:使数据库能够了解数据是否已加载。让我们通过添加" hasData"对我们的数据库类进行一些小修改。方法:

class Database(Singleton):
    def __init__(self):
        Singleton.__init__(self)

    def get(self):
        return self._data

    def change(self):
        # Just arbitrary experiment of changing the data
        self.load()

    def hasData(self):
        return hasattr(self, "_data")

    def load(self):
        # For example from csv or binary files using
        # np.genfromtxt or np.fromfile
        self._data = np.random.randint(0, 10, (3, 3))

此方法询问数据库是否已具有属性_data。我们来做一个实验:

db = Database()
print(db.hasData())
db.load()
print(db.hasData())

结果是:

False
True

其他变体可以使用第一个实例来加载数据。这在很大程度上取决于您的软件需求。