从其 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()
以下程序存在内存泄漏(我在 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()