Einfaches Grundgerüst für ein GUI-Programm mit wxPython

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Freitag 14. April 2006, 23:02

Hi!

Ich lerne gerade mit wxPython umzugehen. Ich kann mir Dinge leichter merken, wenn ich sie mir aufschreibe. Und da spricht doch nichts dagegen, wenn ich es so mache, dass andere auch etwas davon haben. ;-)

Hier ein Beispiel für ein einfaches Grundgerüst:

Bild

Hier der zugehörige Code:

Code: Alles auswählen

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

import wx

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


class MyFrame(wx.Frame):
    """
    Hauptframe mit Menü und Statuszeile
    """

    def __init__(self, parent = None, title = "wxPython"):
       
        wx.Frame.__init__(self, parent, -1, title)
       
        # Menüleiste erstellen
        menubar = wx.MenuBar()
       
        # Datei-Menü
        mnu_file = wx.Menu()
       
        # Datei-Schließen
        mnu_f_close = mnu_file.Append(
            id = -1, text = u"Sch&ließen", help = u"Schließt dieses Fenster."
        )
        self.Bind(wx.EVT_MENU, self.close_frame, mnu_f_close)
       
        # Datei-Menü an Menüleiste binden
        menubar.Append(mnu_file, u"&Datei")
       
        # Hilfe-Menü
        mnu_help = wx.Menu()
       
        # Hilfe-Hilfe
        mnu_h_help = mnu_help.Append(
            id = -1, text = u"&Hilfe...", help = u"Zeigt die Hilfe an."
        )
        self.Bind(wx.EVT_MENU, self.show_help, mnu_h_help)
       
        # Separator
        mnu_help.AppendSeparator()
       
        # Hilfe-Info
        mnu_h_info = mnu_help.Append(
            id = -1, text = u"&Info...",
            help = u"Zeigt Informationen über das Programm an."
        )
        self.Bind(wx.EVT_MENU, self.show_info, mnu_h_info)
       
        # Hilfe-Menü an Menüleiste binden
        menubar.Append(mnu_help, u"&Hilfe")
       
        # Menüleiste an Frame binden
        self.SetMenuBar(menubar)
       
        # Panel erstellen
        panel = wx.Panel(self)
       
        ##########
        # Hier können weitere Widgets auf das Panel gelegt werden...
        ##########
       
        # Statusleiste erstellen und zuweisen
        self.CreateStatusBar()
    
    
    def close_frame(self, event = None):
        """
        Schließt dieses Fenster
        """
       
        self.Close()


    def show_help(self, event = None):
        """
        Zeigt die Hilfe an. (Als Ersatz dient hier eine einfache MessageBox.)
        """
       
        wx.MessageBox(
            message = u"Hier könnte ein Hilfetext stehen...",
            caption = u"Hilfe",
            style = wx.OK | wx.CENTER | wx.ICON_INFORMATION,
        )


    def show_info(self, event = None):
        """
        Zeigt Programminformationen an. (Als Ersatz dient hier eine einfache 
        MessageBox.)
        """
       
        wx.MessageBox(
            message = u"Info, Info, Info...",
            caption = u"Info",
            style = wx.OK | wx.CENTER | wx.ICON_INFORMATION,
        )


class MyApp(wx.PySimpleApp):
   
    def OnInit(self):
       
        # Frame erstellen, zentrieren und anzeigen
        frame = MyFrame()
        frame.Center()
        frame.Show()
        
        ##########
        # Hier gehört die fensterübergreifende Anwendungslogik her
        ##########
       
        return True


def main():
    """
    Hauptprozedur
    """
    
    # Jedes wxPython-Programm braucht eine App.
    app = MyApp()
    # Hier geht es erst weiter, wenn alle Fenster geschlossen wurden.
    app.MainLoop()


# Die Hauptprozedur wird nur gestartet, wenn dieses Python-Modul direkt aufgerufen
# wurde. Wenn dieses Modul von einem anderen Modul importiert wurde, dann passiert
# nichts. Dafür sind die folgenden zwei Zeilen Code zuständig.
if __name__ == "__main__":
    main()
lg
Gerold
:-)

Edit: Code ein wenig verbessert...
Zuletzt geändert von gerold am Samstag 1. Dezember 2007, 05:24, 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
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 5. April 2007, 17:39

Grundgerüst mit ein paar Widgets.

