Book Image

wxPython 2.8 Application Development Cookbook

By : Cody Precord
Book Image

wxPython 2.8 Application Development Cookbook

By: Cody Precord

Overview of this book

<p>In today’s world of desktop applications there is a great amount of incentive to be able to develop applications that can run in more than one environment. Currently there are a handful of options available for cross platform frameworks to develop desktop applications in Python. wxPython is one such cross- platform GUI toolkit for the Python programming language. It allows Python programmers to create programs with a complete, highly functional graphical user interface, simply and easily. wxPython code style has changed quite a bit over the years, and gotten much more Pythonic. The examples you will find in this book are right up to date and reflect this change in style.<br />This cookbook provides you with the latest recipes to quickly create robust, reliable, and reusable wxPython applications. These recipes will guide you from writing simple, basic wxPython scripts all the way through complex concepts, and also feature various design approaches and techniques in wxPython.<br /><br />The book starts off by covering a variety of topics from the most basic requirements of a wxPython application to some of the more in depth details of the inner workings of the framework laying the foundation for any wxPython application. It then explains event handling, basic and advanced user interface controls, designing and layout, creating dialogs, components and extending functionality, and so on. We conclude by learning how to build and manage applications for distribution.<br />For each of the recipes, there is an introductory example, then more advanced examples, and plenty of example code to develop and manage user-friendly applications. For more experienced developers, most recipes also include additional discussion of the solution, allowing you to further customize and enhance the component.</p>
Table of Contents (19 chapters)
wxPython 2.8 Application Development Cookbook
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Understanding inheritance limitations


wxPython is a wrapper around the wxWidgets C++ framework. This relationship means that inside most wxPython objects there is a C++ object. Because of this, methods that belong to wxPython classes cannot always be overridden in the same way as they can with a normal Python object.

To demonstrate this behavior, this recipe will show how to create a class that will automatically add its children windows to its Sizer layout. This will be contrasted to a class that does not expose its virtual methods to the Python layer of the class.

How to do it...

To demonstrate the difference in overriding methods, we will create two similar classes first starting with one that derives from the standard Panel class:

import wx

class MyPanel(wx.Pael): 
    def __init__(self, parent):
        super(MyPanel, self).__init__(parent)

        sizer = wx.BoxSizer()
        self.SetSizer(sizer)

    def AddChild(self, child):
        sizer = self.GetSizer()
        sizer.Add(child, 0, wx.ALIGN_LEFT|wx.ALL, 8)
        return super(MyPanel, self).AddChild(child)

Now we will create a class that is exactly the same except that it derives from the Py version of the class:

class MyVirtualPanel(wx.PyPanel):
    """Class that automatically adds children
    controls to sizer layout.
    """
    def __init__(self, parent):
        super(MyVirtualPanel, self).__init__(parent)

        sizer = wx.BoxSizer()
        self.SetSizer(izer) 

    def AddChild(self, child):
        sizer = self.GetSizer()
        sizer.Add(child, 0, wx.ALIGN_LEFT|wx.ALL, 8)
        return super(MyVirtualPanel, self).AddChild(child)

Now below we have a little sample application that uses the above two classes:

class MyFrame(wx.Frame):
    def __init__(self, parent, *args, **kwargs):
        super(MyFrame, self).__init__(parent,
                                      *args, **kwargs)

        # Attributes
        self.mypanel = MyPanel(self)
        self.mypanel.SetBackgroundColour(wx.BLACK)
        self.virtpanel = MyVirtualPanel(self)
        self.virtpanel.SetBackgroundColour(wx.WHITE)

        # Setup
        self.__DoLayout()

    def __DoLayout(self):
        """Layout the window"""
        # Layout the controls using a sizer
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.mypanel, 1, wx.EXPAND)
        sizer.Add(self.virtpanel, 1, wx.EXPAND)
        self.SetSizer(sizer)
        
        # Create 3 children for the top panel
        for x in range(3):
            wx.Button(self.mypanel,
                      label="MyPanel %d" % x)
        # Create 3 children for the bottom panel
        for x in range(3):
            wx.Button(self.virtpanel,
                      label="VirtPanel %d" % x)

        self.SetInitialSize(size=(300, 200))

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None,
                             title="Virtualized Methods")
        self.SetTopWindow(self.frame)
        self.frame.Show()

        return True

if __name__ == "__main__":
    app = MyApp(False)
    app.MainLoop()

Running this code will result in a window like the following one being displayed:

How it works...

In each version of our Panel class we override the AddChild method, which is called every time that a window has a new child window created. AddChild is called inside the C++ part of the class when this happens, so in order to be able to override the method in our Python version of the class, we need to use the special version that provides access to overriding the virtualized method from the C++ class.

The classes in wxPython that have a version of the class prefixed with Py have the virtualized versions of many of the methods exposed, so that when they are overridden in a Python subclass they get bound to the method in the C++ layer of the object and will be called by the framework instead of the base class's implementation.

This can be seen in the screenshot of our recipe application that was shown above. The top version of the class that does not derive from PyPanel has all three of its Buttons stacked on top of each other in the top left-hand corner of the window, because its overridden AddChild method is never called. On the other hand, the version of the class that does derive from PyPanel has its AddChild method called and is able to lay out the Buttons in its Sizer.

There's more...

It is not well documented as to which methods are exposed as virtual methods and which ones are not. Here is a little trick that can help you to identify which virtual methods are available in a given class. Just run the following code inside the Python interpreter:

import wx
for method in dir(wx.PyPanel):
    if method.startswith('base_'):
        print method

The argument in the dir() call can be changed to whatever class you want to inspect. Running this will print out a list of all of the methods in the class that are virtualized. The base_ methods are generated by SWIG as a part of the wxPython bindings to wxWidgets, and should not be used directly in your code. Instead, the methods without the base_ prefix should be used.

See also

  • The Creating a custom control recipe in Chapter 10, Creating Components and Extending Functionality, shows more usage examples of overriding virtual methods.

  • The Using a BoxSizer recipe in Chapter 7, Window Design and Layout, explains how the BoxSizer class can be used to perform the layout of controls in a window.