基于用户交互,我想动态添加和删除控件到wxPython笔记本中的面板。我最彻底尝试的方法是在面板的sizer上调用.Clear()
并添加所有新控件。但是,在Windows 7和Linux桌面上,渲染工件和过时控件在新内容下仍然可见。如何在没有这些工件的情况下完全删除旧控件并添加新控件?
以下是在Windows 7上重现该问题的示例程序。请注意.update()
和StaticPanel
的两种DynamicPanel
方法:
#!/usr/bin/python
import wx
import sys
class StaticPane(wx.Panel):
"""A panel that contains simple text that is updated
when the .update() method is called. The text is updated
using .SetText(), and the text control sticks around
between calls to .update()."""
def __init__(self, *args, **kwargs):
super(StaticPane, self).__init__(*args, **kwargs)
self._sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self._sizer)
self._counter = 0
self._base_text = "Some Text"
self._text = wx.TextCtrl(self, -1,
self._base_text + "!" * self._counter,
style=wx.TE_READONLY)
self._sizer.Add(self._text, -1, wx.EXPAND)
def update(self):
self._counter += 1
self._text.SetValue(self._base_text + "!" * self._counter)
class DynamicPane(wx.Panel):
"""A panel that contains simple text that is updated
when the .update() method is called. The text is updated
by removing the existing text control, and adding a new one
with the updated text string."""
def __init__(self, *args, **kwargs):
super(DynamicPane, self).__init__(*args, **kwargs)
self._sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self._sizer)
self._counter = 0
self._base_text = "Some Text"
self._text = wx.TextCtrl(self, -1,
self._base_text + "!" * self._counter,
style=wx.TE_READONLY)
self._sizer.Add(self._text, -1, wx.EXPAND)
def update(self):
self._counter += 1
self._sizer.Clear()
self._text = wx.TextCtrl(self, -1,
self._base_text + "!" * self._counter,
style=wx.TE_READONLY)
self._sizer.Add(self._text, -1, wx.EXPAND)
self.Layout()
class TestViewer(wx.Frame):
"""A Frame with a button and a notebook. When the button is pressed,
each of the two pages in the notebook recieve a call to .update().
"""
def __init__(self, parent):
super(TestViewer, self).__init__(parent, -1, "Test Viewer")
self.Bind(wx.EVT_CLOSE, self.OnClose)
self._panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
self._panel.SetSizer(vbox)
update_button = wx.Button(self._panel, wx.ID_CLOSE, "Update")
update_button.Bind(wx.EVT_BUTTON, self.update)
vbox.Add(update_button, 0, wx.EXPAND)
self._nb = wx.Notebook(self._panel)
self._view_one = StaticPane(self._nb, -1)
self._view_two = DynamicPane(self._nb, -1)
self._nb.AddPage(self._view_one, "One")
self._nb.AddPage(self._view_two, "Two")
vbox.Add(self._nb, 1, wx.EXPAND | wx.ALL)
self.Layout()
def update(self, e):
self._view_one.update()
self._view_two.update()
def OnClose(self, event):
sys.exit(0)
if __name__ == "__main__":
app = wx.App(False)
frame = TestViewer(None)
frame.Show()
app.MainLoop()
单击“更新”按钮以更新两个面板中的文本。第一个面板使用.SetText()
更新文本控件,而第二个面板使用新面板替换TextCtrl
。请注意,在单击几次按钮后调整窗口大小或鼠标悬停在第二个面板上时,会出现重叠控件和其他工件。
以下是显示堆叠控件的屏幕截图。两个图像都是在相同数量的按钮点击后拍摄的,它们只显示处于相同状态的两个不同面板。我希望文本完全相同。
答案 0 :(得分:2)
简单地清除sizer只会删除对其内容的引用,而不是小部件。创建窗口小部件时,它将向您提供的父窗口注册。请考虑以下代码:
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None)
self.textCtrl = wx.TextCtrl(self) # create with Frame as parent
self.textCtrl = None # has no effect on the TextCtrl
父窗口(本例中为Frame)将取得TextCtrl的所有权,即使将其设置为None,Frame也会保持活动状态直到它被销毁。要删除TextCtrl,您必须明确地销毁它:
self.textCtrl.Destroy()
如果要一次删除所有子窗口小部件,可以使用:
self.DestroyChildren()