Mit Splittern arbeiten

Plattformunabhängige GUIs mit wxWidgets.
Antworten
alan
User
Beiträge: 81
Registriert: Dienstag 10. April 2007, 11:30

Montag 27. August 2007, 10:06

Ich frag hier mal einfach weiter und erstell kein neues Posting:

Was ich machen will: flexibles dreigeteiltes Fenster

Code: Alles auswählen

--------------------------------
|         |                    |
|         |                    |
|         |                    |
|         ----------------------
|         |                    |
|         |                    |
|         |                    |
--------------------------------
Ich wollte das eigentlich mit MultiSplitterWindow umsetzen, hab aber schnell gemerkt, dass das nur eine orientation (vertikal oder horizontal) unterstützt.

Habe es jetzt mit zwei einzelnen wx.SplitterWindow() versucht. Der Code wird zwar ohne Fehler gestartet, aber das horizontale Splitting funktioniert nicht und schaut sehr komisch aus (ist schwer zu beschreiben, am besten selbst probieren).

Code: Alles auswählen

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title)

        Vsplitter = wx.SplitterWindow(self, -1)
        panel1 = wx.Panel(Vsplitter, -1)
        panel1.SetBackgroundColour(wx.LIGHT_GREY)
        panel2 = wx.Panel(Vsplitter, -1)
        panel2.SetBackgroundColour(wx.WHITE)
        Vsplitter.SplitVertically(panel1, panel2)

        Hsplitter = wx.SplitterWindow(panel2, -1)
        panel3 = wx.Panel(Hsplitter, -1)
        panel4 = wx.Panel(Hsplitter, -1)
        panel4.SetBackgroundColour(wx.LIGHT_GREY)
        Hsplitter.SplitHorizontally(panel3, panel4)

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, -1, 'splitting.py')
        self.frame.Show(True)
        return True

if __name__ == '__main__':
    app = MyApp()
    app.MainLoop()
Vielleicht bin ich aber auch völlig auf dem Holzweg.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Montag 27. August 2007, 13:31

alan hat geschrieben:aber das horizontale Splitting funktioniert nicht
Hallo alan!

Du musst auch bei Splittern mit Sizern arbeiten. Das ist nicht einfach zu durchschauen, ich weiß. Deshalb hier ein kleines (kommentiertes) Beispiel:

Code: Alles auswählen

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

import wx


class MyFrame(wx.Frame):
    def __init__(self, parent = None, title = "splitting.py"):
        wx.Frame.__init__(self, parent, -1, title)
        
        # Oberster Splitter (horizontal)
        hsplitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
        
        # Linkes Panel (grün)
        panel1 = wx.Panel(hsplitter)
        panel1.SetBackgroundColour(wx.GREEN)
        
        # Rechtes Panel (nur als Container, keine Farbe)
        panel2 = wx.Panel(hsplitter)
        
        # Sizer, der sich darum kümmert, dass der "hsplitter" sich auf die volle
        # Fläche des Panels breit macht.
        vbox_panel2 = wx.BoxSizer(wx.VERTICAL)
        panel2.SetSizer(vbox_panel2)
        
        # Da jetzt die beiden Panel existieren, können diese jetzt als Kinder
        # im Splitter verwendet werden.
        hsplitter.SplitHorizontally(panel1, panel2)
        
        # Vertikaler Splitter, der in das "panel2" gelegt wird
        vsplitter = wx.SplitterWindow(panel2, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
        vbox_panel2.Add(vsplitter, 1, wx.EXPAND)
        
        # Erstes Panel im vertikalen Splitter (rot)
        panel3 = wx.Panel(vsplitter)
        panel3.SetBackgroundColour(wx.RED)
        
        # Zweites Panel im vertikalen Splitter (blau)
        panel4 = wx.Panel(vsplitter)
        panel4.SetBackgroundColour(wx.BLUE)
        
        # Da jetzt die beiden Panel für den vertikalen Splitter existieren, 
        # können diese jetzt als Kinder im Splitter verwendet werden.
        vsplitter.SplitVertically(panel3, panel4)


class MyApp(wx.PySimpleApp):
    def OnInit(self):
        myframe = MyFrame()
        myframe.Show(True)
        return True


if __name__ == '__main__':
    app = MyApp()
    app.MainLoop()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
alan
User
Beiträge: 81
Registriert: Dienstag 10. April 2007, 11:30

Montag 27. August 2007, 15:46

Danke, das hat mich weitergebracht. Ich frag mich zwar, ob ich da jemals von alleine draufgekommen wäre...

Ich würde das gerne verstehen: Wieso funktioniert mein obiger Code, wenn man in MyFrame ab Zeile 14 den zweiten Splitter + panels löscht?

Code: Alles auswählen

class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title)

        Vsplitter = wx.SplitterWindow(self, -1)
        panel1 = wx.Panel(Vsplitter, -1)
        panel1.SetBackgroundColour(wx.LIGHT_GREY)
        panel2 = wx.Panel(Vsplitter, -1)
        panel2.SetBackgroundColour(wx.WHITE)
        Vsplitter.SplitVertically(panel1, panel2)
