Komplette Größe einer Notebook-Seite bestimmen

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Ich habe die Frage schon unter einem anderen Thema gestellt. Da sie dort als Nachtrag nach der eigentlichen Lösung erscheint, geht sie möglicherweise etwas unter. Deshalb möchte ich sie als eigenes Thema nochmals stellen:
Kann man die Größe eines Panels in einem Notebook einschließlich der "Reiter" am oberen Rand bestimmen, um dann die Größe des Fensters, das das Notebook enthält, einfach dynamisch festzulegen? In meiner Lösung unter http://www.python-forum.de/topic-6470.h ... 12b5f6bbb5 mußte ich für eine näherungsweise Lösung etwas tricksen.
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

HWK hat geschrieben:Ich habe die Frage schon unter einem anderen Thema gestellt. Da sie dort als Nachtrag nach der eigentlichen Lösung erscheint, geht sie möglicherweise etwas unter. Deshalb möchte ich sie als eigenes Thema nochmals stellen:
Kann man die Größe eines Panels in einem Notebook einschließlich der "Reiter" am oberen Rand bestimmen, um dann die Größe des Fensters, das das Notebook enthält, einfach dynamisch festzulegen? In meiner Lösung unter http://www.python-forum.de/topic-6470.h ... 12b5f6bbb5 mußte ich für eine näherungsweise Lösung etwas tricksen.

Wenn ich <notebook>.GetSize() aufrufe, dann bekomme ich (als zweiten Wert des Tupels) ziemlich genau die Höhe des Fensters mit den Tabs heraus.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Bei mir liefert notebook.GetSize() leider immer (1, 1).
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

HWK hat geschrieben:Bei mir liefert notebook.GetSize() leider immer (1, 1).
Hi HWK!

Das kommt immer darauf an, ob du ``GetSize()`` während des Layout-Vorgangs aufrufst. Zuerst, glaube ich, wird alles zurück gesetzt und von hinten nach vorne neu resized. Deshalb kann es sein, dass du zu gewissen Zeitpunkten nur Blödsinn von dieser Methode zurück bekommst.

Allerdings habe ich ein wenig experimentiert. Das hier ist das Ergebnis:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import wx 


class MyFrame(wx.Frame):
    """
    Hauptframe
    """
    
    def __init__(self, parent = None, id = -1, title = "Hauptframe"):
        """
        Initialisiert das Frame und baut es auf
        """
        
        wx.Frame.__init__(self, parent, id, title)
        
        # Hauptpanel
        panel = wx.Panel(self)
        
        # Hauptsizer
        vbox = wx.BoxSizer(wx.VERTICAL)
        panel.SetSizer(vbox)
        
        # Kurzer Text
        lab = wx.StaticText(panel, -1, "Servus aus Oberhofen im Inntal.")
        vbox.Add(lab, 0, wx.ALL, 10)
        
        # Notebook
        notebook = wx.Notebook(panel)
        vbox.Add(notebook, 1, wx.ALL | wx.EXPAND, 5)
        
        # Panels für das Notebook
        notebook_panel1 = Panel1(notebook)
        notebook.AddPage(notebook_panel1, "Panel 1")
        
        notebook_panel2 = Panel2(notebook)
        notebook.AddPage(notebook_panel2, "Panel 2")
        
        # Größe anpassen
        panel.Fit()
        self.SetClientSize(panel.GetSizeTuple())
        self.SetSizeHintsSz(self.GetSizeTuple())
        
        # Zentrieren und anzeigen
        if parent:
            self.CenterOnParent(parent)
        else:
            self.Center()
        self.Show()


class Panel1(wx.Panel):
    """
    Panel1
    """
    
    def __init__(self, parent = None):
        """
        Initialisiert das Panel
        """
        
        wx.Panel.__init__(self, parent)
        
        self.SetBackgroundColour("blue")
        
        vbox = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(vbox)
        
        for i in range(7):
            vbox.Add(wx.Button(self, -1, "Button %i" % i), 0, wx.ALL, 8)


class Panel2(wx.Panel):
    """
    Panel2
    """
    
    def __init__(self, parent):
        """
        Initialisiert das Panel
        """
        
        wx.Panel.__init__(self, parent)
        
        self.SetBackgroundColour("red")
        
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        self.SetSizer(hbox)
        
        for i in range(5):
            hbox.Add(wx.Button(self, -1, "Button %i" % i), 0, wx.ALL, 8)


def main():
    """
    Hauptprozedur
    """
    
    app = wx.PySimpleApp()
    myframe = MyFrame()
    app.MainLoop()


if __name__ == "__main__":
    main()
Bild

Bild

Du wolltest doch, dass sich die Fenstergröße an die Größe des Notebooks anpasst. Das passiert in diesem Code bei Zeile 40.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Danke!
Ich hab's probiert. Es funktioniert. Das entscheidende ist der Sizer. Der sorgt dafür, dass die Größen passen. Bei mir sieht's so aus:

