Home Application-development wxPython 2.8 Application Development Cookbook

wxPython 2.8 Application Development Cookbook

By Cody Precord
books-svg-icon Book
Subscription
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
Subscription
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Getting Started with wxPython
About this book

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.
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.

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.
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.

Publication date:
December 2010
Publisher
Packt
Pages
308
ISBN
9781849511780

 

Chapter 1. Getting Started with wxPython

In this chapter, we will cover the components that are at the foundation of nearly all wxPython applications, such as:

  • The application object

  • The main frame

  • Understanding the window hierarchy

  • Referencing controls

  • Using Bitmaps

  • Adding icons to Windows

  • Utilizing Stock IDs

  • Accessing the clipboard

  • Supporting drag and drop

  • Two-stage widget creation

  • Understanding inheritance limitations

 

Introduction


In today's world of desktop applications there is a great amount of incentive to be able to develop applications that can run on multiple operating systems and desktop platforms. Currently there are a handful of cross-platform Python frameworks that can be used to develop desktop applications. The wxPython Library is a set of Python bindings to the wxWidgets Library, which is a powerful cross-platform C++ application framework that can be used to create user interfaces. What sets wxPython apart is that, unlike other UI toolkits that draw their own controls, wxPython uses the platform's own native UI toolkit for creating and displaying UI components. This means that a wxPython application will have the same look and feel as other applications on the system since it is using the same controls and themes as the rest of the system.

Developing an application in wxPython provides great flexibility for writing applications that will run on Windows, Macintosh OS X, Linux, and other UNIX like environments. Applications can rapidly be developed on one platform and often deployed to another with little or no changes necessary.

 

The application object


The App object bootstraps the library and initializes the underlying toolkit. All wxPython applications must create an App object. This should be instantiated before trying to create any other GUI objects to ensure that all the dependant parts of the library have been properly initialized. The App object also maintains the MainLoop, which is used to drive a wxPython application.

This recipe will demonstrate the basic pattern that all wxPython applications can be built from.

How to do it...

Here we will create a "Hello World" like application to show the basic structure of a wxPython application:

import wx

class MyApp(wx.App):
    def OnInit(self):
        wx.MessageBox("Hello wxPython", "wxApp")
        return True

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

Running the previous script will result in the following pop-up dialog shown on the screen. Click on OK to close it and exit the application.

How it works...

The application object calls its OnInit mehod when it is created. This method is overridden and used as the main entry point for initializing this application. By returning True, the method informs the framework that it is good to go. OnInit is where most applications will do their initialization and create their main window(s).

In this example, we created the App object by passing False as the first argument. This argument is used to tell wxPython whether to redirect output or not. When developing an application, it is advised to always set this to False, and to run scripts from the command line so that you can see any error output that might be missed when running the script by double clicking on it.

After creating the application object and once all initializations are complete, the last thing that you need to do is to call the App objects MainLoop method in order to start the event loop. This method will not return until the last top-level window is destroyed or until the App object is told to exit. wxPython is an event-driven system and the MainLoop is the heart of the whole system. During each iteration of the loop, events are dispatched to perform all of the tasks in the GUI, such as handling mouse clicks, moving the window, and redrawing the screen.

There's more...

The wx.App class constructor has four optional keyword arguments:

wx.App(redirect=True, filename=None,
       useBestVisual=False,clearSigInt=True)

The four optional keyword arguments are as follows:

  • redirect: Redirec stdout.

  • filename: If redirect is True this can be used to specify an output file to reirect to.

  • useBestVisual: Specifies whether the application should try to use the best visuals provided by the underlying toolkit. (It does not have an affect on mos systems.)

  • clearSigInt: Should SIGINT be cleared? Setting this to True will allow the application to be terminated by pressing Ctrl + C, like most other applications.

 

The main frame


For most applications, you will want to display a window for its users to interact with. In wxPython, the most typical window object is known as a Frame. This recipe will show you how to subass a Frame and display it in an application.

How to do it...

This example extends upon the previous recipe to add a minimal empty application window:

import wx

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

        return True

class MyFrame(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="", 
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_FRAME_STYLE,
                 name="MyFrame"):
        super(MyFrame, self).__init__(parent, id, title,
                                      pos, size, style, name)

        # Attributes
        self.panel = wx.Panel(self)

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

