Fehler beim Beenden

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

Hallo!

Ich habe folgendes Problem:
Ich habe eine Wx-Applikation geschrieben und jetzt habe ich (warum auch immer) eine Fehlermeldung, wenn ich das Programm beenden will, dabei kann ich keinen Fehler finden.
meine End-Methode sieht so aus:

Code: Alles auswählen

        self.Bind(wx.EVT_CLOSE, self.__onClose)
           .
           .
           .
    def __onClose(self, event):
        self.Destroy()
Ich bekomme kein Traceback, sondern einen Windows Fehler. Der Frame schließt sich und es kommt eine Meldung
"Python Exe hat ein Problem festgestellt und muss beendet werden
Problembericht senden / nicht senden usw..."
Bei meinen anderen Programmen habe ich dieses Problem nicht.

Ich habe gar keine Ahnung, woran das liegen könnte, hat jemand
auch schonmal so ein Problem gehabt? Habt ihr nen Tip, woran das liegen könnte?
Wär echt toll... :lol:
Python-Version: 2.5
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Spaten hat geschrieben:[...]eine Fehlermeldung, wenn ich das Programm beenden will

Code: Alles auswählen

        self.Bind(wx.EVT_CLOSE, self.__onClose)
           .
           .
    def __onClose(self, event):
        self.Destroy()
Hi Spaten!

1.) Du musst das Event wx.EVT_CLOSE nur dann abfangen, wenn du noch schnell etwas erledigen willst, bevor das Frame geschlossen wird.

2.) Ich persönlich, halte die zwei Unterstriche, vor dem ``onClose`` für übertrieben. Wenn du deine Methoden klein schreibst, dann läufst du auch nicht in Gefahr, eine wxPython-Methode zu überschreiben. Z.B. ``def on_close(self, event):``

3.) Wenn du nicht ``event.Skip()`` verwendest, brichtst du damit die wxPython-interne Verarbeitung des Close-Events ab.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import wx

wx.SetDefaultPyEncoding("iso-8859-1")


class MyFrame(wx.Frame):
    
    def __init__(self, parent = None, id = -1, title = "Servus"):
        wx.Frame.__init__(self, parent, id, title)
        self.Bind(wx.EVT_CLOSE, self.on_close)
    
    def on_close(self, event):
        print "on_close"
        event.Skip()
        return True
    

app = wx.PySimpleApp()
f = MyFrame()
f.Show()
app.MainLoop()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

Danke für die schnelle Antwort, aber ich verwende diese Methode
nicht nur mit dem Close-Event, sondern auch mit einem Menü-Event
und dort funktioniert es genauso wenig:

Code: Alles auswählen

self.Bind(wx.EVT_MENU, self.__onClose, id=ID_EXIT)
Python-Version: 2.5
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Spaten hat geschrieben:

Code: Alles auswählen

self.Bind(wx.EVT_MENU, self.__onClose, id=ID_EXIT)
Hi Spaten!

Kann es sein, dass du nicht das Event ``Close`` abfangen, sondern die Methode ``Close`` **auslösen** möchtest?

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import wx

wx.SetDefaultPyEncoding("iso-8859-1")


class MyFrame(wx.Frame):
    
    def __init__(self, parent = None, id = -1, title = "Servus"):
        wx.Frame.__init__(self, parent, id, title)
        
        # Das Schließen des Frames abfangen
        self.Bind(wx.EVT_CLOSE, self.on_close)
        
        # Menubar
        menubar = wx.MenuBar()
        
        # File-Menu
        mnu_file = wx.Menu()
        menuitem = mnu_file.Append(-1, u"Sch&ließen", u"Schließt dieses Fenster")
        self.Bind(wx.EVT_MENU, self.close_frame, menuitem)
        menubar.Append(mnu_file, "&Datei")
        
        # Menubar an Frame binden
        self.SetMenuBar(menubar)
        
        # Panel
        panel = wx.Panel(self)
        
        # Main-Sizer
        vbox = wx.BoxSizer(wx.VERTICAL)
        panel.SetSizer(vbox)
        
        # Platzhalter, damit der Button in der Mitte des Panels ist
        vbox.Add((0, 0), 1)
        
        # Close-Button
        cmd_close = wx.Button(panel, wx.ID_CLOSE, u"Sch&ließen")
        cmd_close.Bind(wx.EVT_BUTTON, self.close_frame)
        vbox.Add(cmd_close, 0, wx.ALIGN_CENTER)
        
        # Platzhalter, damit der Button in der Mitte des Panels ist
        vbox.Add((0, 0), 1)
        
        # Statuszeile
        self.CreateStatusBar()
        
        # Zentrieren
        self.Center()
    
    
    def close_frame(self, event = None):
        self.Close()
    
    
    def on_close(self, event):
        if wx.MessageBox(
            u"Möchten Sie das Fenster wirklich schließen?", u"Schließen",
            wx.YES_NO | wx.CENTER | wx.NO_DEFAULT | wx.ICON_QUESTION
        ) == wx.YES:
            # Mit dem Schließen des Frames weiter machen.
            event.Skip()
            return True
        else:
            # Das Schließen des Frames abbrechen
            event.Veto()
            return False
    

