Alternative Frames in wxPython

I’m sure you know all about wxPython’s primary frame, wxFrame. It is the basis for most of your windows and will most likely continue to be. Of course, though, wxPython offers other things to put controls on. I’m sure you’re getting bored of attaching your controls to slight variations of the same exact thing. In this article, we’ll explore other frames offered by wxPython, examining what they are for, how they are used and how to change their appearance.

Let’s get started.

wxMiniFrame

Our first stop is wxMiniFrame. It is basically a frame with a short title bar at the top, rather than the large one that wxFrame displays. While entire applications will definitely look strange in a wxMiniFrame, small windows that must stay out of the user’s way can be made with wxMiniFrame. Let’s take a look:

from wxPython.wx import *

class Window ( wxMiniFrame ):

   def __init__ ( self ):

      # No suprises here

      # We only use a different class

      wxMiniFrame.__init__ ( self, None, -1, ‘A Small Frame’ )

      # Create a panel

      self.panel = wxPanel ( self, -1 )

      # Create a wxCheckBox

      self.check = wxCheckBox ( self.panel, -1, ‘This is a wxMiniFrame’, pos = ( 10, 10 ) )

      # No suprises here, either

      self.Show ( True )

application = wxPySimpleApp()

Window()

application.MainLoop()

The wxMiniFrame class features nothing else worth mentioning. It’s nothing more than a small frame. Let’s move on to something else.

{mospagebreak title=wxDialog}

We’ve looked at dialogs several times so far, but what if we need to create our own dialog? By using the wxDialog class, we are able to do so. Let’s create a dialog based on wxDialog that displays four radio buttons, asking the user to choose his or her favorite candidate. Additionally, we’ll give our dialog a parent window:

from wxPython.wx import *

# Subclass wxDialog to create a dialog

class BallotDialog ( wxDialog ):

   def __init__ ( self, parent ):

      # Call wxDialog’s __init__ method

      wxDialog.__init__ ( self, parent, -1, ‘Ballot’, size = ( 200, 200 ) )

      # Create a panel for our dialog

      self.panel = wxPanel ( self, -1 )

      # Create a label

      self.label = wxStaticText ( self.panel, -1, ‘Please choose a candidate:’ )

      

      # Create four radio buttons

      self.candidate1 = wxRadioButton ( self.panel, -1, ‘R.Q. Peters’, style = wxRB_GROUP )

      self.candidate2 = wxRadioButton ( self.panel, -1, ‘P.M. Roger’ )

      self.candidate3 = wxRadioButton ( self.panel, -1, ‘T.A. Waters’ )

      self.candidate4 = wxRadioButton ( self.panel, -1, ‘M.W. Wise’ )

      # Create a button

      self.button = wxButton ( self.panel, 100, ‘Submit Ballot’ )

      # Link a button click to a method that destroys

      EVT_BUTTON ( self.panel, 100, self.click )

      # Put everything in a wxBoxSizer

      self.sizer = wxBoxSizer ( wxVERTICAL )

      self.sizer.Add ( ( 200, 5 ), 0 )

      self.sizer.Add ( self.label, 0, wxALIGN_CENTER )

      self.sizer.Add ( ( 5, 5 ), 0 )

      self.sizer.Add ( self.candidate1, 0, wxALIGN_CENTER )

      self.sizer.Add ( ( 5, 5 ), 0 )

      self.sizer.Add ( self.candidate2, 0, wxALIGN_CENTER )

      self.sizer.Add ( ( 5, 5 ), 0 )

      self.sizer.Add ( self.candidate3, 0, wxALIGN_CENTER )

      self.sizer.Add ( ( 5, 5 ), 0 )

      self.sizer.Add ( self.candidate4, 0, wxALIGN_CENTER )

      self.sizer.Add ( ( 5, 5 ), 0 )

      self.sizer.Add ( self.button, 0, wxALIGN_CENTER )

      self.sizer.Add ( ( 5, 5 ), 0 )

      # Attach the sizer to the panel

      self.panel.SetSizerAndFit ( self.sizer )

      # Resize the dialog

      self.sizer.Fit ( self )

   # Handles a click to the button

   def click ( self, event ):

      self.EndModal ( wxID_OK )

# Create a window

class Window ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Parent Window’ )

      # Create a panel for the window

      self.panel = wxPanel ( self, -1 )

      # Add a wxTextCtrl

      self.text = wxTextCtrl ( self.panel, -1 )

      # Create the dialog

      dialog = BallotDialog ( self )

      # Show the window

      self.Show ( True )

      # Show the dialog ( AFTER we show the window )

      dialog.ShowModal()

      # Center the dialog

      dialog.Center()