Running the previous code will result in a window like the following being shown:

How it works...

The Frame is the main top-level window and container for most applications. Let's start by examining our MyFrame class. In this class there is one important thing to note. We created a Panel object as a child window of the Frame. You can think of a Panel as a box for containing other controls. Also, in order for a Frame to operate and look correct on all platforms, it is important that it has a Panel as its main child.

Firstly, in the OnInit method of our App, we create an instance of MyFrame, passing None as its first parameter. This parameter is used to specify the parent window of the Frame. Because this is our main window, we pass in None to indicate that it has no parent. Secondly, we call the SetTopWindow method of our App in order to set our newly-created MyFrame instance as the application's top window. Thirdly and finally, we call Show on our Frame; this simply does what its name suggests, and shows the Frame so that a user can see it, though the Frame will not actually be visible on the screen until the MainLoop is started.

There's more...

The Frame class has a number of style flags that can be set in its constructor to modify the behavior and appearance of the window. These style flags can be combined as a bitmask and are supplied as the value to the constructors' style parameter. The following table outlines some of the common ones. A full list of all available styles can be found in the wxPython online documentation, at http://wxpython.org/onlinedocs.php.

Style flags

Description

wx. DEFAULT_FRAME_STYLE

This is a bitwise OR of the following flags:

  • wx.MINIMIZE_BOX

  • wx.MAXIMIZE_BOX

  • wx.RESIZE_BORDER

  • wx.SYSTEM_MENU

  • wx.CAPTION

  • wx.CLOSE_BOX

  • wx.CLIP_CHILDREN

wx. MINIMIZE_BOX

Display a title bar button that minimizes the Frame

wx. MAXIMIZE_BOX

Display a title bar button that maximizes the Frame

wx. CLOSE_BOX

Display a title bar button that allows the Frame to be closed. (the "X" button)

wx. RESIZE_BORDER

Allow the Frame to be resized by the user when they drag the border

wx. CAPTION

Displays a caption on the Frame

wx. SYSTEM_MENU

Display a system menu (that is, the menu that is shown when clicking in the frames icon on Windows)

wx. CLIP_CHILDREN

Eliminates flicker caused by the background being repainted (Windows only)

 

Understanding the window hierarchy


All of the different windows and controls in wxPython have a hierarchy of containment. Some controls can be containers for other controls and some cannot. This recipe is geared towards giving an understanding of this hierarchy.

Getting ready

We will be making just a minor change to the Frame from the previous recipe, so let's open the code from that recipe to get ready for the new changes.

How to do it...

Here is the new code that will replace our existing Frame class.

class MyFrame(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="", 
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_FRAME_STYLE,
                 name="MyFrame"):
        super(MyFrame, self).__init__(parent, id, title,
                                      pos, size, style, name)

        # Attributes
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour(wx.BLACK)
        self.button = wx.Button(self.panel,
                                label="Push Me",
                                pos=(50, 50))

How it works...

Basically, there are three general categories of window objects that are tiered, in the following containment order:

  • Top-Level Windows (Frames and Dialogs)

  • General Containers (Panels and Notebooks, …)

  • Controls (Buttons, CheckBoxes, ComboBoxes, …)

The Top-Level Window is at the top of the hierarchy and it can contain any kind of window except another Top-Level Window. General Containers come next, and they can arbitrarily hold any other General Container or Control. Finally, at the bottom of the Hierarchy are the Controls. These are the functional part of a UI that the user will interact with. They can, in some cases, be used to hold other controls, but typically will not. The containment hierarchy is connected to the parental hierarchy of controls. A parent will be the container for its children.

When running the previous sample, this hierarchy becomes apparent. The Frame, as we have previously seen, is the outer-most container object; next you can see the Panel, which we turned black to make it more visible; finally you can see the Button, which was added as a child of the Panel.

See also

  • The Referencing controls recipe in this chapter offers further explanation as to how the window hierarchy is connected together.

 

Referencing controls


All Window objects in an application are connected in various ways. Quite often it is useful to get a reference to an instance of a control so that you can perform some operation on the control or retrieve some data from it. This recipe will show some of the facilities that are available for finding and getting references to controls.

How to do it...