Bild

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 = "wxPython", size = (300, 250)):
       
        wx.Frame.__init__(self, parent, id, title, size = size)
       
        # Menüleiste erstellen
        menubar = wx.MenuBar()
       
        # Datei-Menü
        mnu_file = wx.Menu()
        
        # Datei-WerteAnzeigen-Menüeintrag
        mnu_f_show_values = mnu_file.Append(
            id = -1, text = u"Werte &anzeigen", help = u"Zeigt die Werte der Textfelder an."
        )
        self.Bind(wx.EVT_MENU, self.show_values, mnu_f_show_values)
        
        # Menü-Separator
        mnu_file.AppendSeparator()
       
        # Datei-Schließen-Menüeintrag
        mnu_f_close = mnu_file.Append(
            id = -1, text = u"Sch&ließen", help = u"Schließt dieses Fenster."
        )
        self.Bind(wx.EVT_MENU, self.close_frame, mnu_f_close)
       
        # Datei-Menü an Menüleiste binden
        menubar.Append(mnu_file, u"&Datei")
       
        # Hilfe-Menü
        mnu_help = wx.Menu()
       
        # Hilfe-Menüeintrag
        mnu_h_help = mnu_help.Append(
            id = -1, text = u"&Hilfe...", help = u"Zeigt die Hilfe an."
        )
        self.Bind(wx.EVT_MENU, self.show_help, mnu_h_help)
       
        # Menü-Separator
        mnu_help.AppendSeparator()
       
        # Info-Eintrag
        mnu_h_info = mnu_help.Append(
            id = -1, text = u"&Info...",
            help = u"Zeigt Informationen über das Programm an."
        )
        self.Bind(wx.EVT_MENU, self.show_info, mnu_h_info)
       
        # Hilfe-Menü an Menüleiste binden
        menubar.Append(mnu_help, u"&Hilfe")
       
        # Menüleiste an Frame binden
        self.SetMenuBar(menubar)
       
        # Panel erstellen (auf diesem Panel werden die Widgets angeordnet)
        panel = wx.Panel(self)
        
        # Innerhalb des Panels werden die Widgets mit Hilfe von Sizern angeordnet.
        # In diesem Fall mit einem FlexGridSizer. Dieser ordnet die Widgets in einer
        # Tabelle an, die sich bei der Breite und Höhe der einzelnen Zellen am
        # jeweils höchsten/breitesten Widget orientiert.
        fgrid_panel = wx.FlexGridSizer(cols = 2)
        
        # Damit die Felder in der zweiten Spalte gestreckt werden könne, muss
        # man das dem FlexGridSizer mitteilen.
        fgrid_panel.AddGrowableCol(1)
        
        # Damit das Notizfeld in der dritten Zeile gestreckt werden kann, muss
        # man das dem FlexGridSizer mitteilen.
        fgrid_panel.AddGrowableRow(2)
        
        # Der Sizer muss dem Panel zugewiesen werden, da das Panel ein Widget
        # ist, in das die anderen Widgets gelegt werden.
        panel.SetSizer(fgrid_panel)
        
        #
        # Vorname
        #
        
        # Vorname-Label erstellen (in das Panel)
        lab_first_name = wx.StaticText(parent = panel, label = u"Vorname:")
        
        # Position und Größe des Vorname-Labels vom Sizer verwalten lassen
        # "proportion = 0" bedeutet, dass das Widget vom Sizer nicht
        #     gestreckt werden soll. In welche Richtung gestreckt wird, hängt
        #     vom Sizertyp ab. In diesem Fall "vertikal".
        # "wx.ALIGN_CENTER_VERTICAL" bedeutet, dass das Widget im Zellbereich
        #     des Sizers horizontal zentriert werden soll.
        # "wx.ALL" gibt an, dass der über den Parameter "border" übergebene
        #     Abstand allen Seiten zugewiesen werden kann. Es gäbe auch noch
        #     die Werte "wx.LEFT", "wx.RIGHT", usw.
        fgrid_panel.Add(
            item = lab_first_name, proportion = 0, 
            flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5
        )
        
        # Vorname-Textfeld erstellen (in das Panel)
        txt_first_name = wx.TextCtrl(parent = panel)
        
        # Position und Größe des Vornamen-Textfeldes vom Sizer verwalten lassen
        # wx.EXPAND gibt an, dass das Widget entgegengesetzt der Proportionalrichtung
        #     des Sizers gestreckt werden soll. Die Proportionalrichtung des
        #     FlexGridSizers ist "vertikal". Also gibt die Konstante wx.EXPAND
        #     an, dass das Widget "horizontal" gestreckt werden soll.
        fgrid_panel.Add(
            item = txt_first_name, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5
        )
        
        #
        # Nachname (diesmal ohne große Erklärungen)
        #
        
        # Nachname-Label erstellen (in das Panel)
        lab_last_name = wx.StaticText(parent = panel, label = u"Nachname:")
        fgrid_panel.Add(
            item = lab_last_name, proportion = 0,
            flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5
        )
        
        # Nachname-Textfeld erstellen (in das Panel)
        txt_last_name = wx.TextCtrl(parent = panel)
        fgrid_panel.Add(
            item = txt_last_name, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5
        )
        
        #
        # Notiz
        #
        
        # Notiz-Label erstellen (in das Panel)
        lab_notice = wx.StaticText(parent = panel, label = u"Notiz:")
        fgrid_panel.Add(
            item = lab_notice, proportion = 0,
            flag = wx.ALIGN_TOP | wx.ALL, border = 5
        )
        
        # Notiz-Textfeld erstellen (in das Panel)
        # Dieses Notizfeld wird den restlichen, vertikalen Platz in Anspruch
        # nehmen. Achte auf den Parameter "proportion".
        txt_notice = wx.TextCtrl(
            parent = panel, style = wx.TE_MULTILINE | wx.TE_WORDWRAP
        )
        fgrid_panel.Add(
            item = txt_notice, proportion = 1,
            flag = wx.ALL | wx.EXPAND, border = 5
        )
        
        # Damit auf die Textfelder auch von Instanzmethoden aus zugegriffen
        # werden kann, werden die benötigten Felder an "self" gebunden.
        # Das kann natürlich auch sofort nach dem Erstellen eines Widgets 
        # erfolgen.
        self.txt_first_name = txt_first_name
        self.txt_last_name = txt_last_name
        self.txt_notice = txt_notice
        
        # Statusleiste erstellen und zuweisen
        self.CreateStatusBar()
       
        # Zentrieren und anzeigen
        self.Center()
    
    
    def close_frame(self, event = None):
        """
        Schließt dieses Fenster
        """
       
        self.Close()


    def show_help(self, event = None):
        """
        Zeigt die Hilfe an.
        """
       
        wx.MessageBox(
            message = u"Hier könnte ein Hilfetext stehen...",
            caption = u"Hilfe",
            style = wx.OK | wx.CENTER | wx.ICON_INFORMATION,
        )


    def show_info(self, event = None):
        """
        Zeigt Programminformationen an.
        """
       
        wx.MessageBox(
            message = u"Info, Info, Info...",
            caption = u"Info",
            style = wx.OK | wx.CENTER | wx.ICON_INFORMATION,
        )
    
    
    def show_values(self, event = None):
        """
        Liest die Werte der Textfelder aus und zeigt diese in einer 
        MessageBox an.
        """
        
        first_name = self.txt_first_name.GetValue()
        last_name = self.txt_last_name.GetValue()
        notice = self.txt_notice.GetValue()
        
        message = (
            u"Vorname: %s\n\n"
            u"Nachname: %s\n\n"
            u"Notiz: %s"
        ) % (first_name, last_name, notice)
        
        wx.MessageBox(
            message = message,
            caption = u"Werte",
            style = wx.OK | wx.CENTER | wx.ICON_INFORMATION
        )


