我正在开发一个 Python 类,它允许调用者将小部件添加到自定义 GUI。要设置 GUI,用户需要编写一个方法,将小部件(命名或匿名)添加到小部件区域,以便小部件形成一棵树(这在 GUI 中很常见)。
为了允许用户设置小部件树,而不必为每个容器小部件指定名称(然后在每次添加子小部件时显式引用该父小部件),我的 API 支持“父小部件”的概念小部件堆栈”。声明容器小部件时,用户可以指定将该小部件推入此堆栈,然后任何其他小部件(未显式指定父级)将默认添加到堆栈顶部的父级。这是我的意思的一个简单例子:
def SetupGUI(self):
self.AddWidget(name="root", type="container", push=True)
self.AddWidget(type="container", push=True)
for i in range(0,8):
self.AddWidget(name="button%i"%i, type="button")
self.PopParentWidget() # pop the buttons-container off the parents-stack
self.AddWidget(type="container", push=True)
for i in range(0,8):
self.AddWidget(name="slider%i"%i, type="slider")
self.PopParentWidget() # pop the sliders-container off the parents-stack
self.PopParentWidget() # pop the container "root" off the parents-stack
这很方便,但我发现当 GUI 层次结构变得更加复杂时,开始变得很难判断哪个 self.PopParentWidget() 调用对应于哪个容器小部件。很容易输入太多或太少,最终会在 GUI 中产生非常有趣但意想不到的结果。
所以我的问题是,除了强制 PopParentWidget() 采用显式小部件名称(我想避免这种情况,因为我不想命名每个容器小部件)之外,我能做些什么来进行推送/pop 代码中的配对看起来更明显?
在 C/C++ 中我会使用缩进来做到这一点,但在 Python 中我不允许这样做。例如,我很想能够做到这一点:
def SetupGUI(self):
self.AddWidget(name="root", type="container", push=True)
self.AddWidget(type="container", push=True)
for i in range(0,8):
self.AddWidget(name="button%i"%i, type="button")
self.PopParentWidget() # pop the buttons-container off the parents-stack
self.AddWidget(type="container", push=True)
for i in range(0,8):
self.AddWidget(name="slider%i"%i, type="slider")
self.PopParentWidget() # pop the sliders-container off the parents-stack
self.PopParentWidget() # pop the container "root" off the parents-stack
...但是如果我有这样的创意,Python 会抛出一个 IndentationError。
这种情况——你有一对相反的操作——需要上下文管理器。您无需将容器小部件显式推入堆栈或从堆栈中弹出,而是将容器的子级包装在
with
块中。基于您在此处显示的代码构建,可以将其实现为类似
@contextlib.contextmanager
def container(self, name=None):
self.AddWidget(name=name, type='container', push=True)
yield
self.PopParentWidget()
contextlib.contextmanager
的文档)。
您的
SetupGUI
方法将变为:
def SetupGUI(self):
with self.container(name='root'):
with self.container():
for i in range(0,8):
self.AddWidget(name='button%i' % i, type='button')
with self.container():
for i in range(0,8):
self.AddWidget(name='slider%i' % i, type='slider')
如您所见,嵌套从缩进中清晰可见,无需手动推送和弹出。