gelöst: OS X Duplikate von Fenstern nach verschieben

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Hallo allerseits!

Ich habe ein kleines Programm geschrieben, daß ein Hauptfenster und mehere zusätzliche Fenster besitzt (Prefs, About, Help, u.s.w.)
aufgerufen wird das Hauptfenster aus dem Hauptprogramm mit

Code: Alles auswählen

class MainApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
        MainWindow = MainFrame(None, -1, "")
        self.SetTopWindow(MainWindow)
        MainWindow.Show()
        return 1
und z.B. das Prefsfenster aus der MainWindow mit

Code: Alles auswählen

    def PrefsMenuItemHandler(self, event):
        PrefsWindow = PrefsFrame(None)
        PrefsWindow.Show()
        event.Skip()
Geschlossen werden die Fenster mit

Code: Alles auswählen

    def PrefsOkHandler(self, event):
        self.prefs[0] = 2    #    Prefsversion
        print 'PrefsWindow local prefs = ' +  str(self.prefs)
        self.writeprefs(self.prefs)
        self.Close() # self.Destroy() habe ich auch probiert - keine Veränderung
        event.Skip()
Das Hauptfenster verhält sich vollkommen normal, doch wenn ich das "Tochterfenster" verschiebe, dann bleiben an der Ausgangsposition Duplikate stehen.
Je öfter ich verschiebe, desto mehr "Tochterfenster muß ich nachher auch schließen, aber auch wenn ich nicht verschiebe muß ich immer sechs Fenster schließen.
Unter Linux, wo ich die GUI mit wxGlade erstellt habe, funktionieren übrigens alle Fenster normal.
Hat jemand von Euch eine Ahnung woran das liegen könnte?

Vielen Dank und LG

SB
Zuletzt geändert von Shining-Blue am Freitag 11. September 2009, 22:12, insgesamt 2-mal geändert.
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Zeig mal ein bischen mehr Code, bitte.

Wann und wo werden denn Deine Handler aufgerufen? Und wo werden sie gebunden?
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Daran soll es nicht hapern - wollte nur nicht gleich den halben Code hier abladen.
Die MainApp:

Code: Alles auswählen

import wx
from MainFrame import MainFrame

class MainApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
        MainWindow = MainFrame(None, -1, "")
        self.SetTopWindow(MainWindow)
        MainWindow.Show()
        return 1

# end of class MainApp

if __name__ == "__main__":
    import gettext
    gettext.install("ScaleIt") # replace with the appropriate catalog name

    ScaleIt = MainApp(0)
    ScaleIt.MainLoop()
Das Hauptfenster:

Code: Alles auswählen

# -*- coding: utf-8 -*-

import wx
import os
import pickle
from base64 import b64encode, b64decode
from PrefsFrame import PrefsFrame
from bbCodeFrame import bbCodeFrame
from HelpFrame import HelpFrame
from AboutFrame import AboutFrame

class MainFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MainFrame.__init__
        kwds["style"] = wx.ICONIZE|wx.CAPTION|wx.MINIMIZE|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.MAXIMIZE_BOX|wx.SYSTEM_MENU|wx.RESIZE_BORDER|wx.CLIP_CHILDREN
        wx.Frame.__init__(self, *args, **kwds)
        
        # Menu Bar
        self.MainFrame_menubar = wx.MenuBar()
        self.FileMenu = wx.Menu()

#	some file menu items

        self.EditMenu = wx.Menu()

#	some edit menu items

        self.EditMenu.AppendSeparator()
        self.PrefsMenuItem = wx.MenuItem(self.EditMenu, 8, _("Einstellungen..."), "", wx.ITEM_NORMAL)
        self.EditMenu.AppendItem(self.PrefsMenuItem)
        self.MainFrame_menubar.Append(self.EditMenu, _("Bearbeiten"))

#	some more menustuff

        self.MainFrame_menubar.Append(self.HelpMenu, _("Hilfe"))
        self.SetMenuBar(self.MainFrame_menubar)
        # Menu Bar end

#	more MainFrame items

        self.__set_properties()
        self.__do_layout()

#	some bindings

        self.Bind(wx.EVT_MENU, self.PrefsMenuItemHandler, self.PrefsMenuItem)

#	more bindings

        # end wxGlade

    def __set_properties(self):

#	some item properties

        # end wxGlade
        self.MainFrame_statusbar.SetStatusText("Arbeitsverzeichnis = " + self.prefs[4])

    def __do_layout(self):
        # begin wxGlade: MainFrame.__do_layout
        MainWindowSizer = wx.BoxSizer(wx.VERTICAL)

#	all the MainFrameSizer Stuff

        self.SetSizer(MainWindowSizer)
        self.Layout()
        # end wxGlade

#	some functions

    def QuitMenuItemHandler(self, event): # wxGlade: MainFrame.<event_handler>
        self.writeprefs(self.prefs)
        self.Close()
        event.Skip()

#	more handlers

    def PrefsMenuItemHandler(self, event): # wxGlade: MainFrame.<event_handler>
        PrefsWindow = PrefsFrame(None)
        PrefsWindow.Show()
        event.Skip()

#	more handlers
    
# end of class MainFrame
und z.B. das Prefsfenster

Code: Alles auswählen

# -*- coding: utf-8 -*-

import wx
import os
import pickle
from base64 import b64encode, b64decode

class PrefsFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: PrefsFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.PrefsWindowTabSet = wx.Notebook(self, -1, style=0)
        self.StampPrefsTab = wx.Panel(self.PrefsWindowTabSet, -1)
        self.FtpPrefsTab = wx.Panel(self.PrefsWindowTabSet, -1, style=wx.RAISED_BORDER)

