Our next example will be more complex and will show you how to change a few notebook settings.

Listing 5

import panelOne, panelTwo, panelThree
import wx
import wx.lib.agw.aui as aui
 
ID_NotebookArtGloss = 0
ID_NotebookArtSimple = 1
ID_NotebookArtVC71 = 2
ID_NotebookArtFF2 = 3
ID_NotebookArtVC8 = 4
ID_NotebookArtChrome = 5
 
########################################################################
class AUIManager(aui.AuiManager):
    """
    AUI Manager class
    """
 
    #----------------------------------------------------------------------
    def __init__(self, managed_window):
        """Constructor"""
        aui.AuiManager.__init__(self)
        self.SetManagedWindow(managed_window)
 
########################################################################
class AUINotebook(aui.AuiNotebook):
    """
    AUI Notebook class
    """
 
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        aui.AuiNotebook.__init__(self, parent=parent)
        self.default_style = aui.AUI_NB_DEFAULT_STYLE | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER
        self.SetWindowStyleFlag(self.default_style)
 
        # add some pages to the notebook
        pages = [panelOne, panelTwo, panelThree]
 
        x = 1
        for page in pages:
            label = "Tab #%i" % x
            tab = page.TabPanel(self)
            self.AddPage(tab, label, False)
            x += 1
 
########################################################################
class DemoFrame(wx.Frame):
    """
    wx.Frame class
    """
    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        title = "AGW AUI Notebook Feature Tutorial"
        wx.Frame.__init__(self, None, wx.ID_ANY,
                          title=title, size=(600,400))
        self.themeDict = {"Glossy Theme (Default)":0,
                          "Simple Theme":1,
                          "VC71 Theme":2,
                          "Firefox 2 Theme":3,
                          "VC8 Theme":4,
                          "Chrome Theme":5,
                          }
 
        # create the AUI manager
        self.aui_mgr = AUIManager(self)
 
        # create the AUI Notebook
        self.notebook = AUINotebook(self)
 
        self._notebook_style = self.notebook.default_style
 
        # add notebook to AUI manager
        self.aui_mgr.AddPane(self.notebook,
                             aui.AuiPaneInfo().Name("notebook_content").
                             CenterPane().PaneBorder(False))
        self.aui_mgr.Update()
 
        # create menu and tool bars
        self.createMenu()
        self.createTB()
 
    #----------------------------------------------------------------------
    def createMenu(self):
        """
        Create the menu
        """
        def doBind(item, handler):
            """ Create menu events. """
            self.Bind(wx.EVT_MENU, handler, item)
 
        menubar = wx.MenuBar()
 
        fileMenu = wx.Menu()
 
        doBind( fileMenu.Append(wx.ID_ANY, "&Exit\tAlt+F4",
                                "Exit Program"),self.onExit)
 
        optionsMenu = wx.Menu()
 
        doBind( optionsMenu.Append(wx.ID_ANY,
                                   "Disable Current Tab"),
                self.onDisableTab)
 
        # add the menus to the menubar
        menubar.Append(fileMenu, "File")
        menubar.Append(optionsMenu, "Options")
 
        self.SetMenuBar(menubar)
 
    #----------------------------------------------------------------------
    def createTB(self):
        """
        Create the toolbar
        """
        TBFLAGS = ( wx.TB_HORIZONTAL
                    | wx.NO_BORDER
                    | wx.TB_FLAT )
        tb = self.CreateToolBar(TBFLAGS)
        keys = self.themeDict.keys()
        keys.sort()
        choices = keys
        cb = wx.ComboBox(tb, wx.ID_ANY, "Glossy Theme (Default)",
                         choices=choices,
                         size=wx.DefaultSize,
                         style=wx.CB_DROPDOWN)
        cb.Bind(wx.EVT_COMBOBOX, self.onChangeTheme)
        tb.AddControl(cb)
        tb.AddSeparator()
 
        self.closeChoices = ["No Close Button", "Close Button At Right",
                             "Close Button On All Tabs",
                             "Close Button On Active Tab"]
        cb = wx.ComboBox(tb, wx.ID_ANY,
                         self.closeChoices[3],
                         choices=self.closeChoices,
                         size=wx.DefaultSize,
                         style=wx.CB_DROPDOWN)
        cb.Bind(wx.EVT_COMBOBOX, self.onChangeTabClose)
        tb.AddControl(cb)
 
        tb.Realize()
 
    #----------------------------------------------------------------------
    def onChangeTabClose(self, event):
        """
        Change how the close button behaves on a tab
 
        Note: Based partially on the agw AUI demo
        """
        choice = event.GetString()
        self._notebook_style &= ~(aui.AUI_NB_CLOSE_BUTTON |
                                 aui.AUI_NB_CLOSE_ON_ACTIVE_TAB |
                                 aui.AUI_NB_CLOSE_ON_ALL_TABS)
 
        # note that this close button doesn't work for some reason
        if choice == "Close Button At Right":
            self._notebook_style ^= aui.AUI_NB_CLOSE_BUTTON
        elif choice == "Close Button On All Tabs":
            self._notebook_style ^= aui.AUI_NB_CLOSE_ON_ALL_TABS
        elif choice == "Close Button On Active Tab":
            self._notebook_style ^= aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
 
        self.notebook.SetWindowStyleFlag(self._notebook_style)
        self.notebook.Refresh()
        self.notebook.Update()
 
    #----------------------------------------------------------------------
    def onChangeTheme(self, event):
        """
        Changes the notebook's theme
 
        Note: Based partially on the agw AUI demo
        """
 
        print event.GetString()
        evId = self.themeDict[event.GetString()]
        print evId
 
        all_panes = self.aui_mgr.GetAllPanes()
 
        for pane in all_panes:
 
            if isinstance(pane.window, aui.AuiNotebook):
                nb = pane.window
 
                if evId == ID_NotebookArtGloss:
 
                    nb.SetArtProvider(aui.AuiDefaultTabArt())
                    self._notebook_theme = 0
 
                elif evId == ID_NotebookArtSimple:
                    nb.SetArtProvider(aui.AuiSimpleTabArt())
                    self._notebook_theme = 1
 
                elif evId == ID_NotebookArtVC71:
                    nb.SetArtProvider(aui.VC71TabArt())
                    self._notebook_theme = 2
 
                elif evId == ID_NotebookArtFF2:
                    nb.SetArtProvider(aui.FF2TabArt())
                    self._notebook_theme = 3
 
                elif evId == ID_NotebookArtVC8:
                    nb.SetArtProvider(aui.VC8TabArt())
                    self._notebook_theme = 4
 
                elif evId == ID_NotebookArtChrome:
                    nb.SetArtProvider(aui.ChromeTabArt())
                    self._notebook_theme = 5
 
                #nb.SetWindowStyleFlag(self._notebook_style)
                nb.Refresh()
                nb.Update()
 
    #----------------------------------------------------------------------
    def onDisableTab(self, event):
        """
        Disables the current tab
        """
        page = self.notebook.GetCurrentPage()
        page_idx = self.notebook.GetPageIndex(page)
 
        self.notebook.EnableTab(page_idx, False)
        self.notebook.AdvanceSelection()
 
    #----------------------------------------------------------------------
    def onExit(self, event):
        """
        Close the demo
        """
        self.Close()
 
 
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = DemoFrame()
    frame.Show()
    app.MainLoop()

