wx.aui.AuiManager (Folge-Thread)

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

Hands Thread wx.aui AUI_MDI und AUI_DockingWindowMgr integrieren? ist wohl wieder durch seinen extrem langen Source-Code blockiert. Ich finde es aber trotzdem interessant. Deshalb mache ich einen neuen Thread auf.
Die Lösung scheint zu sein, dass es sich nicht um AUI_MDI, sonder um ein AuiNotebook handelt. Ich glaube, folgendes Beispiel kommt Hands Vorstellungen schon recht nahe:

Code: Alles auswählen

import wx
import wx.aui


text = """\
Hello!
Welcome to this little demo of draggable tabs using the wx.aui module.
To try it out, drag a tab from the top of the window all the way to the bottom. 
After releasing the mouse, the tab will dock at the hinted position. 
Then try it again with the remaining tabs in various other positions.
Finally, try dragging a tab to an existing tab ctrl. 
You'll soon see that very complex tab layouts may be achieved.
"""


class TestPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)

        self.nb = wx.aui.AuiNotebook(self)
        page = wx.TextCtrl(self.nb, -1, text, style=wx.TE_MULTILINE)
        self.nb.AddPage(page, "Welcome")

        for num in range(1, 5):
            page = wx.TextCtrl(self.nb, -1, "This is page %d" % num ,
                               style=wx.TE_MULTILINE)
            self.nb.AddPage(page, "Tab Number %d" % num)
            
        sizer = wx.BoxSizer()
        sizer.Add(self.nb, 1, wx.EXPAND)
        self.SetSizer(sizer)


class MyFrame(wx.Frame):
    def __init__(self, parent, id=-1, title='wx.aui Test',
                 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
        wx.Frame.__init__(self, parent, id, title, (0,0), size, style)

        self._mgr = wx.aui.AuiManager(self)

        # create several text controls
        text1 = wx.TextCtrl(self, -1, 'Pane 1 - sample text',
                            wx.DefaultPosition, wx.Size(200,150),
                            wx.NO_BORDER | wx.TE_MULTILINE)

        text2 = wx.TextCtrl(self, -1, 'Pane 2 - sample text',
                            wx.DefaultPosition, wx.Size(200,150),
                            wx.NO_BORDER | wx.TE_MULTILINE)

        notebook = TestPanel(self)

        # add the panes to the manager
        self._mgr.AddPane(text1, wx.LEFT, 'Pane Number One')
        self._mgr.AddPane(text2, wx.BOTTOM, 'Pane Number Two')
        self._mgr.AddPane(notebook, wx.CENTER)

        # tell the manager to 'commit' all the changes just made
        self._mgr.Update()

        self.Bind(wx.EVT_CLOSE, self.OnClose)


    def OnClose(self, event):
        # deinitialize the frame manager
        self._mgr.UnInit()
        # delete the frame
        self.Destroy()


app = wx.App(0)
frame = MyFrame(None)
frame.Show()
app.MainLoop()
MfG
HWK
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Da haben wir beide den gleichen Gedanken gehabt ;)

http://www.python-forum.de/post-60420.html#60420
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Hallo, Sape!
Du hast

Code: Alles auswählen

if __name__ == '__main__':
    main()
vergessen.
MfG
HWK
Hand
User
Beiträge: 65
Registriert: Sonntag 28. Januar 2007, 14:28

Hey Super, danke! :)

Genauso hatte ich mir das vorgestellt, jetzt nur noch meine Frage wo
ist denn eigentlich dann der Unterschid zu einem AuiMDI?
Optisch sehen beide ja gleich aus.

Und eine Doku zu dem ganze giebts wohl nicht?
Zumindest hab ich weder bei wxwidgets noch bei wxpython was erklärendes gefunden?
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

sape hat geschrieben:Die Lösung für dein Problem heißt ``wx.aui.AuiNotebook`` das ein Art "Panel" und kein Frame ist.
MfG
HWK
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Hand hat geschrieben:Hey Super, danke! :)

Genauso hatte ich mir das vorgestellt, jetzt nur noch meine Frage wo
ist denn eigentlich dann der Unterschid zu einem AuiMDI?
Optisch sehen beide ja gleich aus.
Der GUI Teil von wx besteht aus zwei verschiedenen Basen:

http://wxpython.wxcommunity.com/docs/ap ... class.html
1. Das eine ist das sogenannte Frame und seht an "oberster"[1] Hierarchie. Etwas was ein Frame ist, wird grundsätzlich als eigenständiges Fenster angezeigt, und lässt sich nicht in andere Fenster einbetten wie z.B. ein ``wx.Panel``, ``wx.TextCtrl``, etc...

[1]
``wx.Frame`` hat als Base ``TopLevelWindow`` (Das wiederum ``Window`` als Base hat, das bei den GUI Teile an der oberster Hierarchie ist.). So weit ich das verstanden habe ist das ``TopLevelWindow`` dafür zuständig um ein Widget als eigenständiges Fenster zu definieren. Ein widget wie z.B. ``wxFrame`` das von ``TopLevelWindow`` erbt und dann einen Konstruktor definiert (``TopLevelWindow`` hat keinen), wird dann als eigenständiges Fenster angezeigt.

Wenn wir es ganz genau nehmen, dann ist ``TopLevelWindow`` (wenn es einen Konstruktor (__init__) und eine Create-Methode defineiren würde) ausreichend ;)

Hier mal ein Beispiel, was für einen primitiven Frame reichen würde:

Code: Alles auswählen

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

