【问题标题】:Removing a widget from its wxPython parent从其 wxPython 父级中删除一个小部件
【发布时间】:2016-12-09 04:49:01
【问题描述】:

以下程序存在内存泄漏(我在 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 的方法是什么?

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

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

【问题讨论】:

    标签: python wxpython


    【解决方案1】:

    我想我明白了。我在 Windows 10 上,但我观察到相同的内存泄漏。将 RemoveWidget 方法修改为此在我的计算机上解决了它。 解释见代码 cmets

    经过编辑以反映 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()
    

    【讨论】:

    • 小部件在销毁时会从 sizer 中移除,所以是的,这是多余的。此外,小部件会将自己从父级的子级列表中删除,因此调用 RemoveChild 也是多余的。 IOW,对 window.Destroy() 的调用将足以删除小部件及其资源,并在父级和 sizer 中进行必要的清理。
    • 在 linux (raspbian) 中检查了你的代码:也没有内存泄漏。
    猜你喜欢
    • 1970-01-01
    • 2016-12-12
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 2020-07-09
    • 2019-06-24
    相关资源
    最近更新 更多