BoxSizer benimmt sich nicht wie erwartet.

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Benutzeravatar
C4S3
User
Beiträge: 292
Registriert: Donnerstag 21. September 2006, 10:07
Wohnort: Oberösterreich

Hallo liebe Leute!

Nachdem Gerold sich ja schon die Mühe gemacht hat und mir diverse Sizer wirklich ausführlich erklärt hat, habe ich beschlossen, mit diesen Dingen noch rumzuspielen, bis ich sie verstanden habe.

Jetzt ist es so:
Ich habe mir einen Frame gemacht, der ein Panel enthält. Auf dem Panel liegt ein BoxSizer.
Und wie mir erklärt wurde, habe ich dann Widgets (in diesem Fall 2 Buttons) erstellt, die ich beim Instanziieren auf dem Panel erzeugt habe und später dann dem Sizer hinzugefügt habe. Soweit funktioniert das auch alles, aber:

Sollten die Knöpfe, wenn sie nicht absolut positioniert sind, vom Sizer so angelegt werden, dass sie passen? Mein beiden Buttons scheinen beide auf x0, y0 zu liegen.

Über einen kleinen Hinweis würde ich mich freuen, danke!

Code: Alles auswählen

#!/usr/bin/env python

import wx

class MyFrame(wx.Frame):
	# Init the super Class
	def __init__(self):
		wx.Frame.__init__(self,
		None, -1, "Hi", 
		wx.DefaultPosition, 
		wx.DefaultSize)
		
		# place a panel in the frame
		panel = wx.Panel(self, -1)
		mainBox = wx.BoxSizer(wx.VERTICAL)
		mainBox.Add(panel, 1)
		
		# create 2 buttons and place it
		# to the panel and the sizer.
		button = wx.Button(panel, -1, "close")
		button2 = wx.Button(panel, -1, "Another Button")
		mainBox.Add(button, 0)
		mainBox.Add(button2, 0)
		
		# bind the button - event to a method
		button.Bind(wx.EVT_BUTTON, self.OnCloseButton)
		button2.Bind(wx.EVT_BUTTON, self.Message)
		
	def OnCloseButton(self, event):
		self.Close(True)
		# oder doch self.Destroy() ??
		
	def Message(self, event):
		wx.MessageBox("My message: 'HI!'", "Hello", wx.OK)
		
if __name__ == "__main__":
	app = wx.App(False)
	frame = MyFrame()
	frame.Show()
	app.MainLoop()
Gruß!
fred.reichbier
User
Beiträge: 155
Registriert: Freitag 29. Dezember 2006, 18:27

Hallo,

hast du evtl. ein self.SetSizer(mainBox) vergessen?

Gruß Fred
Benutzeravatar
C4S3
User
Beiträge: 292
Registriert: Donnerstag 21. September 2006, 10:07
Wohnort: Oberösterreich

Hm, ich weiß nicht so recht, um ehrlich zu sein...

Bisheriger Code sieht auf meiner Maschine so aus:

Bild


Wenn ich das mit self.SetSizer(mainBox) versuche, sieht es so aus:

Bild

Das sieht ja ganz komisch aus...
Gruß!
BlackJack

Ich kenne mich mit wx nicht so aus, aber Du packst ein Panel in den Sizer und dann zwei Buttons die aber gleichzeitig Kinder vom Panel sind? Das sieht IMHO komisch aus. Muss das Panel denn als Objekt in den Sizer!? Und nicht der Sizer irgendwie als "Layout-Dings" an das Panel!?
Benutzeravatar
C4S3
User
Beiträge: 292
Registriert: Donnerstag 21. September 2006, 10:07
Wohnort: Oberösterreich

Das ist es ja gerade.
In diesem Thread habe ich das schon angedeutet:
http://www.python-forum.de/topic-12184,15.html
case in besagtem Thread hat geschrieben:Und was mich an der Sache am meisten verwirrt und mir gleichzeitig auch vor Augen führt, dass ich das Konzept nicht verstanden habe:

Code: Alles auswählen

top_txt = wx.TextCtrl(panel, size = (-1, 100), style = wx.TE_MULTILINE)
vbox.Add(top_txt, 0, wx.EXPAND | wx.ALL, 3)
Ein Textcontrol, das als Parent das Panel hat und in der nächsten Zeile wird aber genau diese Objekt an die Vbox übergeben. Das verstehe icht nicht. Wie hängen dies zusammen? Sorgt die Box nicht dafür, dass das Panel vergrößert/verkleinert wird und mit ihm auch sein Inhalt?
Aber wenn ich richtig verstanden habe, was und wie Gerold es mir erklärt hat, so müsste es stimmen.
gerold in besagtem Thread hat geschrieben:Ein Widget muss auf einem Container liegen. Frames, Dialogs, Panels und noch so ein paar Objekte sind solche Container.

Sizer sind keine Container. Sizer sind unsichtbare "Helfer", die sich **nur** darum kümmern, dass die Widgets auf dem Container korrekt angeordnet werden.