Here we extend the MyFrame class from the previous recipe to have an event handler for when its Button is clicked. In the event handler we can see some ways to access different controls in our UI during runtime:

class MyFrame(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="", 
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_FRAME_STYLE,
                 name="MyFrame"):
        super(MyFrame, self).__init__(parent, id, title,
                                      pos, size, style, name)

        # Attributes
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour(wx.BLACK)
        button = wx.Button(self.panel,
                           label="Get Children",
                           pos=(50, 50))
        self.btnId = button.GetId()
        # Event Handlers
        self.Bind(wx.EVT_BUTTON, self.OnButton, button)

    def OnButton(self, event):
        """Called when the Button is clicked"""
        print "\nFrame GetChildren:"
        for child in self.GetChildren():
            print "%s" % repr(child)

        print "\nPanel FindWindowById:"
        button = self.panel.FindWindowById(self.btnId)
        print "%s" % repr(button)
        # Change the Button's label
        button.SetLabel("Changed Label")

        print "\nButton GetParent:"
        panel = button.GetParent()
        print "%s" % repr(panel)

        print "\nGet the Application Object:"
        app = wx.GetApp()
        print "%s" % repr(app)

        print "\nGet the Frame from the App:"
        frame = app.GetTopWindow()
        print "%s" % repr(frame)

How it works...

Each window in the framework keeps a reference to its parent and to its children. Running our program now will print out the results of using the accessor functions that all windows have for finding and retrieving references to their children and other related controls.

  • GetChildren: This method will return a list of all of the children that the given control has

  • FindWindowById: This can be used to find a specific child window by using its ID

  • GetParent: This method will retrieve the window's parent window

  • wx. GetApp: This is a global function for getting access to the one and only application object

  • App. GetTopWindow: This gets the main Top-Level Window in the application

Clicking on the Button will cause the OnButton method to be called. In OnButton, there are examples that show how to use each of the above methods. Each of them will return a reference to a GUI object. In our example, calling GetChildren on the Panel will return a list of its children controls. Iterating over this list, we print out each of the children, which will just be the Button in this case. FindWindowById can be used to find a specific child control; again, we called this on our Panel to find the Button control. Just to show that we found the Button, we used its SetLabel method to change its label. Next, calling GetParent on the Button will return the Button's parent, which is the Panel. Finally, by using the global GetApp function, we can get a reference to the application object. The App object's GetTopWindow will return a reference to our Frame.

There's more...

Here are a few more useful methods available for getting references to controls.

Function Name

Description

wx.FindWindowByLabel(label)

Finds a child window by looking for it by Label

wx.FindWindowByName(name)

Finds a child window by looking for it by Name

wx.GetTopLevelParent()

Gets the Top-Level Window, which is at the top of the given control's parental hierarchy

See also

  • The Understanding the window hierarchy recipe in this chapter outlines the structure of how windows are contained within and are related to each other.

 

Using Bitmaps


It's likely that, at some point, you will want to be able to display an image in your application. A Bitmap is the basic data type that is used to display images in an application. This recipe will show how to load an image file into a Bitmap and then display it in a Frame.

How to do it...

To see how to use Bitmaps, we will create a little application that loads an image from the hard disk and displays it in a Frame:



import os
import wx

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

        return True

class MyFrame(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="", 
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_FRAME_STYLE,  
                 name="MyFrame"):
        super(MyFrame, self).__init__(parent, id, title,
                                      pos, size, style, name)

        # Attributes
        self.panel = wx.Panel(self)

        img_path = os.path.abspath("./face-grin.png")
        bitmap = wx.Bitmap(img_path, type=wx.BITMAP_TYPE_PNG)
        self.bitmap = wx.StaticBitmap(self.panel, 
                                      bitmap=bitmap)

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

How it works...

The StaticBitmap control is the simplest method of displaying a Bitmap in an application. In the example code that accompanies this recipe, we have an image in the same directory as our script, called face-grin.png, that we want to display. In order to display the image we first use the Bitmap constructor to load the image into memory, and then pass it to the StaticBitmap control in order to display the image on the screen. The constructor takes a path to the file, and a type argument that specifies the image format.

There's more...

