Python PyQt-轻松地向所有视图添加QWidget
我有以下几点Python PyQt-轻松地向所有视图添加QWidget,python,pyqt,pyqt5,Python,Pyqt,Pyqt5,我有以下几点 class MyView(QWidget): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QVBoxLayout() layout.addWidget(QLabel('Hello World')) self.setLayout(layout) class NavigationMenu(QWi
class MyView(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QVBoxLayout()
layout.addWidget(QLabel('Hello World'))
self.setLayout(layout)
class NavigationMenu(QWidget):
pass
# Renders a bar of full width and 15 px height
将导航菜单添加到MyView
的最简单方法是什么
将来,我还必须将NavigationMenu
添加到所有其他视图中,因此我希望从键入和可维护性的角度来寻找可扩展的内容
我尝试了decorator(只在类的顶部使用了@NavigationMenuDecorator
),但我要么无法绑定它们,要么它们在解析时被初始化,错误QWidget:必须在QWidget
之前构造QApplication
我试着把它添加到我的视图中,但是有很多样板文件
class MyWidget(Widget.QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = Widget.QVBoxLayout()
layout.addWidget(QLabel('Hello World'))
topLayout = Widget.QVBoxLayout()
topLayout.setContentsMargins(0, 0, 0, 0)
topLayout.addWidget(NavigationMenu())
topLayout.addLayout(layout)
self.setLayout(topLayout)
一种可能的解决方案是使用元类:
from PyQt5 import QtCore, QtWidgets
class NavigationMenu(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(QtWidgets.QLabel("NavigationMenu"))
class MetaNavigationMenu(type(QtWidgets.QWidget), type):
def __call__(cls, *args, **kw):
obj = super().__call__(*args, **kw)
lay = obj.layout()
if lay is not None:
lay.addWidget(NavigationMenu())
return obj
class View(QtWidgets.QWidget, metaclass=MetaNavigationMenu):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(QtWidgets.QLabel('Hello World'))
self.setLayout(layout)
if __name__=="__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = View()
w.show()
sys.exit(app.exec_())
更新:
使用以下方法,可以插入视图和视图所需的其他参数:
from PyQt5 import QtCore, QtWidgets
class NavigationMenu(QtWidgets.QWidget):
def __init__(self, value, text="", parent=None):
super().__init__(parent)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(QtWidgets.QLabel(text))
print(value)
class MetaMenu(type(QtWidgets.QWidget), type):
def __new__(cls, class_name, parents, attrs, **kwargs):
cls._view = kwargs.pop('view', None)
cls._args = kwargs.pop('args', tuple())
cls._kwargs = kwargs.pop('kwargs', dict())
return type.__new__(cls, class_name, parents, attrs)
def __call__(cls, *args, **kw):
obj = super().__call__(*args, **kw)
layout = getattr(obj, 'layout', None)
if callable(layout) and View is not None:
layout().addWidget(cls._view(*cls._args, **cls._kwargs))
return obj
class View(QtWidgets.QWidget, metaclass=MetaMenu, view=NavigationMenu, args=(10, ), kwargs={"text": "NavigationMenu"}):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(QtWidgets.QLabel('Hello World'))
self.setLayout(layout)
if __name__=="__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = View()
w.show()
sys.exit(app.exec_())
这里的另一个解决方案是惊人的,我学到了很多关于元类的知识。然而,它很难阅读,并且增加了不必要的复杂性。我决定采用一种基于合成的方法,在这种方法中,我只是将样板文件提取到一个单独的函数中
add_navigation()
函数将旧布局包装到小部件中,使用NavigationMenu
和旧布局创建QVBoxLayout,最后交换布局
def add_navigation(widget, title)
main = QWidget()
main.setLayout(widget.layout())
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
layout.addWidget(NavigationBar(title))
layout.addWidget(main)
widget.setLayout(layout)
然后,我们只有一行的样板文件,代码就变成了
class MyView(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QVBoxLayout()
layout.addWidget(QLabel('Hello World'))
self.setLayout(layout)
add_navigation(self, 'Navigation Title')
class NavigationMenu(QWidget):
pass
# Renders a bar of full width and 15 px height
如果您继承自MyWidget
,则最后一个选项不是boiler plate。但是,我必须为每个视图增加一个类,对吗?那将是样板。我不确定你的解决方案会是什么样子。如果你的每个类都继承自MyWidget
,那么它们都可以免费获得导航菜单。听起来很有趣。你能在回答中详细说明一下吗?我想那会有用的。但是,如果NavigationMenu接受一些参数(例如“NavigationMenu”QLabel
),该怎么办?继承也会有同样的问题。时区不同,上床睡觉了,抱歉。这个解决方案是有效的,这就是我正在寻找的。我从中学到了很多关于元类的知识。谢谢你不仅花时间写了这封信,而且还向我解释了这封信。然而,对于代码库中的初学者来说,它不容易阅读。最后,我只是将样板文件提取到一个函数中,然后使用组合。我对你的答案投了赞成票,但无法接受。谢谢你@不幸的是,我在编写代码时并没有考虑OP在这个主题上的级别,在我的例子中,我编写了关于设施的最佳解决方案(这并不意味着设施除了使用之外,所有人都能理解)和可伸缩性:-)