1

基于用户交互,我想在 wxPython 笔记本的面板中动态添加和删除控件。我尝试过的最彻底的方法是调用.Clear()面板的 sizer 并添加所有新控件。但是,在 Windows 7 和 Linux 桌面上,渲染工件和过时的控件在新内容下仍然可见。如何在没有这些工件的情况下完全删除旧控件并添加新控件?

下面是在 Windows 7 上重现该问题的示例程序。请注意 和 的两种不同.update()方法:StaticPanelDynamicPanel

#!/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为新的。请注意,在单击几次按钮后调整窗口大小或将鼠标悬停在第二个面板上时,会出现重叠的控件和其他伪影。

以下是显示堆叠控件的屏幕截图。两张图片都是在点击相同次数的按钮后拍摄的,它们只是显示两个不同的面板处于相同的状态。我希望文本完全一样。

面板 1 (<code>.SetText()</code>) 面板 2(<code>TextCtrl</code> 已替换)

4

1 回答 1

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()
于 2012-11-01T22:50:18.520 回答