There is built-in support for the most common image formats. The following list shows the supported image file formts:

  • wx.BITMAP_TYPE_ANY

  • wx.BITMAP_TYPE_BMP

  • wx.BITMAP_TYPE_ICO

  • wx.BITMAP_TYPE_CUR

  • wx.BITMAP_TYPE_XBM

  • wx.BITMAP_TYPE_XPM

  • wx.BITMAP_TYPE_TIF

  • wx.BITMAP_TYPE_GIF

  • wx.BITMAP_TYPE_PNG

  • wx.BITMAP_TYPE_JPEG

  • wx.BITMAP_TYPE_PNM

  • wx.BITMAP_TYPE_PCX

  • wx.BITMAP_TYPE_PICT

  • wx.BITMAP_TYPE_ICON

  • wx.BITMAP_TYPE_ANI

  • wx.BITMAP_TYPE_IFF

See also

  • The Working with ToolBars recipe in Chapter 3, Basic Building Blocks of a User Interface contains some more Bitmap usage examples.

  • The Customizing the ArtProvider recipe in Chapter 10, Creating Components and Extending Functionality provides more on information how to create Bitmaps.

 

Adding icons to Windows


Adding an icon to your application's title bar as a way of branding the application that will help to set it apart and distinguish it from the other applications running on the desktop. This recipe will show how easy it is to add an icon to a Frame.

Note

Support for adding an Icon to the title bar on OS X is currently not supported by wxPython 2.8.

How to do it...

Here we will create a Frame subclass that loads an image file from the hard disk and displays it on its title bar:

class MyFrame(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="", 
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_FRAME_STYLE,
                 name="MyFrame"):
        super(MyFrame, self).__init__(parent, id, title, pos,
                                      size, style, name)


        # Attributes
        self.panel = wx.Panel(self)

        # Setup
        path = os.path.abspath("./face-monkey.png")
        icon = wx.Icon(path, wx.BITMAP_TYPE_PNG)
        self.SetIcon(icon)

Displaying this Frame subclass will result in a window like the following. Comparing this to the one in the Main Frame recipe, you can see the new icon to the left of the title:

How it works...

In this recipe we have a small (16x16) image of a monkey that we want to show in the title bar of the Frame. For simplicity, this image is located in the same directory as our script and we load it using a relative path. The Frame requires an icon instead of a Bitmap, so we have to use an Icon to load our image into memory. After loading the image, all that is left is to call the Frame's SetIcon method in order to set the Icon for the Frame.

See also

  • The Using Bitmaps recipe in this chapter discusses the more commonly-used Bitmap image type.

 

Utilizing Stock IDs


All controls, and many other user-interface elements, such as menus, take an ID as an argument in their constructor that can be used to identify the control or object inside event handlers. Typically, the value of wx.ID_ANY is used to let the system automatically generate an ID for the item, or the wx.NewId function is used to create a new ID. However, there are also a number of predefined IDs available in the wx module that have special meaning for certain common items that many applications tend to have, such as Copy/Paste menu items or Ok/Cancel buttons. The expected behavior and appearance of some of these items can vary from platform to platform. By using the stock ID, wxPython will take care of the differences for you. This recipe will show a few of the places in which these IDs can come in handy.

How to do it...

This code snippet shows how to make use of some of the predefined IDs to simplify the creation of some common UI elements:

class MyFrame(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="", 
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_FRAME_STYLE,
                 name="MyFrame"):
        super(MyFrame, self).__init__(parent, id, title, 
                                      pos, size, style, name)

        # Attributes
        self.panel = wx.Panel(self)

        # Setup
        ok_btn = wx.Button(self.panel, wx.ID_OK)
        cancel_btn = wx.Button(self.panel, wx.ID_CANCEL,
                               pos=(100, 0))

        menu_bar = wx.MenuBar()
        edit_menu = wx.Menu()
        edit_menu.Append(wx.NewId(), "Test")
        edit_menu.Append(wx.ID_PREFERENCES)
        menu_bar.Append(edit_menu, "Edit")
        self.SetMenuBr(menu_bar)

The previous class will create the following window:

How it works...

The first thing to notice in this recipe is that no labels were specified for the two buttons that we created. By using the Stock IDs for OK and Cancel as their IDs, the framework will automatically put the proper label o the control.

This also applies to menu items, as can be seen in our Edit menu for the Preferences item. Another important thing to note is that if this sample is run on Macintosh OS X, the framework will also automatically move the Preferences menu item to its expected location in the Application menu.