application = wxPySimpleApp()

Window()

application.MainLoop()

Try to type something in the wxTextCtrl on the window while the dialog is visible. It’s not possible. This is because of the ShowModal method. The ShowModal method creates a modal dialog, causing clicks to other windows to be ignored. In most cases, this behavior is ideal. However, if you do not want this behavior, make a modeless dialog by using the Show method.

Another thing I would like to shed light on is the EndModal method of wxDialog. This exits the dialog and returns the value specified. In this case, we return wxID_OK. Alternatively, you can set the value you will return with SetReturnCode, which works with Show.

An interesting feature of wxDialog is the ability to put the dialog in help mode when using Windows. I’m sure you’ve seen this feature in other applications. By pressing a button at the top of the dialog, your cursor will change, allowing you to click controls and learn more about them. To access this functionality, we have to create the dialog differently. We have to pre-create it. Fortunately, however, this is fairly simple. Let’s create an application that takes advantage of this special help functionality:

from wxPython.wx import *

class HelpDialog ( wxDialog ):

   def __init__ ( self, parent ):

      # Pre-create our dialog

      preCreation = wxPreDialog()

      # Set the wxDIALOG_EX_CONTEXTHELP style

      # This allows for the help functionality

      preCreation.SetExtraStyle ( wxDIALOG_EX_CONTEXTHELP )

      # Create it

      preCreation.Create ( parent, -1, ‘Help Dialog’ )

      # Do post-creation

      # This is required to get our dialog working

      self.PostCreate ( preCreation )

      # Set the help provider

      # This is necessary to display anything

      wxHelpProvider_Set ( wxSimpleHelpProvider() )

      # Create a panel

      self.panel = wxPanel ( self, -1 )

      # Create a wxTextCtrl

      self.text = wxTextCtrl ( self.panel, -1 )

      # Set the help text

      self.text.SetHelpText ( ‘Nice, huh?’ )

      # Create a wxButton

      self.button = wxButton ( self.panel, -1, ‘Just A Button’ )

      # Set the help text

      self.button.SetHelpText ( ‘Yes, very nice.’ )

      # Add our controls to a sizer

      self.sizer = wxBoxSizer ( wxVERTICAL )

      self.sizer.Add ( ( 200, 5 ), 0 )

      self.sizer.Add ( self.text, 0, wxALIGN_CENTER )

      self.sizer.Add ( ( 5, 5 ), 0 )

      self.sizer.Add ( self.button, 0, wxALIGN_CENTER )

      self.sizer.Add ( ( 5, 5 ), 0 )

      # Attach the sizer to the panel

      self.panel.SetSizerAndFit ( self.sizer )

      # Resize the dialog

      self.sizer.Fit ( self )

application = wxPySimpleApp()

dialog = HelpDialog ( None )

dialog.ShowModal()

{mospagebreak title=wxWizard}

We’ve all seen wizards in all sorts of applications. They exist to make tasks easy. They are found in installers, graphics programs and even wxPython. Using the wizard module, we can create wizards to use in our applications, making them even more user-friendly. Best of all, these wizards are pretty easy to create. Here’s a very simple dummy wizard:

from wxPython.wx import *

# The wizard-related classes are here:

from wxPython.wizard import *

application = wxPySimpleApp()

# Create a wizard with the title “A Wizard”

wizard = wxWizard ( None, -1, ‘A Wizard’ )

# Create three pages for the wizard

# This is very simple

wizardPage1 = wxWizardPageSimple ( wizard )

wizardPage2 = wxWizardPageSimple ( wizard )

wizardPage3 = wxWizardPageSimple ( wizard )

# Add a label to each page

label1 = wxStaticText ( wizardPage1, -1, ‘This is the first page.’ )

label2 = wxStaticText ( wizardPage2, -1, ‘This is the second page.’ )

label3 = wxStaticText ( wizardPage3, -1, ‘This is the third and final page.’ )

# Link the pages together

# 1 to 2 and 2 to 3

wxWizardPageSimple_Chain ( wizardPage1, wizardPage2 )

wxWizardPageSimple_Chain ( wizardPage2, wizardPage3 )

# Run the wizard and display a message if it was completed successfully

# Otherwise, yell at the user

if wizard.RunWizard ( wizardPage1 ):

   dialog = wxMessageDialog ( None, ‘Wizard finished!’, ‘Finished’, style = wxOK )

   dialog.ShowModal()

   dialog.Destroy()