Code: Alles auswählen

class MyApp(wx.App):
    def OnInit(self):
        self.frame = wx.Frame(None, -1, 'Formeln')
        panel = wx.Panel(self.frame)
        vbox = wx.BoxSizer()
        panel.SetSizer(vbox)
        nb = my_notebook(panel)
        vbox.Add(nb, 1, wx.ALL | wx.EXPAND)
        vbox.Fit(panel)
        self.frame.SetClientSize(panel.GetSize())
        self.frame.SetMinSize(self.frame.GetSize())
        nb.labels[nb.data[0][0]][0].SetFocus()
        self.SetTopWindow(nb)
        self.frame.Show()
        self.Bind(wx.EVT_KEY_DOWN, self.on_esc)
        return True
MfG
HWK
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

HWK hat geschrieben:

Code: Alles auswählen

class MyApp(wx.App):
    def OnInit(self):
        self.frame = wx.Frame(None, -1, 'Formeln')
        panel = wx.Panel(self.frame)
        vbox = wx.BoxSizer()
        panel.SetSizer(vbox)
        nb = my_notebook(panel)
        vbox.Add(nb, 1, wx.ALL | wx.EXPAND)
        vbox.Fit(panel)
        self.frame.SetClientSize(panel.GetSize())
        self.frame.SetMinSize(self.frame.GetSize())
        nb.labels[nb.data[0][0]][0].SetFocus()
        self.SetTopWindow(nb)
        self.frame.Show()
        self.Bind(wx.EVT_KEY_DOWN, self.on_esc)
        return True
MfG
HWK
Hi HWK!

Aus diesem (nicht aufrufbaren) Code-Fetzen finde ich jetzt nicht wirklich heraus, was dein Problem ist.
Allerdings stelle ich ein paar Probleme fest, die das Entwickeln komplexer Anwendungen extrem behindern. Ich gehe einfach mal darauf ein.

- Ein Frame ist schon ein ziemlich großes Gebilde. Eine eigene Klasse dafür wäre schon angebracht.

- Es hat sich bei mir bewährt, ein Notebook einfach nur Notebook sein zu lassen und nicht das Notebook als Klasse zu definieren, sondern die Panel, die im Notebook angezeigt werden.

- Ein Notebook kann kein TopWindow werden. Außerdem braucht man diese Anweisung ``SetTopWindow()`` sowiso nicht, da das erste Frame der Applikation automatisch das *Top-Window*, also das Hauptfenster wird.

- Du bindest irgendeine ``on_esc``-Methode an das Ereignis ``wx.EVT_KEY_DOWN`` der gesamten Anwendung. Damit wird der Eventhandler ``on_esc`` nicht nur für den erste Frame, sondern für alle Frames, die deine Anwendung hat, aufgerufen. Wenn das nicht gewollt ist, dann würde ich wirklich mal eine Klasse für den Frame machen und den Eventhandler ``on_esc`` in diese Klasse stellen und auch nur dort an den Frame binden.

Wie wäre es mit ein wenig ausführbaren Code? Dann könnte man ein wenig damit experimentieren.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Danke für den Kommentar:
Ich habe aber durch Deine Hilfe kein Problem mehr, wie ich bereits beim letzten Mal mitgeteilt habe. Durch die durch Deinen Hinweis notwendig gewordenen Veränderungen ist das Frame deutlich größer geworden. Zum Ausprobieren habe ich mir aber noch nicht die Mühe gemacht, es in eine eigene Klasse zu packen.
Notebook als eigene Klasse wird im wxPython-Demo auch so gemacht.
Der Hinweis mit SetTopWindow ist hilfreich.
Die on_esc-Bindung ist so gewünscht, um überall das Programm, das übrigens nur diesen einen Frame besitzt, mit ESC beenden zu können.
Danke
HWK
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hi HWK!

Das freut mich. :-)

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

HWK hat geschrieben:Bei mir liefert notebook.GetSize() leider immer (1, 1).
Wie Gerold bereits gesagt, ist der richtige Wert erst dann vorhanden, wenn
der Layout Mechanismus abgeschlossen ist.
Für diese Fälle kann man trotzdem (wie ich es hin und wieder mache) mit
wx.CallAfter die Dimensionen ermitteln.
Also wx.CallAfter (Funktion, parameter1, parameter2) z.B.

und in Funktion kann dann z.B. stehen:
self.nbheight = self.GetSize()[1]
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Francesco, die Idee ist gut. Aber egal, wo ich wx.CallAfter aufgerufen habe, ich habe nie die richtige Größe des Notebooks erhalten. Schade eigentlich. Es klingt viel logischer als Gerolds Variante.
Antworten