#	all the other items

        self.PrefsOkButton = wx.Button(self, -1, _("OK"))

        self.__set_properties()
        self.__do_layout()

#	all the bindings

        self.Bind(wx.EVT_BUTTON, self.PrefsCancelHandler, self.PrefsCancelButton)
        self.Bind(wx.EVT_BUTTON, self.PrefsOkHandler, self.PrefsOkButton)
        # end wxGlade

    def __set_properties(self):
        # begin wxGlade: PrefsFrame.__set_properties
        self.SetTitle(_("Einstellungen"))
        self.SetSize((550, 500))
        self.SetBackgroundColour(wx.Colour(220, 220, 220))

#	and so on

        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: PrefsFrame.__do_layout
        PrefsWindowSizer = wx.BoxSizer(wx.VERTICAL)
        PrefsWindowButtonsGridSizer = wx.GridSizer(1, 2, 0, 0)
        StampPrefsTabVertSizer = wx.BoxSizer(wx.VERTICAL)
        StampPrefsHorzSizer = wx.BoxSizer(wx.HORIZONTAL)

#	and so on

        PrefsWindowSizer.Add(PrefsWindowButtonsGridSizer, 1, wx.ALIGN_BOTTOM|wx.SHAPED, 0)
        self.SetSizer(PrefsWindowSizer)
        self.Layout()
        # end wxGlade

#	my functions doing the stuff

    def PrefsCancelHandler(self, event): # wxGlade: PrefsFrame.<event_handler>
        self.Close()
        event.Skip()

    def PrefsOkHandler(self, event): # wxGlade: PrefsFrame.<event_handler>
        self.prefs[0] = 2    #    Prefsversion
        print 'PrefsWindow local prefs = ' +  str(self.prefs)
        self.writeprefs(self.prefs)
        self.Close()
        event.Skip()
# end of class PrefsFrame
Interresanter Weise verhalten sich alle Tochterfenster so, egal ob wxFrame oder wxDialog.
Ich hoffe das reichte soweit an Code um das Problem erkennen zu können, denn an sonsten würde ich den Quelltext schnell onliene stellen und verlinken.

LG SB

P.S.:
Umgebungen:
Linux Fedora 10, Python 2.6.2, wxPython 2.8.9.1 (funktioniert problemlos)
OS X 10.5.8, Python 2.6.2, wxPython 2.8.9.2 (hier treten die Probleme auf)
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Ok, der problematische Codeteil war doch schon in Deinem ersten Beitrag. Das event.Skip() in PrefsMenuItemHandler sorgt wohl dafür, dass der Event auf manchen Systemen (Mac OS X, aber auch hier bei mir unter Vista) mehrfach gefeuert wird. Scheint ein Bug oder zumindest "Quirk" in wxPython zu sein. Ich habe auch ein ziemlich altes Ticket auf wxwidgets.org gefunden, das genau auf die Problematik passt - ist mir wahrscheinlich nur deshalb noch nie selbst passiert, weil ich bis jetzt noch kein Skip() in einem Menu-Item-Handler gebrauch habe. Falls Du das also nicht zwingend brauchst, sollte das Weglassen schon die Lösung sein :)
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Na das ist doch eine klare Ansage :!:
Ich habe das Skip() nur im Code gelassen, weil wxGlade sie dort automatisch gesetzt hat, ohne mich näher um deren Funktion zu kümmern - traue keinem Codegenerator :oops:
Als Python und erst recht wxPython Anfängerin erkunde ich noch sehr viel nach dem Try and Error Prinzip.
So wie ich es jetzt in http://www.wxpython.org/docs/api/wx.Eve ... .html#Skip verstanden habe, scheint das Problem also im aufrufenden Eventhandler zu liegen, wo eine Weiterverarbeitung des Events absolut überflüssig ist. Einzig beim QuitEvent möchte ich eine Weiterleitung des Events, was ja unkritisch sein dürfte, da ja schon das erste Event letztendlich in einem Destroy(self) endet.
Werde es gleich mal umsetzen und nachher auf den anderen Plattformen (OS X / WinXP) testen.
Vielen dank für den heißen Tip.

LG SB

P.S.: wxPython scheint ja noch einige Bugs mehr zu haben, die nur plattformübergreifend zu Tage treten.
Z.B. das explizite setzen einer Hintergrundfarbe eines Labels auf den Wert der Hintergrundfarbe des Frames / Panels o.ä. funktioniert unter Linux, auch wenn es überflüssig ist, wie erwartet. Unter OS X bekommen die Objekte interessanter Weise eine andere (dunklere) Farbe - häää ??? Läßt man die explizite Definition einfach weg ist alles wieder im grünen Bereich.
Shining-Blue
User
Beiträge: 37
Registriert: Samstag 15. August 2009, 04:36

Ich wollte nur noch einmal eine kurze Rückmeldung geben und den Thread als gelöst markieren.
Also der Tip mit dem event.Skip() war ein Volltreffer!
Ich konnte es leider erst jetzt auf den anderen Plattformen testen, da unser Mac dauernd besetzt war ( grrr, grummel, aber wen wundert's).
In der Zwischenzeit ist eine recht komplexe und komfortable GUI entstanden, die erstaunlicher Weise unter alllen drei Plattformen ein recht sauberes Look & Feel aufweist.
Also nochmals herzlichen Dank für den hilfreichen Tip (und etlichen weiteren, die ich zwischenzeitlich hier im Forum entdeckt habe)

LG SB
Antworten