There's more...

Using buttons with Stock IDs in a Modal Dialog will also allow the dialog to be dismissed, and return the appropriate value, such as wx.OK or wx.CANCEL, without the need to connect event handlers to the buttons for performing this standard action. Automatically getting the correct button layout for a dialog can also be achieved by using Stock IDs with StdDialogButtonSizer.

See also

  • The Creating Stock Buttons recipe in Chapter 3, Basic Building Blocks of a User Interface shows how Stock IDs can be used to construct standard buttons.

  • The Standard dialog button layout recipe in Chapter 7, Window Layout and Design shows how to easily add common buttons to dialogs by using Stock IDs.

  • The Optimizing for OS X recipe in Chapter 12, Building and Managing Applications for Distribution shows more uses for Stock IDs.

 

Accessing the clipboard


The Clipboard is a system-wide, accessible way of getting data to and from one application to another. This recipe will show how to get text from the clipboard, as well as how to put text in the clipboard for other applications to access.

How to do it...

The following two functions can be used to get text from and put text on the clipboard:

def SetClipboardText(text):
    """Put text in the clipboard
    @param text: string
    """
    data_o = wx.TextDataObject()
    data_o.SetText(text)
    if wx.TheClipboard.IsOpened() or wx.TheClipboard.Open():
        wx.TheClipboard.SetData(data_o)
        wx.TheClipboard.Close()

def GetClipboardText():
    """Get text from the clipboard
    @return: string
    """
    text_obj = wx.TextDataObject()
    rtext = ""
    if wx.TheClipboard.IsOpened() or wx.TheClipboard.Open():
        if wx.TheClipboard.GetData(text_obj):
            rtext = text_obj.GetText()
        wx.TheClipboard.Close()
    return rtext

How it works...

wxPython provides a singleton clipboard object that can be used to interact with the systems clipboard. This class works with data objects that are used to represent the underlying system data types. The use of the clipboard is a three-step process:

  • Open the Clipboard

  • Set/Get the DataObject

  • Close the Clipboard

There's more...

The clipboard supports many other data types besides just text. wxPython provides built-in support for some additional types, as well as classes for defining your own custom types. The usage of these different data types follows the same general pattern as the TextDataObject.

Data types

Description

wx. BitmapDataObject

Used to get Bitmaps from and put Bitmaps on the Clipboard

wx. CustomDataObject

Can hold any Python picklable data type

wx. DataObjectComposite

Can contain any arbitrary number of simple data types and make them all available at once

wx. FileDataObject

Used for holding filenames

wx. URLDataObject

Used for holding URLs

See also

  • The Supporting drag and drop recipe in this chapter is related to the clipboard in that it allows for the transfer of data between applications.

 

Supporting drag and drop


In order to improve usability, it is good to support drag and drop in an application so that the user can simply drop files or other objects into your application. This recipe will show how to support accepting a CompositeDataObject that supports both files and text.

How to do it...

First we will define a custom drop target class:

class FileAndTextDropTarget(wx.PyDropTarget):
    """Drop target capable of accepting dropped 
    files and text
    """
    def __init__(self, file_callback, text_callback):
        assert callable(file_callback)
        assert callable(text_callback)
        super(FileAndTextDropTarget, self).__init__()
        # Attributes
        self.fcallback = file_callback # Drop File Callback
        self.tcallback = text_callback # Drop Text Callback
        self._data = None
        self.txtdo = None
        self.filedo = None

        # Setup
        self.InitObjects()
        
    def InitObjects(self):
        """Initializes the text and file data objects"""
        self._data = wx.DataObjectComposite()
        self.txtdo = wx.TextDataObject()
        self.filedo = wx.FileDataObject()
        self._data.Add(self.txtdo, False)
        self._data.Add(self.filedo, True)
        self.SetDataObject(self._data)

    def OnData(self, x_cord, y_cord, drag_result):
        """Called by the framework when data is dropped 
        on the target
        """
        if self.GetData():
            data_format = self._data.GetReceivedFormat()
            if data_format.GetType() == wx.DF_FILENAME:
                self.fcallback(self.filedo.GetFilenames())
            else:
                self.tcallback(self.txtdo.GetText())
            
        return drag_result

