Wed 9 Dec 2009
The “Book” Controls of wxPython (Part 2 of 2)
Posted by Mike under Cross-Platform, Python, wxPython
[11] Comments
In the first part of this series, I wrote on all the non-agw notebook widgets included with wxPython. For this second article, I will be focusing on the two notebooks that are in the AGW library of wxPython. AGW stands for Advanced Generic Widgets, a set of widgets that are written in Python instead of wrapped C++ code. I personally think that AGW is also a callback to its amazing author, Andrea Gavana. Regardless, the two widgets in this review will be the FlatNotebook and another AUI Notebook. The FlatNotebook has a great demo and I will spend most of this article on demos I’ve created that are based on it. The AUI Notebook is a part of agw.aui. While the demo for agw.aui is cool, it focuses on AUI in general, not the notebook. So I’ll just show you what I can glean from that. Now, let’s get cracking!
Update: The API changed slightly when it comes to AGW-related widgets. Basically some style flags in wxPython 2.8.11.0+ now require the agw-specific style flags. To use them, you’ll need to use the agwStyle keyword. See Andrea’s docs for more info: http://xoomer.virgilio.it/infinity77/AGW_Docs/ If you run into an error, try changing that first or post to the mailing list.
The Amazing FlatNotebook
The Flatbook control is written in Python rather than a wrapped widget from wxWidgets. It was added to wxPython with the release of wxPython 2.8.9.2 on February 16, 2009. Since then Andrea Gavana has been updating the agw library with lots of fixes. My examples will work with the 2.8.9.2+ versions of wxPython, but I recommend getting the SVN version of agw and replacing your default one with it as there have been a lot of bug fixes applied to the AUI module and several others. There is also an effort going on currently to better document this library in the code itself, so you may find that helpful too!
Here are a few of the FlatNotebook’s Features:
- 5 Different tab styles
- It’s a generic control (i.e. pure python) so it’s easy to modify
- You can use the mouse’s middle-click to close tabs
- A built-in function to add right-click pop-up menus on tabs
- A way to hide the “X” that closes the individual tabs
- Support for disabled tabs
- Plus lots more! See the source and the wxPython Demo for more information!
Now that we’ve done an unpaid commercial, let’s take a look at the actual product:
Listing 1
import panelOne, panelTwo, panelThree import wx import wx.lib.agw.flatnotebook as fnb ######################################################################## class FlatNotebookDemo(fnb.FlatNotebook): """ Flatnotebook class """ #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" fnb.FlatNotebook.__init__(self, parent, wx.ID_ANY) pageOne = panelOne.TabPanel(self) pageTwo = panelTwo.TabPanel(self) pageThree = panelThree.TabPanel(self) self.AddPage(pageOne, "PageOne") self.AddPage(pageTwo, "PageTwo") self.AddPage(pageThree, "PageThree") ######################################################################## class DemoFrame(wx.Frame): """ Frame that holds all other widgets """ #---------------------------------------------------------------------- def __init__(self): """Constructor""" wx.Frame.__init__(self, None, wx.ID_ANY, "FlatNotebook Tutorial", size=(600,400) ) panel = wx.Panel(self) notebook = FlatNotebookDemo(panel) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5) panel.SetSizer(sizer) self.Layout() self.Show() #---------------------------------------------------------------------- if __name__ == "__main__": app = wx.PySimpleApp() frame = DemoFrame() app.MainLoop()
In Listing 1, I subclass FlatNotebook and use the generic panels from my previous article for the pages. You’ll notice that FlatNotebook has its own AddPage method that mimics the wx.Notebook. This should come as no surprise as the FlatNotebook’s API is such that you should be able to use it as a drop-in replacement for wx.Notebook. Of course, right out of the box, FlatNotebook has the advantage. If you run the demo above, you’ll see that FlatNotebook allows the user to rearrange the tabs, close the tabs and it includes some previous/next buttons in case you have more tabs than can fit on-screen at once.
Now let’s take a look at the various styles that we can apply to FlatNotebook:
Listing 2
import panelOne, panelTwo, panelThree import wx import wx.lib.agw.flatnotebook as fnb ######################################################################## class FlatNotebookDemo(fnb.FlatNotebook): """ Flatnotebook class """ #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" fnb.FlatNotebook.__init__(self, parent, wx.ID_ANY) pageOne = panelOne.TabPanel(self) pageTwo = panelTwo.TabPanel(self) pageThree = panelThree.TabPanel(self) self.AddPage(pageOne, "PageOne") self.AddPage(pageTwo, "PageTwo") self.AddPage(pageThree, "PageThree") ######################################################################## class DemoFrame(wx.Frame): """ Frame that holds all other widgets """ #---------------------------------------------------------------------- def __init__(self): """Constructor""" wx.Frame.__init__(self, None, wx.ID_ANY, "FlatNotebook Tutorial with Style", size=(600,400) ) self.styleDict = {"Default":self.OnDefaultStyle, "VC71":self.OnVC71Style, "VC8":self.OnVC8Style, "Fancy":self.OnFancyStyle, "Firefox 2":self.OnFF2Style} choices = self.styleDict.keys() panel = wx.Panel(self) self.notebook = FlatNotebookDemo(panel) self.styleCbo = wx.ComboBox(panel, wx.ID_ANY, "Default", wx.DefaultPosition, wx.DefaultSize, choices=choices, style=wx.CB_DROPDOWN) styleBtn = wx.Button(panel, wx.ID_ANY, "Change Style") styleBtn.Bind(wx.EVT_BUTTON, self.onStyle) # create some sizers sizer = wx.BoxSizer(wx.VERTICAL) hSizer = wx.BoxSizer(wx.HORIZONTAL) # add the widgets to the sizers sizer.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5) hSizer.Add(self.styleCbo, 0, wx.ALL|wx.CENTER, 5) hSizer.Add(styleBtn, 0, wx.ALL, 5) sizer.Add(wx.StaticLine(panel), 0, wx.ALL|wx.EXPAND, 5) sizer.Add(hSizer, 0, wx.ALL, 5) panel.SetSizer(sizer) self.Layout() self.Show() #---------------------------------------------------------------------- def onStyle(self, event): """ Changes the style of the tabs """ print "in onStyle" style = self.styleCbo.GetValue() print style self.styleDict[style]() # The following methods were taken from the wxPython # demo for the FlatNotebook def OnFF2Style(self): style = self.notebook.GetWindowStyleFlag() # remove old tabs style mirror = ~(fnb.FNB_VC71 | fnb.FNB_VC8 | fnb.FNB_FANCY_TABS | fnb.FNB_FF2) style &= mirror style |= fnb.FNB_FF2 self.notebook.SetWindowStyleFlag(style) def OnVC71Style(self): style = self.notebook.GetWindowStyleFlag() # remove old tabs style mirror = ~(fnb.FNB_VC71 | fnb.FNB_VC8 | fnb.FNB_FANCY_TABS | fnb.FNB_FF2) style &= mirror style |= fnb.FNB_VC71 self.notebook.SetWindowStyleFlag(style) def OnVC8Style(self): style = self.notebook.GetWindowStyleFlag() # remove old tabs style mirror = ~(fnb.FNB_VC71 | fnb.FNB_VC8 | fnb.FNB_FANCY_TABS | fnb.FNB_FF2) style &= mirror # set new style style |= fnb.FNB_VC8 self.notebook.SetWindowStyleFlag(style) def OnDefaultStyle(self): style = self.notebook.GetWindowStyleFlag() # remove old tabs style mirror = ~(fnb.FNB_VC71 | fnb.FNB_VC8 | fnb.FNB_FANCY_TABS | fnb.FNB_FF2) style &= mirror self.notebook.SetWindowStyleFlag(style) def OnFancyStyle(self): style = self.notebook.GetWindowStyleFlag() # remove old tabs style mirror = ~(fnb.FNB_VC71 | fnb.FNB_VC8 | fnb.FNB_FANCY_TABS | fnb.FNB_FF2) style &= mirror style |= fnb.FNB_FANCY_TABS self.notebook.SetWindowStyleFlag(style) #---------------------------------------------------------------------- if __name__ == "__main__": app = wx.PySimpleApp() frame = DemoFrame() app.MainLoop()
That’s a lot of code for a “simple” example, but I think it will help us understand how to apply tab styles to our widget. I borrowed most of the methods from the wxPython demo, in case you didn’t notice. The primary talking point in this code is the contents of those methods, which are mostly the same. Here’s the main snippet to take away from this section:
style = self.notebook.GetWindowStyleFlag() # remove old tabs style mirror = ~(fnb.FNB_VC71 | fnb.FNB_VC8 | fnb.FNB_FANCY_TABS | fnb.FNB_FF2) style &= mirror style |= fnb.FNB_FF2 self.notebook.SetWindowStyleFlag(style)
First, we need to get the current style of the FlatNotebook. Then we use some fancy magic in the “mirror” line that creates a set of styles that we want to remove. The line, “style &= mirror” actually does the removing and then we add the style we wanted with “style |= fnb.FNB_FF2″. Finally, we use SetWindowStyleFlag() to actually apply the style to the widget. You may be wondering what’s up with all those goofy symbols (i.e. |, ~, &). Well, those are known as bitwise operators. I don’t use them much myself, so I recommend reading the Python documentation for full details as I don’t fully understand them myself.
-
bc
-
bc
-
http://www.pythonlibrary.org/ mld
-
Anonymous
-
ma
-
ma
-
Anonymous
-
ma
-
Anonymous
-
ma