import wx
import wx._windows
from wx._windows import _windows_
wx.SetDefaultPyEncoding("utf-8")


class PrimitiveFrame(wx.TopLevelWindow):
    def __init__(self, *args, **kwargs): 
        _windows_.Frame_swiginit(self,_windows_.new_Frame(*args, **kwargs))
        self._setOORInfo(self)

    def Create(*args, **kwargs):
        return _windows_.Frame_Create(*args, **kwargs)


def main():
    app = wx.PySimpleApp()
    mf = PrimitiveFrame(None)
    mf.Show()
    app.MainLoop()
 
if __name__ == "__main__":
    main()
Wie man sehen kann ist das ``TopLevelWindow`` tatsächlich dafür zuständig, um ein Widget als eigenständiges Fenster zu definieren.

Es ist nicht empfohlen sich eigene Frame-Typen zu definieren, da man da auf private Interna (ebene Namen die mit _ oder __ beginnen) zurückgreifen muss, die sich in späteren Versionen von wx wider ändern können! Das obere Beispiel dient nur der Veranschaulichung und damit ich denn zweck von ``TopLevelWindow`` darstellen kann!



2. Ein Panel (Etwas das ``wx.Window in seiner Hierarchie hat aber kein ``TopLevelWindow``) ist nicht als eigenständiges Fenster geeignet und wird nur verwendet um es in einem Frame "einzubetten".

http://wxpython.wxcommunity.com/docs/ap ... class.html

Das es nicht geht kann man daran sehen:

Code: Alles auswählen

# ...
class TestPanel(wx.Panel):
    def __init__(self, *args, **kwargs):
        wx.Panel.__init__(self, *args, **kwargs)

def main():
    app = wx.PySimpleApp()
    mf = TestPanel(None)
    mf.Show()
    app.MainLoop()
 
if __name__ == "__main__":
    main()

# can't create wxWindow without parent
Ein einbetbares Widget erwartet immer einen Parent, das entweder ein Frame sein kann oder ein anderes Widget das die oberste Base ``wx.Window`` hat.


So, wie bereits erwähnt hat ``wxPanel`` ``wx.Window`` als Base und kein ``TopLevelWindow``.
Schauen wir mal wie wir aus ``wx.Window`` ein eigenen Paneltyp definieren:

Code: Alles auswählen

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

import wx
import wx._windows
from wx._windows import _windows_
wx.SetDefaultPyEncoding("utf-8")


class PrimitivePanel(wx.Window):
    def __init__(self, *args, **kwargs):
        wx.Window.__init__(self, *args, **kwargs)
        
class PrimitiveFrame(wx.TopLevelWindow):
    def __init__(self, *args, **kwargs): 
        _windows_.Frame_swiginit(self,_windows_.new_Frame(*args, **kwargs))
        self._setOORInfo(self)
        
        my_panel = PrimitivePanel(parent=self, id=-1, name='PrimitivePanel')
        my_panel.SetBackgroundColour((150,150,100))
        
    def Create(*args, **kwargs):
        return _windows_.Frame_Create(*args, **kwargs)


def main():
    app = wx.PySimpleApp()
    mf = PrimitiveFrame(None)
    mf.Show()
    app.MainLoop()
 
if __name__ == "__main__":
    main()
Wie man sieht funktioniert es.

Auch hier empfehle ich nicht von ``wxWindow`` zu erben sondern direkt von ``wx.Panel`` aus dem Grund, das `wx.Panel`` par nützliche Methoden mitbringt.


Nun sollte der unterschied zwischen einen "Frame" und "Panel" klar geworden sein. -- Als Frame bezeichnen wir(?) ein eigenständiges Fenster, und als Panel(?) etwas das man in einem Fenster einbetten kann, wie z.B. ein ``wxTextCtrl``. das eben auch `wx.Window`` als Base und kein ``TopLevelWindow`` dazwischen hat. €: Auf Events (z.B. Keyevents) gehe ich mal hier nicht ein, das es den Rahmen sprengen würde.


Zusammengefast:
1. Jedes Widget das in der Hierarchie ein ``wx.Window`` und ein``TopLevelWindow`` dazwischen hat, wird automatisch zu einem eigenständigen Fenster definiert, und lässt sich somit nicht in einem anderen Fenster einbetten.
2. Jedes Widget das ein ``wx.Window`` und kein ``TopLevelWindow`` hat, ist etwas das man nur in einem Fenster oder einem anderen "Panel" einbetten kann.
3. Mit wx.aui wird das ganz ein wenig konfus, da man "Panels" abdocken kann und sie dann wie Frames wirken. Davon bitte nicht irritieren lassen.



Nach der ganzen Theorie die Antwort zu deiner frage:
Der unterschied zwischen ``wx.aui.AuiMDIParentFrame`` und ``wx.aui.AuiNotebook`` ist der, das ``wx.aui.AuiNotebook`` kein ``TopLevelWindow`` in seiner Hierarchie dazwischen hat und somit zu etwas einbettbaren wird. Das ``wx.aui.AuiMDIParentFrame`` hat (denke ich mal da keine Doku dazu vorhanden) ein ``TopLevelWindow`` dazwischen (oder etwas äquivalentes) und kann nur als eigenständiges Fenster fungieren!

Aber, man kann in einer Instanz von ``wx.aui.AuiManager`` auch Frames hinzufügen, aber sie werden nicht eingebettet und schweben frei rum, daher Sinnfrei...Davon wird aber strengstens abgeraten, da es (im Fall von ``wx.aui.AuiMDIParentFrame``) zum Absturz der Applikation kommen kann!

lg
Antworten