2016-12-09 5 views
2

Das folgende Programm hat einen Speicherverlust (I bestätigte diese auf einem Linux-System, mit dem top Befehl)Entfernen ein Widget von seiner WxPython Mutter

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() 

Das Problem ist, dass in RemoveWidget, wird der Knopf entfernt von die Sizer, aber nicht von der übergeordneten wx.Panel.

Wie entferne ich die wx.Button vom übergeordneten (wx.Panel in diesem Fall)?

Als ich nach "remove wxPython widget" suchte, sagten die Antworten, die ich fand, nur, wie man von Sizer entfernt. (In der Tat ist mein Code eine Variation von http://www.blog.pythonlibrary.org/2012/05/05/wxpython-adding-and-removing-widgets-dynamically/).

Es gibt eine RemoveChild Methode in der wx.Window Klasse, aber Dokumentation sagt, es interne und sollte nicht durch Benutzercode (https://wxpython.org/Phoenix/docs/html/wx.Window.html#wx.Window.RemoveChild)

Antwort

2

Ich denke, nennen ich es herausgefunden. Ich bin auf Windows 10, aber ich beobachtete das gleiche Speicherleck. Durch das Ändern der RemoveWidget-Methode wurde dies auf meinem Computer gelöst. Siehe Code Kommentare für eine Erklärung

Edited widerzuspiegeln Eingaben von 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() 
+4

Widgets werden sich aus den Sizer entfernen, wenn sie zerstört werden, also ja, es ist überflüssig. Außerdem entfernen sich Widgets selbst aus der Child-Liste der Eltern, so dass der Aufruf von 'RemoveChild' ebenfalls redundant ist. IOW, der Aufruf von 'window.Destroy()' wird ausreichen, um das Widget und seine Ressourcen zu entfernen und die notwendigen Bereinigungen im Parent und im Sizer durchzuführen. – RobinDunn

+0

Überprüft Ihren Code in Linux (Raspbian): kein Speicherleck entweder. –

Verwandte Themen