Man kann einem Container einen Sizer zuweisen. Dieser Sizer ist dann nur für die Anordnung der Widgets auf diesem Container zuständig.

Code: Alles auswählen

panel = wx.Panel(parent = self)
vbox = wx.BoxSizer(wx.VERTICAL)
panel.SetSizer(vbox)
Wenn ich jetzt ein neues Widget erstelle, dann lege ich es schon beim Erstellen auf einen Container.

Code: Alles auswählen

txt = wx.TextCtrl(parent = panel)
Damit liegt das Widget schon auf dem Container, aber es ist noch nicht korrekt angeordnet. Dafür binde ich das neue Widget zusätzlich an einen Sizer.
Deswegen war ich ja der Meinung, dass es funktionieren sollte.

edit: Wenn ich mir die "wxPython in One Page" Seite anschaue, wird dies nicht viel anders gelöst:

Code: Alles auswählen

#!/usr/bin/python

# wxboxsizer.py

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, (-1, -1), wx.Size(250, 50))
        panel = wx.Panel(self, -1)
        box = wx.BoxSizer(wx.HORIZONTAL)
        box.Add(wx.Button(panel, -1, 'Button1'), 1 )
        box.Add(wx.Button(panel, -1, 'Button2'), 1 )
        box.Add(wx.Button(panel, -1, 'Button3'), 1 )
        panel.SetSizer(box)
        self.Centre()

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

app = MyApp(0)
app.MainLoop()
Ja, den "SetSizer()" habe ich vergessen, aber selbst, wenn ich mein Programm dahingehend umbaue, funktioniert es nicht.
Zuletzt geändert von C4S3 am Montag 15. Oktober 2007, 16:45, insgesamt 1-mal geändert.
Gruß!
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo C4S3!

@all wxPython-Interessierte: Bitte lest das Buch. Das sind nicht umsonst 30 Seiten, die sich nur um die Arbeit mit Sizern drehen. Ich kann das niemals alles in ein paar Sätzen erklären. Auch die Hintergründe, die in den 300 Seiten vorher erklärt werden, sind wichtig.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import wx

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


class MyFrame(wx.Frame):
    
    def __init__(self, parent = None, title = "Example"):
        wx.Frame.__init__(self, parent, -1, title)
        
        # Obligatorisches Panel -- muss sein.
        #        
        # Da das Panel das einzige Widget sein wird, welches **direkt** im
        # Frame liegt, wird dieses ganz automatisch auf volle Frame-Größe
        # aufgeblasen. Wenn also nur ein Widget im Frame ist, dann
        # hat dieses Widget immer die volle Größe und muss nicht extra von einem
        # Sizer verwaltet werden.
        panel = wx.Panel(self)
        
        # Vertikaler Box-Sizer -- alles was an diesen Sizer gebunden wird, wird
        # untereinander angeordnet
        vbox = wx.BoxSizer(wx.VERTICAL)
        
        # Der vertikale Box-Sizer "vbox" wird jetzt flächendeckend über das
        # Panel gelegt (unsichtbar).
        # Damit ist der Sizer jetzt gleich groß wie das Panel.
        panel.SetSizer(vbox)
        
        # Erster Button
        btn_erster = wx.Button(panel, label = "Erster Button")
        
        # Der Button wird jetzt an den Sizer gebunden (links angeordnet (=Standard) 
        # und mit 5 px Abstand)
        vbox.Add(btn_erster, proportion = 0, flag = wx.ALL, border =5)
        
        # Zweiter Button
        btn_zweiter = wx.Button(panel, label = "Zweiter Button")
        
        # Der Button wird jetzt an den Sizer gebunden (rechts angeordnet und mit 5 px Abstand)
        vbox.Add(btn_zweiter, 0, wx.ALIGN_RIGHT | wx.ALL, 5)
        
        # Dritter Button
        btn_dritter = wx.Button(panel, label = "Dritter Button")
        
        # Der Button wird jetzt an den Sizer gebunden (volle Breite, 5 px Abstand und
        # 1 als Proportion = Nimmt den gesamten restlichen Platz ein)
        vbox.Add(btn_dritter, 1, wx.EXPAND | wx.ALL, 5)


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


if __name__ == "__main__":
    main()
mfg
Gerold
:-)
Zuletzt geändert von gerold am Montag 15. Oktober 2007, 16:54, 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:

...und weil ich ein Haarspalter bin, muss um alle Widgets noch ein 5 px breiter Abstand, damit alle Abstände insgesamt 10 px sind. Und nicht nur die zwischen den Buttons.

