【发布时间】:2017-06-14 10:01:21
【问题描述】:
假设我有一个要在 Qt Designer 中使用的自定义 PyQt 小部件,例如用于 matplotlib 画布:
plot_widget.py:
from PyQt5 import QtWidgets
import matplotlib
matplotlib.use('Qt5Agg')
from matplotlib.backends.backend_qt5agg import (
FigureCanvasQTAgg, NavigationToolbar2QT
)
class PlotWidget(QtWidgets.QWidget):
def __init__(self, parent=None, toolbar=True, figsize=None, dpi=100):
super(PlotWidget, self).__init__(parent)
self.setupUi(toolbar, figsize, dpi)
def setupUi(self, toolbar=True, figsize=None, dpi=100):
layout = QtWidgets.QVBoxLayout(self)
self.figure = Figure(figsize=figsize, dpi=dpi)
self.canvas = FigureCanvasQTAgg(self.figure)
if toolbar:
self.toolbar = NavigationToolbar2QT(self.canvas, self)
layout.addWidget(self.toolbar, 0)
layout.addWidget(self.canvas, 1)
在 Qt 设计器中,我可以轻松地为此提升一个 QWidget,将头文件设置为“my_module/plot_widget.h”,并将其名称设置为 PlotWidget。然后,我可以通过动态加载从我的 ui 文件构造一个小部件,如下所示:
example.py:
from PyQt5 import QtWidgets, uic
class MyWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
uic.loadUi('example.ui', self)
self.show()
这很好用,除了 我没有看到修改默认初始化参数的直接方法(在本例中为工具栏、figsize 和 dpi)。
我知道有可能为此创建自定义插件,但我想避免它,因为我认为这会给我的简单需求增加不必要的复杂性。此外,我希望我的代码尽可能与 PySide / PyQt4 / PyQt5 兼容(为此,我实际上是直接使用 QtPy 而不是 PyQt5,虽然这有点离题),我并不完全相信如果我开始使用插件,我可以做到这一点。
因此,我想到了以下两种方法:
方法 1:以编程方式调用 setupUi()
基本上,我可以简化我的构造函数,以便不在那里调用 setupUi(),并在加载 ui 文件后执行该调用:
plot_widget.py:
class PlotWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(PlotWidget, self).__init__(parent)
...
example.py:
from PyQt5 import QtWidgets, uic
class MyWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
uic.loadUi('example.ui', self)
self.myPlotWidget.setupUi(figsize=(4, 4), dpi=200)
self.show()
方法 2:使用动态属性
我可以在 Qt 设计器中添加我需要的任何动态属性,而不是向 setupUi() 传递额外的参数,然后像这样使用它们:
figsize = self.property('figsize')
如果它们没有被定义,它们将只是 None。问题是在将这些动态属性添加到对象之前调用了 init 构造函数(这似乎是逻辑),因此 figsize 在此代码中始终为 None:
plot_widget.py:
class PlotWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(PlotWidget, self).__init__(parent)
def setupUi(self):
layout = QtWidgets.QVBoxLayout(self)
toolbar = self.property('toolbar') # Always None
figsize = self.property('figsize') # Always None
dpi = self.property('dpi') # Always None
self.figure = Figure(figsize=figsize, dpi=dpi)
self.canvas = FigureCanvasQTAgg(self.figure)
if toolbar:
self.toolbar = NavigationToolbar2QT(self.canvas, self)
layout.addWidget(self.toolbar, 0)
layout.addWidget(self.canvas, 1)
这意味着我仍然需要在我的 example.py 文件中显式调用 setupUi(),除非我能找出其他东西。
结论
我更喜欢方法 2 的想法,因为它允许我直接从 Qt 设计器修改所有 ui 参数。但是,我想避免显式调用 setupUi()。因此,是否有任何 QWidget 方法在将动态属性分配给对象后总是被调用(因此我可以重写它以在那里调用 setupUi())?
另外,您是否发现这种方法有任何其他缺陷,或者您知道实现我想要实现的目标的任何其他替代方法吗?请注意,我使用了 matplotlib 画布作为示例(可能已经有一些特定的方法),但我想将它用于我可能需要的任何自定义小部件。
【问题讨论】:
标签: python pyqt qt-designer