2016-09-20 5 views
0

Ich kann nicht einen wx.ProgressDialog zu schließen. Wenn es abläuft; alles ist gut. Durch Klicken auf "Abbrechen" oder "Überspringen" wird der Dialog verlassen, aber das Fenster bleibt für immer auf dem Bildschirm eingefroren (Kontrollfluss kehrt zurück).wxpython: zerstören abgebrochen ProgressDialog

import wx 
def Progress(parent=None, message="", title="", maximum=3000): 
    dlg = wx.GenericProgressDialog(title, message, maximum,style=wx.PD_AUTO_HIDE|wx.PD_APP_MODAL|wx.PD_CAN_SKIP|wx.PD_CAN_ABORT) 
    keepGoing = True 
    skip = False 
    count = 0 

    while keepGoing and (not skip) and count < maximum: 
     count += 1 
     wx.MilliSleep(1) 
     wx.Yield() 
     (keepGoing, skip_bogus) = dlg.Update(count) 
     skip = dlg.WasSkipped() #NOTE: skip_bogus doesn't ever seem to update; even when skip button is clicked 

    dlg.Destroy() 
    wx.Yield() 

    if not keepGoing: 
     return "cancel" 
    elif skip: 
     return "skip" 
    else: 
     return None 

app = wx.App() 
app.MainLoop() 

Progress(None, "message", "title") 

wxpython v3.0.2 Python v2.7.10

Antwort

0

Dies ist ein klassisches Beispiel für eine LongRunningTask: Ihre while Schleife wird alle Zeit nicht verwendet für Event-Handling auffressen. Wenn sich die Ereignisse häufen, reagiert die GUI nicht mehr und wxPython kann Ereignisse nicht mehr rechtzeitig verarbeiten (oder Anrufe für wx.Yield() verarbeiten).

Die Lösung für dieses Problem besteht darin, blockierende Ereignisse/lang laufende Aufgaben in einem separaten Thread zu platzieren und in die GUI threadsicher zurückzurufen, indem Sie e verwenden. G. wx.CallAfter wenn die Arbeit erledigt ist.

Studieren Sie das letzte Beispiel in der oben angegebenen Verbindung, Easiest Example *ever* :), um eine Idee zu bekommen, wie man das macht.

+0

Das löst das Problem nicht. NACH dem Beenden der Schleife wird der Dialog nicht zerstört. CPU-Auslastung während der Schleife ist irrelevant. – whitey04

+0

Zugegeben, Ihr Beispiel funktioniert bei mir mit der exakt gleichen ** Konfiguration wie Ihre (Python dinge 32 bit, Win7 64 bit) ohne die geringste Änderung. Selbst Änderungen wie von @RobinDunn vorgeschlagen sind nicht notwendig. – nepix32

1

Es kann etwas Plattform abhängig sein, aber Ihre Progress Funktion nach der MainLoop Rückkehr ist eine rote Fahne für mich. Top-Level-Fenster werden nicht zerstört, wenn ihre Methode Destroy aufgerufen wird, stattdessen werden sie einer ausstehenden Löschwarteschlange hinzugefügt, die später in der Ereignisschleife verarbeitet wird.

Versuchen Sie, den Anruf zu Process vor dem MainLoop Aufruf setzen, und den Anruf zu wx.Yield nach den Destroy entfernen. Das funktioniert bei OSX und Phoenix.

0

Die Antworten von Robin und nepix32 sind wertvolle Ratschläge. Warum nicht wx.Timer verwenden, um den Dialog kontinuierlich zu aktualisieren? Etwas wie:

class Progress: 
    def __init__(self): 
     self.dlg = wx.GenericProgressDialog(whatever) 
     self.count = 0 

    def Start(self): 
     self._update() 
     self.timer = wx.Timer(self.dlg) 
     self.dlg.Bind(wx.EVT_TIMER, self._update, self.timer) 
     self.timer.Start(1) # 1ms interval 

    def _update(self, evt=None): 
     self.count += 1 
     if self.count == self.dlg.GetRange(): 
      self._stop() 
     else: 
      self.dlg.Update(self.count) 
      if self.dlg.WasSkipped() or self.dlg.WasCancelled(): 
       self._stop() 

    def _stop(self): 
     self.timer.Stop() 
     self.dlg.Close() 
     wx.GetApp().ExitMainLoop() 

Die Antwort auf Ihre Frage - wie den Dialog zu schließen - ist wx.GetApp().ExitMainLoop().