从其 wxPython 父级中删除一个小部件

Removing a widget from its wxPython parent

以下程序存在内存泄漏(我在 linux 系统上使用 top 命令验证了这一点)

import wx
from random import randint

class MyPanel(wx.Panel):
  def __init__(self,parent):
    wx.Panel.__init__(self,parent)
    self._parent = parent
    self._nb_buttons = 0
    self._main_sizer = wx.BoxSizer(wx.VERTICAL)
    self._ctrl_sizer = wx.BoxSizer(wx.HORIZONTAL)
    self._btns_sizer = wx.BoxSizer(wx.VERTICAL)
    self._btn_tim = wx.Button(self,label="Start auto")
    self._btn_tim.Bind(wx.EVT_BUTTON, self.OnStartStopEvent)
    self._ctrl_sizer.Add(self._btn_tim, 0, wx.CENTER|wx.ALL, 5 )
    self._main_sizer.Add(self._ctrl_sizer, 0, wx.CENTER )
    self._main_sizer.Add(self._btns_sizer, 0, wx.CENTER|wx.ALL,10)
    self.SetSizer(self._main_sizer)
    self._timer1 = wx.Timer(self)
    self.Bind(wx.EVT_TIMER, self.OnTimer, self._timer1)
    self._timer_running = False

  def OnStartStopEvent(self,event):
    if self._timer_running:    # toggle state of Timer
      self._timer1.Stop()
      self._btn_tim.SetLabel("Start")
      self._timer_running = False
    else:
      self._timer1.Start(200,False)
      self._btn_tim.SetLabel("Stop")
      self._timer_running = True

  def AddWidget(self):
    self._nb_buttons += 1 
    label = "Button %d" % self._nb_buttons
    name = "button%d" % self._nb_buttons
    new_button = wx.Button(self,label=label, name=name)
    self._btns_sizer.Add( new_button, 0, wx.ALL, 5 )
    self._parent._my_sizer.Layout()
    self._parent.Fit()

  def RemoveWidget(self):
    if self._btns_sizer.GetChildren():
      self._btns_sizer.Hide(self._nb_buttons -1 )
      self._btns_sizer.Remove(self._nb_buttons -1 )
      self._nb_buttons -= 1
      self._parent._my_sizer.Layout()
      self._parent.Fit()

  def OnTimer(self,event):
    n = randint(-3,3)
    if self._nb_buttons < 2: n += randint(0,2)
    if self._nb_buttons > 10: n -= randint(0,3)
    while n > 0:
      self.AddWidget()
      n -= 1
    while n < 0:
      self.RemoveWidget()
      n += 1

class MyFrame(wx.Frame):
  def __init__(self):
    wx.Frame.__init__(self,parent=None, title="Add remove buttons")
    self._my_sizer = wx.BoxSizer(wx.VERTICAL)
    panel1 = MyPanel(self)
    self._my_sizer.Add(panel1, 1, wx.EXPAND)
    self.SetSizer(self._my_sizer)
    self.Fit()
    self.Show()

def main():
  app = wx.App(False)
  frame1 = MyFrame()
  app.MainLoop()

if __name__ == '__main__':
  main()

问题是在 RemoveWidget 中,按钮是从 Sizer 中删除的,但不是从父 wx.Panel 中删除的。

从父级(在本例中为 wx.Panel)删除 wx.Button 的方法是什么?

当我搜索 "remove wxPython widget" 时,我找到的答案只告诉我如何从 sizer 中删除。 (实际上,我的代码是 http://www.blog.pythonlibrary.org/2012/05/05/wxpython-adding-and-removing-widgets-dynamically/ 的变体)。

wx.Window class 中有一个 RemoveChild 方法,但文档说它是内部方法,不应由用户代码调用 (https://wxpython.org/Phoenix/docs/html/wx.Window.html#wx.Window.RemoveChild)

我想我明白了。我在 windows 10,但我观察到同样的内存泄漏。将 RemoveWidget 方法修改为此在我的计算机上解决了它。 请参阅代码注释以获取解释

已编辑以反映 RobinDunn 的意见

def RemoveWidget(self):
    if self._btns_sizer.GetChildren():
        # GetItem returns a SizerItem, to get the actual button we have to call GetWindow
        window = self._btns_sizer.GetItem(self._nb_buttons - 1).GetWindow()
        # Calling Destroy removes widget from parent and sizer
        window.Destroy()
        self._nb_buttons -= 1
        self._parent._my_sizer.Layout()
        self._parent.Fit()