Then to make use of the FileAndTextDropTarget, we assign it to a window using the window object's SetDropTarget method.

class DropTargetFrame(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="", 
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_FRAME_STYLE,
                 name="DropTargetFrame"):
        super(DropTargetFrame, self).__init__(parent, id,
                                              title, pos,
                                              size, style,
                                              name)

        # Attributes
        choices = ["Drag and Drop Text or Files here",]
        self.list = wx.ListBox(self, 
                               choices=choices)
        self.dt = FileAndTextDropTarget(self.OnFileDrop,
                                        self.OnTextDrop)
        self.list.SetDropTarget(self.dt)

        # Setup
        self.CreateStatusBar()

    def OnFileDrop(self, files):
        self.PushStatusText("Files Dropped")
        for f in files:
            self.list.Append(f)

    def OnTextDrop(self, text):
        self.PushStatusText("Text Dropped")
        self.list.Append(txt) 

How it works...

The framework will call the OnData method of our DropTarget when the window has received the drop data. When OnData is called, we simply get the data from our DataObject and pass it to the appropriate callback function to let our window decide how to handle the data.

All window objects have a SetDropTarget method that can be used to assign a DropTarget, so this class can be reused for almost any type of control. In the previous example, we assigned it to a ListBox and then appended the dropped data to the list in each of our callbacks.

There's more...

The PyDropTarget class provides a few more methods that can be called at different times during the drag operation. These methods can also be overridden in order to do things such as change the mouse cursor, show a custom drag image, or reject the drag object.

Methods

When the methods are called

OnEnter(x, y, drag_result)

Called when a drag object enters the window. Returns a drag result value (that is, wx.DragNone, wx.DragCopy, …)

OnDragOver(x, y, drag_result)

Called while the mouse is dragging the object over the target

OnLeave()

Called when the mouse leaves the drop target

OnDrop(x, y)

Called when the user drops the object. Return True to accept the object or False to reject it

OnData(x, y, drag_result)

Called after OnDrop, when the data object was accepted

See also

  • The Accessing the clipboard recipe in this chapter shows another way to perform data transfer between applications.

 

Two-stage widget creation


Two-stage widget creation is a way of initialzing a widget and then its UI part, in two steps. This method of object creation is used by class factories such as XRC (XML Resource) and to set extra style flags that cannot be set by using the constructor's regular style parameter. This recipe will show how to use two-stage creations to create a frame that has a special button that can be used to put it into a context-sensitive help mode.

Note

This is a Windows-specific example; other platforms do not support having a ContextButton in their title bar.

How to do it...

Here we will create a Frame subclass that uses two stage creation in order to set an extra style flag:

class MyFrame(wx.Frame):
    def __init__(self, parent, *args, **kwargs):
        pre = wx.PreFrame()
        pre.SetExtraStyle(wx.FRAME_EX_CONTEXTHELP)
        pre.Create(parent, *args, **kwargs)
        self.PostCreate(pre

How it works..

In wxPython, two-stage widget creation is actually a three-step process. First, each class that supports it has its own PreClass that is used as a factory constructor that pre-creates the object. At this point, the pre object can be used to set the extra style flag. The next step is to call Create. Create acts like the regular constructor and creates the UI portion of the control. The final step is to call PostCreate, PostCreate does the work of translating the pre object into self so that the object will appear just as if the class's __init__ method had been called normal.

See also

  • The Using XRC recipe in Chapter 7, Window Layout and Design discusses XRC.

 

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.

About the Author
  • Cody Precord

    Cody Precord is a software engineer based in Minneapolis, MN, USA. He designs and writes systems and application software for Windows, AIX, Linux, and Macintosh OS X using primarily C++, C#, C, Perl, Bash, and Python. The constant need for working on multiple platforms naturally led Cody to the wxPython toolkit, which he has used for several years. He is the author of wxPython 2.8 Application Development Cookbook, Packt Publishing and has also contributed to the development of the wxPython library. Cody is interested in promoting cross platform development practices and improving usability in software.

    Browse publications by this author
Latest Reviews (1 reviews total)
Good content and reasonable prices for ebooks. I will continue to purchase them in the future.
wxPython 2.8 Application Development Cookbook
Unlock this book and the full library FREE for 7 days
Start now