else:

   dialog = wxMessageDialog ( None, ‘Grr!’, ‘Not Finished’, style = wxOK )

   dialog.ShowModal()

   dialog.Destroy()

# Destroy the wizard

wizard.Destroy()

There are more advanced and flexible methods for creating wizards, too. Let’s suppose we are creating an installer with two installation modes: minimal and full. Based on the user’s selection, we want to go to different sections of the wizard. This is completely possible, but it is done a little differently from the way we did it above:

from wxPython.wx import *

# Import the wizard-related data

from wxPython.wizard import *

# Create the wizard page that allows the use to select an installation type

# We wills subclass wxPyWizardPage here

class TypePage ( wxPyWizardPage ):

   def __init__ ( self, parent ):

      # Call __init__

      wxPyWizardPage.__init__ ( self, parent )

      # Specify None for the next and previous pages

      self.next = None

      self.previous = None

      # Add a wxRadioBox that displays the two installation options

      self.box = wxRadioBox ( self, -1, ‘Instalation Method’, choices = [ 'Minimal', 'Full' ] )

   def GetNext ( self ):

      # Return a value based on the radio buttons elected

      if self.box.GetSelection() == 0:

         return minimal

      else:

         return full

   def GetPrev ( self ):

      return self.previous

application = wxPySimpleApp()

# Create the wizard

wizard = wxWizard ( None, -1, ‘Installer’ )

# Create the installation type page

type = TypePage ( wizard )

# Create a page for the minimal mode

minimal = wxWizardPageSimple ( wizard )

minimalText = wxStaticText ( minimal, -1, ‘Poof. Your application has been installed minimally.’ )

# Create a page for the full mode

full = wxWizardPageSimple ( wizard )

fullText = wxStaticText ( full, -1, ‘Bang. Your application has been fully installed.’ )

# Create an additional page

register = wxWizardPageSimple ( wizard )

registerText = wxStaticText ( register, -1, ‘Please register your product online,nor we will keep nagging you.’ )

# Link the pages that have fixed links ( minimal and full )

minimal.SetNext ( register )

full.SetNext ( register )

# Run the wizard

wizard.RunWizard ( type )

# Destroy the wizard

wizard.Destroy()

If you feel inclined to do so, you can easily add an image to your wizard by creating it like this, where “wizard.PNG” is the name of the image:

wizard = wxWizard ( None, -1, ‘My Wizard’, wxBitmap ( ‘wizard.PNG’ )

{mospagebreak title=Multiple Document Interface}

Microsoft’s Multiple Document Interface, or MDI, allows a parent window to house multiple child windows. The wxPython library supports the Multiple Document Interface, and it is simple to include it in your applications:

from wxPython.wx import *

# Subclass wxMDIParentFrame

class Parent ( wxMDIParentFrame ):

   def __init__ ( self ):

      # Call __init__ and make the window big

      wxMDIParentFrame.__init__ ( self, None, -1, “Multiple Document Interface Test”, size = ( 500, 500 ) )

      # Create a menu that allows us to open new windows

      windowMenu = wxMenu()

      windowMenu.Append ( 1, ‘Open New’ )

      # Create a menu bar and add the menu

      menuBar = wxMenuBar()

      menuBar.Append ( windowMenu, ‘Options’ )

      self.SetMenuBar ( menuBar )

      # Catch a menu click

      EVT_MENU ( self, 1, self.openNew )

      self.Show ( True )

   # This method will add a window

   def openNew ( self, event ):

      # Create a child window

      child = wxMDIChildFrame ( self, -1, ‘MDI Child’ )

      # Give the child a panel

      child.panel = wxPanel ( child, -1 )

      child.panel.SetSize ( child.GetClientSize() )

      # Add a label

      child.label = wxStaticText ( child, -1, ‘I am only a child.’ )

      child.Show ( True )

application = wxPySimpleApp()

Parent()

application.MainLoop()

Although the idea sounds complicated at first, wxPython makes it all extremely easy, requiring only a handful of code to create something basic like we did. Notice, too, that a “Window” menu is added to our application, giving us organization and navigation options.

The Multiple Document Interface is useful in some applications. Each window has the potential to be very different from the next window, too. It’s all up to your creativity.

Conclusion

The wxPython library offers more frames than just wxFrame. These frames are geared toward specific things, such as modal dialogs, modeless dialogs, wizards and organizing child windows within a large parent window. They enable you to extend your application’s capabilities with little effort, and, at the same time, give you a variety of complex options. They can be excellent additions to your applications, benefitting the end user and, in turn, you –- the developer.

Google+ Comments

Google+ Comments