if __name__ == "__main__":
    
    # Bei kleinen Anwendungen ist es nicht unbedingt nötig, eine eigene
    # App-Klasse zu verwenden. Bei größeren Anwendungen kann eine eigene
    # App-Klasse aber recht vorteilhaft sein, um z.B. globale Objekte zu
    # Verwalten oder um die einzelnen Fenster zu koordinieren.
    
    app = wx.PySimpleApp()
    frame = MyFrame()
    frame.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
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 5. April 2007, 18:30

Und so funktioniert es mit Unicode. Egal ob die Unicode-Version oder die ANSI-Version von wxPython installiert ist.

Zumindest fällt mir bis jetzt nichts besseres ein.

--> http://paste.pocoo.org/show/1335/

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Donnerstag 5. April 2007, 19:21

Ich habe heute ein kleines GUI mit wxGlade erstellt, und muss sagen, es war erstaunlich stressfrei. Kann es sein, dass sich die Codegenerierung, v.a. der Umgang mit Benutzercode, in Version 0.5 ziemlich verbessert hat?
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 5. April 2007, 19:37

birkenfeld hat geschrieben:Kann es sein, dass sich die Codegenerierung, v.a. der Umgang mit Benutzercode, in Version 0.5 ziemlich verbessert hat?
Hallo birkenfeld!

Ich weiß es nicht. Ich habe wxGlade nur einmal vor zwei/drei Jahren ausprobiert. Damals ist es mir ständig abgestürzt, noch bevor ich zu einem Ergebnis kahm.

Inzwischen bin ich so in die Verwendung von Sizern drinnen, dass ich allein mit Lesen des Quellcodes weiß, wie die Anwendung aussehen wird. Aussgenommen die Icons und Bilder natürlich. ;-)

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 5. April 2007, 20:53

gerold hat geschrieben:Inzwischen bin ich so in die Verwendung von Sizern drinnen, dass ich allein mit Lesen des Quellcodes weiß, wie die Anwendung aussehen wird. Aussgenommen die Icons und Bilder natürlich. ;-)
Ach, ich mag XPM, die sind im Quellcode auch lesbar :D
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 5. April 2007, 21:01

Leonidas hat geschrieben:Ach, ich mag XPM, die sind im Quellcode auch lesbar :D
:mrgreen:
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten