wxPerl Primer

This primer highlights the key differences between wxPerl and wxWidgets. The main documentation for the wxPerl API is the wxWidgets manual for the installed version of wxWidgets. The primer contains the content of Mattia Barbon's original online wxPerl Manual with a few minor updates.

Constants

wxWidgets uses several constants (like wxWHITE or wxSUNKEN_BORDER), both to specify option values and to provide some useful constants. In wxPerl, before you use a constant, you must import it in your namespace. This is done (as usual) with the 'use' statement.

    use Wx qw(wxWHITE);
    use Wx qw(wxSUNKEN_BORDER wxBLUE wxSTANDARD_CURSOR);

When you write a real program, however, importing 'by hand' all constants you need one by one will be annoying, so there is a shorthand method: instead of enumerating the constants, you may use a colon followed by a tag specifying the constants you want.

    use Wx qw(:window :textctrl);
    use Wx qw(:pen);
    use Wx qw(:image wxSTANDARD_CURSOR);
    use Wx qw(:everything);     # really quick and dirty

The tags that are defined will depend on your version of Wx and the version of wxWidgets you are using. The following code will provide a list of the tags for your current installation.

#!/usr/bin/perl
use strict;
use warnings;
use Wx qw( :allclasses );
my %seen;
my $content;
my $taglist;
for my $tag ( sort keys(%Wx::EXPORT_TAGS) ) {
    next if $tag =~ /^(everything|all)$/;
    $content .=  qq(\n:$tag\n);
    $taglist .= qq(\t$tag\n);
    for my $exp (@{ $Wx::EXPORT_TAGS{$tag} }) {
        $content .=  qq(\t$exp\n);
        $seen{$exp} = 1;
    }
}

print qq(TAGLIST\n);
print $taglist;
print qq(\nTAGINDEX\n);
print $content;
print qq(\nNO TAGS\n);
for my $exp (@{ $Wx::EXPORT_TAGS{everything} }) {
    print qq(\n$exp) if !$seen{$exp};
}


Interface strategy

Classes, static methods and global functions


In wxPerl all classes are named Wx::Something, so wxFrame is really Wx::Frame. Static methods are called Wx::ClassName::Method(). Global function named wxFunction() are accessible as Wx::Function().

Polymorphysm


In wxWindows some methods (like FindWindow) return a pointer to a base class, and the programmer is obliged to explicitly cast the object to the right type. wxPerl does this for you, so you do not need to worry for that.

Overloaded methods


Where is applicable, wxPerl uses overloaded method names just like wxWindows, when this is not feasible, the difference is documented in the following pages (and will be documented in wxWindows manual, in the future).

Functions modifying their parameters


Some wxWindows functions modify their parameters; though in Perl this is possible, wxPerl avoids this practice, and such methods are always modified to take less parameters and return a Perl array.

Object destruction


In Perl memory management is a matter for the perl interpreter; however, since we are interacting with an external C++ library, there are some problems.

In wxPerl there are three kinds of objects
  1. objects destroyed 'by hand' by the program (using the Destroy method)
  2. objects destroyed automatically by wxWindows in some situations, sometimes they too need to be destroyed by hand
  3. objects destroyed when no more referenced (as Perl does usually)
  4. other objects you do not need to worry about
First category
  • Wx::Log and derived classes
  • Wx::Mask
Second category
  • all Wx::Window/Wx::Sizer/Wx::LayoutConstraints/Wx::Menu* and derived objects: when they are childs of some other window/sizer, are destroyed automatically when the paent itself is destroyed. When they have no parent they need to be destroyed explicitily.
  • all Wx::ImageHandler/Wx::BitmapHandler-derived objects: if you have added them to the handlers (using AddHandler, they are automatically destroyed, otherwise you need to destroy them explicitly
Third category
  • Wx::*Event, Wx::App, Wx::Bitmap, Wx::Brush, Wx::*DC, Wx::Colour, Wx::Cursor, Wx::EvtHandler (user objects derived directly from Wx::EvtHandler), Wx::Font, Wx::Icon, Wx::Image, Wx::ImageList, Wx::Locale, Wx::Pen, Wx::Point, Wx::Rect, Wx::Region, Wx::Size, Wx::ToolTip
Fourth category
  • Wx::ClassInfo, Wx::IndividualLayoutConstraints

Event handling

Event 'macros'


wxPerl can't use static event tables for event handling, but the constructs it uses are similar to wxWidgets ones; in particular wxPerl uses the same names for 'event macros'; the key differences are:

in wxPerl these are regular subroutines exported by the Wx::Event module
they take one additional first parameter: the Wx::EvtHandler object that must handle the event
so in a program you may use:

    package MyClass;
    # ....
    use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
    sub new {
    # ......
        # pay attention to the additional parameter
        EVT_CLOSE( $this, \&OnClose );
        EVT_BUTTON( $this, $ID_MYBUTTON, \&OnClick );
    # .....

In wxPerl, if you do not need to know the id of a control (you will need it for FindWindow and similar functions) you may pass -1 or wxID_ANY to the constructor, and pass the object itself as the id (wxPerl will automatically do a GetId() on the object).

Event handlers and exceptions


Please note that event handlers are not exception safe. This means that if you die() (or croak() or confess() or even exit()) from an event handler, your program will most likely crash. Solution: don't do that, or if you are using exceptions, handle them in the handler. You might like to use the Try::Tiny module.

  use Try::Tiny;

  sub OnFoo {
      my($self, $event) = @_;
      try{
          # code that might die()
      } catch {
          Wx::LogError( $_ );
      };
  }


API Tips

Wx::Point and Wx::Size


Anywhere you can pass a Wx::Size or a Wx::Point object, you can also pass a 2 element array reference (like [2,3]). This saves some typing and is also a bit faster.

Client Data


Anywhere you can pass client data you can also  pass any scalar.

Embedding Perl and wxPerl

Using wxPerl inside a wxWidgets program



Running wxPerl code inside a wxWidgets program has some caveats. There are three senarios:

  1. a single long-running Perl interpreter
  2. multiple short-lived Perl interpreters
  3. multiple simultaneous Perl interpreters

Single long-running Perl interpreter


This section applies when the lifespan of the interpreter is the same as the application lifetime. There is no (known) caveat for this situation.

Multiple short-lived Perl interpreters


In this case a perl interpreter is continually constructed, used to run some code and then destroyed. The typuical structure of Perl code should be:

package MyFrame;
# ...
package MyApp;
# ...
package main;
my $app = MyApp->new;
$app->MainLoop;

This code can't rely on the usual rule that the main loop exits when no more windows are open, because the main application window will always be open! The code must manually keep track of when to exit.

For a single-window application this could be implemented as:

EVT_CLOSE( $frame,
  sub {
    my( $self, $event ) = @_;
    $Wx::wxTheApp->ExitMainLoop;
    $event->Skip;
  }
);

Multiple simultaneous Perl interpreters


This is not supported, sorry.