PyDeadObjectErrors

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

Hi,

ich habe eine Application geschrieben bei der alles wunderbar klappt, jedoch wenn ich die app beende ohne irgendetwas gemacht zu haben (also quasi anschalten und gleich wieder schliessen), schmeisst es mir immer PyDeadObjectError.

Code: Alles auswählen

Traceback (most recent call last):
  File "D:\workspace\MusicNSFX\src\main.py", line 447, in on_timer
    self.volume_music_btn, event)
  File "D:\workspace\MusicNSFX\src\main.py", line 347, in check_vol_pic
    if bitmap_button.GetBitmapLabel() in [self.vol_img, ini_bmp]:
  File "C:\Python26\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 14568, in __getattr__
    raise PyDeadObjectError(self.attrStr % self._name)
wx._core.PyDeadObjectError: The C++ part of the BitmapButton object has been deleted, attribute access no longer allowed.
Es geht also um einen BitmapButton und der C++ Teil wurde geloescht. also dem bild das fundament unter den Fuessen wggerissen. Der Umstand ist fuer mich nicht schlimm, aber etwas unschoen. Ich habe aber keine Ahnung wie ich dem Ganzen vorbeugen koennte.

Wuerde mich ueber jeden Ratschlag freuen. Im Uebrigen beende ich die App in dem ich auf den Windows eigenen Schliessen Knopf (Kreuz rechts oben) druecke.
Gremlin
User
Beiträge: 166
Registriert: Freitag 28. Mai 2010, 23:49

Kann es sein, dass dein Timer-Objekt noch aktiv ist, während wx seine Aufräumarbeiten durchführt? So etwas ähnliches hatte ich glaube ich auch einmal, nur ob es ausgerechnet diese Ausnahme war weiß ich nicht mehr, aber ich nehms an. Jedenfalls würd ich an deiner Stelle dafür sorgen dass alle deine Threads/Timer gestoppt werden bevor du wx die Aufräumarbeiten überlässt. (Fenster schließen)

Edit: Dafür bietet sich das CloseEvent an.
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

Hi Gremlin,

das ist alles sehr gut moeglich, weil ich ja keine wxpython eigene Schliessfunktion benutze sondern die des Betriebssystems. Ich habe seit dem post noch ein bisschen herumprobiert und einen Quit Button eingebaut, der erst den timer stoppt und dann sys.exit() aufruft. Da passiert das nicht.

Muesste ich dann den Schliessaufruf von Windows abfangen und den auch an die selbe funktion wie den quit button binden, um den PyDeadObjectErrors aus dem weg zu gehen?

Ist es ueberhaupt schlimm solche Objekte zu haben, wenn man das program sowieso beendet?
Gremlin
User
Beiträge: 166
Registriert: Freitag 28. Mai 2010, 23:49

Das Betriebssystem kann keine Funktionen in deiner Anwendung ausführen, sondern ihr nur Signale senden. (Korrigiert mich wenn ich falsch liege.) Und bei Windows gibt es in diesem Fall nur das Signal zum beenden. Aber egal aus welchem Grund deine Anwendung beendet werden soll, die Funktionen sind immer dieselben und werden durch Events innerhalb von wx ausgeführt.

Um zukünftige Probleme dieser Art zu vermeiden, solltest du wie erwähnt das "CloseEvent" benutzen. In dieser Funktion führst du dann deine Anwendungsspezifischen Aufräumarbeiten durch (Threads killen, Timer stoppen, etc) oder fragst z.B. den Benutzer ob er denn vor dem beenden noch speichern möchte. Wichtig ist bei diesem Event jedoch, dass solange du die "Verantwortung" nicht wieder an wx übergibst (event.Skip), du dafür sorgen musst, wx zu sagen dass es "aufräumen" soll (window.Destroy). Siehe auch in der Dokumentation.

Sobald du dieses Event integriert hast, kannst du einfach "window.Close" aufrufen, was auch der richtige Weg wäre. Denn "sys.exit" ist nicht sauber. Das ist fast schon mit dem "Task beenden" aus dem Windows Taskmanager zu vergleichen. Wenn du "window.Close" aufrufst wird nämlich auch das "CloseEvent" (also deine Aufräumarbeiten) ausgeführt.

Ob und wie schlimm es ist "Daemon"-Threads zurück zu lassen, kann ich dir nicht sagen, nur dass ich irgendwo irgendwann einmal gelesen habe diese wenn möglich zu vermeiden. :P
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

Hi,

bin jetzt endlich dazu gekommen, dieses kleine Problem zu beheben. PyDeadObjektErrors werden definitiv nicht mehr geworfen. Das habe ich folgendermassen gemacht (self.t und self.occ_sfx_timer sind halt die Timer die noch gestoppt werden mussten)

Code: Alles auswählen

    def init_frame(self):
        self.frame = self.res.LoadFrame(None, 'MAIN_FRAME')     

        # Close frame binding
        self.frame.Bind(wx.EVT_CLOSE, self.on_exit, id=xrc.XRCID('MAIN_FRAME'))

    def on_exit(self, event):
        self.t.Stop()
        self.occ_sfx_timer.Stop()
        self.frame.Destroy()
Falls jemand noch Kommentare hat, dann bitte nicht schuechtern sein. Danke auch an Gremlin. Unser kurzer Austausch hat sehr zu meinem Verstaendnis beigetragen :D
Antworten