Code: Alles auswählen

    def __init__(self, parent = None, title = "Example"):
        wx.Frame.__init__(self, parent, -1, title)
        
        panel = wx.Panel(self)
        
        vbox_border = wx.BoxSizer(wx.VERTICAL)
        panel.SetSizer(vbox_border)
        
        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox_border.Add(vbox, 1, wx.EXPAND | wx.ALL, 5)
        
        btn_erster = wx.Button(panel, label = "Erster Button")
        vbox.Add(btn_erster, 0, wx.ALIGN_LEFT | wx.ALL, 5)
        
        btn_zweiter = wx.Button(panel, label = "Zweiter Button")
        vbox.Add(btn_zweiter, 0, wx.ALIGN_RIGHT | wx.ALL, 5)
        
        btn_dritter = wx.Button(panel, label = "Dritter Button")
        vbox.Add(btn_dritter, 1, wx.EXPAND | wx.ALL, 5)
mfg
Gerold
:-)
Zuletzt geändert von gerold am Montag 15. Oktober 2007, 16:53, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
C4S3
User
Beiträge: 292
Registriert: Donnerstag 21. September 2006, 10:07
Wohnort: Oberösterreich

Danke Gerold. Gerade, als ich auf Absenden gedrückt habe, sah ich meinen Fehler. Hier nun der Code der so funktioniert, wie ich es ursprünglich wollte:

Code: Alles auswählen

#!/usr/bin/env python

import wx

class MyFrame(wx.Frame):
	# Init the super Class
	def __init__(self):
		wx.Frame.__init__(self,
		None, -1, "Hi", 
		wx.DefaultPosition, 
		wx.DefaultSize)
		
		# place a panel in the frame
		panel = wx.Panel(self, -1)
		mainBox = wx.BoxSizer(wx.HORIZONTAL)
		
		# create 2 buttons and place it
		# to the panel and the sizer.
		button = wx.Button(panel, -1, "close")
		button2 = wx.Button(panel, -1, "Another Button")
		mainBox.Add(button, 1)
		mainBox.Add(button2, 1)
		
		# bind the button - event to a method
		button.Bind(wx.EVT_BUTTON, self.OnCloseButton)
		button2.Bind(wx.EVT_BUTTON, self.Message)
		
		panel.SetSizer(mainBox)
		
	def OnCloseButton(self, event):
		self.Close(True)
		# oder doch self.Destroy() ??
		
	def Message(self, event):
		wx.MessageBox("My message: 'HI!'", "Hello", wx.OK)
		
if __name__ == "__main__":
	app = wx.App(False)
	frame = MyFrame()
	frame.Show()
	app.MainLoop()
Der Grund war folgender: ich habe zu voreilig gehandelt und mit "self.SetSizer(mainBox)" den Sizer offenbar an den Frame binden wollen, anstelle des Panels. Ich habe sicher 10 mal drüber gelesen.
Mit "panel.SetSizer(mainBox)" funktioniert es natürlich. :oops:

Entschuldigung, ich wollte eure Zeit nicht verschwenden...
Gruß!
fanus
User
Beiträge: 46
Registriert: Dienstag 13. November 2007, 09:53

Hallo liebe Leute,

der unten stehende Code wurde mit wxDesigner generiert und würde gerne wissen,
wie ich hier meine Panel/Sizer setzen muss, damit ich kein so sehr dunkelnes Hintergrund bekomme...

vielen dank :)

LG,
fanus

Code: Alles auswählen

import wx

from Test_wdr import *


# WDR: classes

class MyFrame(wx.Frame): 
    # Init the super Class 
    def __init__(self): 
        wx.Frame.__init__(self, parent, -1, "help", wx.DefaultPosition, wx.DefaultSize)
        
        
        self.TestFunc()
    def TestFunc( parent, call_fit = True, set_sizer = True ):
        item0 = wx.FlexGridSizer( 0, 2, 5, 5 )
        
        item1 = wx.StaticText( parent, ID_TEXT, "Name", wx.DefaultPosition, wx.DefaultSize, 0 )
        item0.Add( item1, 0, wx.ALL, 5 )

        item2 = wx.Choice( parent, ID_CHOICE, wx.DefaultPosition, [100,-1], ["ChoiceItem"] , 0 )
        item0.Add( item2, 0, wx.ALL, 5 )

        item3 = wx.StaticText( parent, ID_TEXT, "Vorname", wx.DefaultPosition, wx.DefaultSize, 0 )
        item0.Add( item3, 0, wx.ALL, 5 )

        item4 = wx.Choice( parent, ID_CHOICE, wx.DefaultPosition, [100,-1], ["ChoiceItem"] , 0 )
        item0.Add( item4, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )

        if set_sizer == True:
            parent.SetSizer( item0 )
            if call_fit == True:
                item0.SetSizeHints( parent )
        
        return item0
    
    
if __name__ == "__main__": 
    app = wx.App(True) 
    frame = MyFrame() 
    frame.Show() 
    app.MainLoop()
Benutzeravatar
C4S3
User
Beiträge: 292
Registriert: Donnerstag 21. September 2006, 10:07
Wohnort: Oberösterreich

Ist AFAIK ein bekanntes Windowsproblem. Du hast nicht zufällig auf ein Panel vergessen, oder?
Gruß!
Antworten