For this demo, I decided to try subclassing AuiManager and the aui.AuiNotebook. While I think this could be helpful if you ever needed to instantiate multiple AuiManager instances, for the purposes of this demo, it really didn’t help much other than showing you how to do it. Let’s unpack this example bit by bit and see how it works!

In the AuiManager class, I force the programmer to pass in the window to be managed and it calls the SetManagedWindow() automatically. You could do this with some of AuiManager’s other functions as well. In the AuiNotebook’s case, I set a default style using its SetWindowStyleFlag() method and then I add some pages to the notebook. This gives me a quick and easy way to create multiple notebooks quickly.

The DemoFrame does the bulk of the work. It creates a theme dictionary for later use, instantiates the AuiManager and AuiNotebook, and creates a toolbar and menubar. Our focus will be the event handlers related to the menubar and the toolbar as they affect the way the AuiNotebook functions. Our first method of interest is onChangeTabClose().

Listing 6

def onChangeTabClose(self, event):
    """
    Change how the close button behaves on a tab
 
    Note: Based partially on the agw AUI demo
    """
    choice = event.GetString()
    self._notebook_style &= ~(aui.AUI_NB_CLOSE_BUTTON |
                             aui.AUI_NB_CLOSE_ON_ACTIVE_TAB |
                             aui.AUI_NB_CLOSE_ON_ALL_TABS)
 
    # note that this close button doesn't work for some reason
    if choice == "Close Button At Right":
        self._notebook_style ^= aui.AUI_NB_CLOSE_BUTTON
    elif choice == "Close Button On All Tabs":
        self._notebook_style ^= aui.AUI_NB_CLOSE_ON_ALL_TABS
    elif choice == "Close Button On Active Tab":
        self._notebook_style ^= aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
 
    self.notebook.SetWindowStyleFlag(self._notebook_style)
    self.notebook.Refresh()
    self.notebook.Update()

This event handler is invoked from combobox events generated by the second combobox in the toolbar. Its purpose is to decide the placement of the close button on the tabs. First, it grabs the user’s choice by calling “event.GetString()”. Next it uses some bitwise operators to clear the close button related styles. If I’m reading it correctly, it “ands” the current notebook style with a “notted” multi-”or”. Yes, it’s confusing. To put it simply, it says that the three styles (aui.AUI_NB_CLOSE_BUTTON, aui.AUI_NB_CLOSE_ON_ACTIVE_TAB, aui.AUI_NB_CLOSE_ON_ALL_TABS) will be subtracted from the current notebook style.

Then I use a conditional to decide which style to actually apply to the notebook. Once that’s added to the variable, I use the notebook’s SetWindowStyleFlag() to apply it and then Refresh and Update the display so the user can see the changes.

Print Friendly