def main():
    app = wx.PySimpleApp()
    f = MyFrame()
    f.Show()
    app.MainLoop()


if __name__ == "__main__":
    main()
mfg
Gerold
:-)

Edit: Codebeispiel erweitert.
Zuletzt geändert von gerold am Samstag 23. Dezember 2006, 17:26, insgesamt 2-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

Ich will beides, ich will sowohl den EVT_CLOSE abfangen, als auch über
das Menü die Methode aufrufen.
Das funktioniert ja auch, aber beim Schließen des Frames (mit oder ohne Abfangen) gibt es einen Fehler (kein traceback, also nicht in der Konsole, sondern eine Windows-Fehlermeldung).

Ich hab das Gefühl, dass das nicht an einem Programmierfehler, sondern an einem Software-Wackelkontakt liegt...
Python-Version: 2.5
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Spaten hat geschrieben:Ich will beides, ich will sowohl den EVT_CLOSE abfangen, als auch über das Menü die Methode aufrufen.
Hi Spaten!

Ich habe oben aufgezeigtes Codebeispiel um deinen Wunsch erweitert.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

Das ist wirklich sehr freundlich von dir, danke! :)
Aber ich hab das ja schon implementiert, ich schließe das Frame mit
self.Destroy() und danach gibt es eine Fehlermeldung. Nicht von Python,
sondern von Windows.
Seltsamerweise geschieht dies auch nur bei dem einen Programm, bei meinen anderen nicht... :(
Python-Version: 2.5
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Spaten hat geschrieben:ich schließe das Frame mit self.Destroy()
Hi Spaten!

Ein Frame sollte man mit ``self.Close()`` schließen, da ``self.Destroy()`` das Event wx.EVT_CLOSE nicht auslöst.

Das Einfachste ist, wenn man im Event-Handler, der das Event wx.EVT_CLOSE behandelt, mit ``event.Skip()``, die Arbeit dem Frame selber überlässt. Wenn das nicht genügt (was nicht sein sollte), dann kannst du im Event-Handler mit ``self.Destroy()`` nachhelfen. Wenn du das Frame mit einem Klick auf das X in der Titelleiste schließen kannst, ohne irgendwo ``self.Destroy()`` angeben zu müssen, dann sollte es auch keine Probleme geben, wenn du im Programm schlicht und einfach ``self.Close()`` zum Schließen des Frames ausführst.

Ich musste ``self.Destroy()`` noch nie benutzen. Vielleicht habe ich aber auch noch nie so komplexe Fenster programmiert. :K

Ich glaube, ab diesem Punkt kann ich ohne funktionierenden Beispielcode, der dein Problem aufzeigt, nicht weiterhelfen.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

Vielen Dank für deine intensive Hilfe!

Ich habe jetzt mal den ganzen Event-Handler und die Bindings rausgenommen.
Das rote X ist ja defaultmäßig belegt.
Selbst ohne das verarbeiten der Events erzeugt das Schließen des Programmes einen Fehler. :cry:
Python-Version: 2.5
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

hmm hab nochwas ausprobiert. Und zwar habe ich ein GenericDirCtrl in meiner GUI.
Der Fehler tritt nur auf, wenn ich im Event-Handler für wx.EVT_TREE_SEL_CHANGED
die Methode GetPath() aufrufe:

Code: Alles auswählen

        self.dirctrl = wx.GenericDirCtrl(splitter, -1, os.getcwd())
        self.tree = self.dirctrl.GetTreeCtrl()
        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.__onFileSelected)

    def __onFileSelected(self, event):
        pfad = self.dirctrl.GetPath() ### !! Hier scheint der Fehler zu sein
        #pfad = "c:\\01.bmp" # feste Pfadangabe funktioniert
Wenn ich den Methodenaufruf durch einen String ersetzte gibt es beim Schließen keinen Fehler.
Während der Ausführung funktioniert dieser Aufruf auch korrekt.
Gibt es vielleicht etwas Unschönes an dieser Stelle?
Python-Version: 2.5
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Spaten hat geschrieben:

Code: Alles auswählen

        self.dirctrl = wx.GenericDirCtrl(splitter, -1, os.getcwd())
        self.tree = self.dirctrl.GetTreeCtrl()
        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.__onFileSelected)

    def __onFileSelected(self, event):
        pfad = self.dirctrl.GetPath() ### !! Hier scheint der Fehler zu sein
        #pfad = "c:\\01.bmp" # feste Pfadangabe funktioniert
Hi Spaten!

Ich habe keine Ahnung warum und keine Zeit zum Testen. Deshalb nur ein Versuch:
Versuche im wx.EVT_CLOSE-Handler den ``self.tree`` explizit zu zerstören.

Code: Alles auswählen

self.tree.Destroy()
del self.tree
wx.YieldIfNeeded()
Vielleicht hilfts :K

mfg
Gerold
:-)
PS: Das ist ein Fall für die wxPython-Mailingliste.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

Hey Danke ! :D :D
self.tree.Destroy() hat geholfen!!!
Super, ich weiß zwar nicht warum :lol: , aber das ist sehr schön, danke! :) :o
Python-Version: 2.5
Antworten