Dann wird "Vsplitter" mit maximaler Länge dargestellt, obwohl kein Sizer verwendet wurde.

Bin mir sicher, dass da Logik dahinter ist, nur kapiere ich die (noch) nicht.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Montag 27. August 2007, 16:03

alan hat geschrieben:Wieso funktioniert mein obiger Code, wenn man in MyFrame ab Zeile 14 den zweiten Splitter + panels löscht?
[...]
Dann wird "Vsplitter" mit maximaler Länge dargestellt, obwohl kein Sizer verwendet wurde.
Hallo alan!

Das ist eine Ausnahme!

Wenn in einem Frame nur ein einziges Objekt liegt, dann wird dieses Objekt automatisch auf die volle Framegröße vergrößert.

Da in den allermeisten Fällen ein Panel als Hauptcontainer innerhalb des Frames liegt, wird dieses Panel sofort gleich groß wie das Frame (genauer gesagt wie die ClientSize). Man spart sich somit, bei jedem Programm/Fenster den Sizer für das obligatorische Panel und der Programmierer spart sich die zugehörige Tipparbeit.

Sobald noch ein zweites Objekt in das Frame gelegt wird, ist dieser Effekt weg.

EDIT:

Wie man in diesem Beispiel sieht, wird der Button auf die volle ClientSize aufgeblasen:
Bild

Code: Alles auswählen

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

import wx

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


class MyFrame(wx.Frame):
    
    def __init__(
        self, parent = None, title = "Example", size = wx.Size(550, 420)
    ):
        wx.Frame.__init__(self, parent, -1, title, size = size)
        button = wx.Button(self, label = "Ich bin der Button")


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


if __name__ == "__main__":
    main()
In diesem Beispiel sieht man sofort, dass der Effekt weg ist, sobald ein zweiter Button in das Frame gelegt wird:
Bild

Code: Alles auswählen

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

import wx

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


class MyFrame(wx.Frame):
    
    def __init__(
        self, parent = None, title = "Example", size = wx.Size(550, 420)
    ):
        wx.Frame.__init__(self, parent, -1, title, size = size)
        button1 = wx.Button(self, label = "Ich bin der erste Button")
        button2 = wx.Button(self, label = "Ich bin der zweite Button..........")
        self.Center()


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


if __name__ == "__main__":
    main()
EDIT2:
Und so funktioniert es mit mehreren Buttons richtig:
Bild

Code: Alles auswählen

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

import wx

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


class MyFrame(wx.Frame):
    
    def __init__(
        self, parent = None, title = "Example", size = wx.Size(550, 420)
    ):
        wx.Frame.__init__(self, parent, -1, title, size = size)
        
        # Diese Panel füllt automatisch den kompletten Platz aus, da es das einzige
        # Objekt innerhalb des Frames ist. !!! Lege nie ein Widget direkt in ein
        # Frame. Lege die Widgets immer auf ein Panel. Damit wird sicher gestellt,
        # dass sich die Widgets in jedem Betriebssystem wie gewohnt verhalten. Z.B. 
        # kann man dann mit der TAB-Taste von einem Widget zum nächsten springen.
        panel = wx.Panel(self)
        
        # Äußere Box
        vbox_outer = wx.BoxSizer(wx.VERTICAL)
        panel.SetSizer(vbox_outer)
        
        # Innere Box mit 5 px Abstand zum Rand
        vbox_inner = wx.BoxSizer(wx.VERTICAL)
        vbox_outer.Add(vbox_inner, 1, wx.ALL | wx.EXPAND, 5)
        
        # Button1
        button1 = wx.Button(panel, label = "Ich bin der erste Button")
        vbox_inner.Add(button1, 1, wx.ALL | wx.EXPAND, 5)
        
        # Button2
        button2 = wx.Button(panel, label = "Ich bin der zweite Button..........")
        vbox_inner.Add(button2, 1, wx.ALL | wx.EXPAND, 5)
        
        self.Center()


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


if __name__ == "__main__":
    main()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
alan
User
Beiträge: 81
Registriert: Dienstag 10. April 2007, 11:30

Montag 27. August 2007, 17:10

Wow, danke Dir für diese super Erklärung. :D
Antworten