Please note that this tutorial is still in alpha. Comments and additions welcome.
Making Perl look good on Windows -
Win32::GUI and The GUI Loft tutorial
The Basic Structure of GUI Programs
Designing the Window with The GUI
Loft
Controls - methods and properties
The program we are about to study is an actual example of Perl's whipuptitude.
Sometimes we play poker at work. Mostly tournament unlimited Texas Hold'em (http://www.casino.com/poker/Texas-Holdem.html). In the game, there is a pair of forced bets that move between the players to keep the game interesting. These are called "blinds", and over time they increase.
So to avoid the horrible burden of keeping track of which blind level we're playing at, I wrote this program.
So there is a blind level with a small blind and a big blind. We'll play at this level for a number of minutes, and then the program plays a sound before entering the next blind level.

The program has two modes. First we set up the blinds. They increase over time, so there is a little logic to make this easier. When adding a blind level, the previous big blind value is entered in the new small blind TextField. Also, the big blind is almost always double the small blind. So when the user tabs from the small blind TextField, the small blind value x 2 is entered in the big blind TextField.
When we're done with the setup we click Start.

Now the program shows the current blind level and the time left to play on this level.
This version of the program doesn't do anything else.
The most notable missing features we noticed was that it would be useful to be able to remove or edit a blind level, and that even though the blind level is pretty visible, it's still too small to look at from a distance, like at the end of the poker table.
Also, we can't pause the game, but that has actually never been needed.
These are things we'll add in the next version, while taking the opportunity to introduce a few new Win32::GUI and The GUI Loft features.
The program consists of a GUI (a single Win32::GUI::Window window) and an application class (App::VenetianBlinds) with it's helper classes (currently only App::VenetianBlinds::Level).
App::VenetianBlinds is both responsible for the entire application (coordinating the GUI and the app) and the basic domain logic for the blind levels and that stuff.
The GUI layer knows about the application object and can invoke methods on it. The application object knows about the window, and can inspect it (getting control values) and manipulate it (set control values).
#!/usr/local/bin/perl -w
use strict;
use Win32::GUI;
use Win32 ();
use Win32::GUI::Loft;
use Data::Dumper;
use lib "../lib";
use FontInspector;
We start off by using a few modules. I shouldn't have to mention this, but I will just to be sure: using warnings (-w) and strict is a pretty clever thing to do. If you think you're so clever that you don't need them, you're most likely wrong.
Now,
about the modules:
Win32::GUI is the window toolkit. Win32 is only used for the alertbox. Win32::GUI::Loft is The GUI Loft runtime classes.
The only thing to out of the ordinary is the Win32 module.
use Win32 ();
The empty list is for not importing any symbols. If we hadn't specified the empty list, some symbols would have clashed with the Win32::GUI module.
use lib "../lib";
use FontInspector;
Let's skip this for a while. It's used when creating the window, but it's beyond the basic stuff we're talking about right now.
The structure of a GUI program may be a little bit different from what you are used to.
GUI programs are usually event based. That means that we first set up the windows and event handlers (sub routines), and then we enter the main loop. In Win32::GUI, the main loop is called
Win32::GUI::Dialog()
After calling this sub we don't really see the program flow anymore, because it's running inside the main loop. We just wait for things to happen, and when they do, Win32::GUI will call the event handlers we have set up. Things that happen can be user interaction, like clicking on buttons, moving the focus to or from a control, or selecting a menu item. It can also be things activated from within Win32::GUI, like a Timer control firing off an event.
There are two kinds of event handlers in Win32::GUI. There are ordinary subs that follow a name convention, and the new event model, aptly acronymized NEM. In this program we'll use the plain old subs.
For example, I may have a window with a button called btnOk. Buttons have a predefined event called Click which is automatically invoked when the user clicks (or otherwise "activates") the button. If I have a sub called btnOk_Click, then that's the event handler for this button's Click event, and the sub will be called. If there is no such sub, nothing happens when the button is clicked.
Before we leave the subject I'd just like to mention that you don't have to use the Win32::GUI::Dialog provided by Win32::GUI. The point of having a main loop is to handle events that pass through the application. This can also be accomplished by repeatedly calling Win32::GUI::DoEvents() in a loop of your own.
This can be used if there is another framework with it's own main loop. I haven't tried it, but in theory this would work with POE or even Tk (if you would like to use the Win32::GUI Taskbar icon in a Tk program).
Another situation where DoEvents is useful is inside an event handler where you do something time consuming. If you just let the program run for a second or two before returning from the event handler, events won't get handled and the GUI will be frozen and unresponsive during that time.
If what you are doing is performed in a loop, make sure you call Win32::GUI::DoEvents() at regular intervals. If there is no loop, investigate if there is a callback interface from where you can do this. An example of this is is the LWP::UserAgent->request() method, which is demonstrated in the TGL demo program FetchURL (look in the Demo directory).
The first part of the program isn't very complicated. The sub main() is called at the end of the file.
(Why call main() at the end? So that all code in the packages are run before we start the program. If the packages had been in their own files and used, that would have happened at compile time, but since we have everything in one file this is how we must do it.)
sub main {
my $fileWindow = "resource/blinds.gld";
my $oDesign = Win32::GUI::Loft::Design->newLoad($fileWindow) or
die("Could not open window file ($fileWindow)");
$oDesign->objApp( my $oApp = App::VenetianBlinds->new() );
my $oWin = $oDesign->buildWindow(undef, FontInspector->new())
or die("Could not build window ($fileWindow)");
$oApp->oWin($oWin);
$oWin->Show();
$oWin->tfSmall->Text("25");
$oWin->tfLarge->Text("50");
$oWin->tfMinutes->Text("15");
$oWin->tfSmall->SetFocus();
Win32::GUI::Dialog();
return(1);
}
Before we can enter the main loop Win32::GUI::Dialog at the end of this sub, we need to set up the window.
It is possible to create the window programmatically by writing Win32::GUI code. Some people like that better, but I certainly don't. I find it immensely more productive to use a visual tool to design a graphical user interface.
The window definition is stored in a file with a .gld (Gui Loft Design) extension. It was created with the window designer The GUI Loft, which makes it a lot easier to design Win32::GUI windows and dialog boxes. But even if you use The GUI Loft (TGL), there is still need for a lot of Win32::GUI coding to be done. TGL is only used for designing the window and building it at run-time. Everything else is up to you.
my $fileWindow = "resource/blinds.gld";
my $oDesign = Win32::GUI::Loft::Design->newLoad($fileWindow) or
die("Could not open window file ($fileWindow)");
Okay, back to the code at hand. First we create a Win32::GUI::Loft::Design object by loading the .gld file. Note the error handling (or die(…)).
But, isn't just dying like that a bit impolite to the user? Well, what I haven't showed you yet is the call to main(), which looks like this:
eval { main() };
$@ and Win32::GUI::MessageBox(0, "Error: $@", "Venetian Blinds");
If an exception is thrown and makes it all the way up the call stack to this location, it is reported in a standard Windows message box. This is important, because this program will not be running as a console application in production. That means the user won't even see the error message being printed unless we do something like this. During development, the program is usually run from the ordinary command line interface so you can see print() and warn() output. We'll see how to run the program as a true Windows program (without a console window) later on.
$oDesign->objApp( my $oApp = App::VenetianBlinds->new() );
There is a class called App::VenetianBlinds that contains the main application logic. We create an object of that class, and stuff it in the objApp property of the Design object we just created. The Win32::GUI module makes it somewhat difficult to avoid using globals to get to your windows throughout the program, and the objApp property is a workaround to that problem. Later on, inside the event handlers, we'll use the objApp property to retrieve our application object.
my $oWin = $oDesign->buildWindow(undef, FontInspector->new())
or die("Could not build window ($fileWindow)");
$oApp->oWin($oWin);
Finally we create a new Win32::GUI::Window object from the Design and assign it to the application object. It will be useful for the application to know about the window object.
Ignore the parameters to buildWindow at the moment. They're used for customizing the window, and we'll get to that later.
$oWin->Show();
$oWin->tfSmall->Text("25");
$oWin->tfLarge->Text("50");
$oWin->tfMinutes->Text("15");
$oWin->tfSmall->SetFocus();
By default windows aren't visible, so we'll have to Show() it. If you have many windows in your application, it's pretty common to create them all at program start, but only Show() them when they are used. And they usually aren't destroyed but hidden when they aren't in use.
The next lines are examples of accessing controls on the window and setting the Text property. Finally we make it easy on the user by moving the focus to the proper control.
All these are Win32::GUI methods which you can read about in the documentation at XXX.
If we look at the main window in The GUI Loft we can see all the controls in our window winBlinds. Usually it's very convenient to have TGL with the window open while coding, because you'll need to know the names of controls, maybe do a slight tweak to the design or add more controls while coding.

Win32::GUI creates accessors for all the controls in the window so that you can use for form:
$win->controlName->MethodOrProperty()
Win32::GUI::Dialog();
return(1);
Finally!
So this is the beginning of the actual program. But how does it end? Does Dialog() ever return? After all, there is a return statement after it…
Actually, yes, the main loop can end. This happens when an event handler returns –1. We'll get back to event handlers, what events there are and how to work with them in a little while. But first, let's see how that .gld file came to be.
· Start The GUI Loft and open the bin/resource/blinds.gld file, either with the File | Open… menu, or by drag-n-drop onto any TGL window.
It's probably most helpful if you open it now and try things out in the program as we discuss them.

The Buttons, Textfields, etc are called Controls in Win32::GUI. In other window toolkits they are known as Widgets.
You can add new controls to the Design window (where you lay out the Window WYSIWYG style) by clicking one of the buttons in the Tool window

The control will snap to an invisible grid of (default) 4 x 4 pixels. That's a pretty useful setting which gives you enough freedom to put things where you want them while still making it easy to make them line up with each other.
When a Control is selected, you can use the mouse to move and change size or bring up the Right-Click menu.
· Read more about using the mouse and keyboard in the User Manual
· http://www.bahnhof.se/~johanl/perl/Loft/manual.html#manipulating_controls
The User Manual is also available from within The GUI Loft, in the Help menu.
I find it useful to try things out by just playing around and see how things look. Sometimes I have sketched the dialog on a piece of paper before, but adding the controls to the window often makes things clear what works and what doesn't, and sometimes you see new possibilities.
If you want to get feedback from actual future users of your application, giving them a nice slick dialog is sometimes too good. They don't feel like they can change anything if it looks so… finished. So sometimes it works better if you just show them the sketch, sometimes they feel relaxed enough if you show them how easy it is to change the layout, or even let them do it themselves on your computer.
The Properties window contains the properties available for the selected Control or Controls. It's pretty straightforward, with only one slight gotcha:
When you edit any value, make sure you press Enter to make it stick.
· Read more about the Properties window in the User Manual
· http://www.bahnhof.se/~johanl/perl/Loft/manual.html#the_properties_window
But, which Properties are there for a certain Control? And what do they mean?
This is sparsely documented in the Win32::GUI docs, available from within The GUI Loft. Sometimes you'll have to Google or look at a Win32 site, especially if you go slightly beyond what Win32::GUI can provide.
why
shortcut
global namespace
why
both menu and right-click
Docs on selected control
Win32::GUI docs
Why
howto
how to think
limitations
in the next section
tabstrips
clusters
Documentation
Naming
the NEM
Return values
=head1 WIN32::GUI EVENT HANDLERS
=head2 winBlinds_Terminate()
Terminate app.
=cut
sub ::winBlinds_Terminate { my ($oWin) = Win32::GUI::Loft::tglApp("winBlinds") or return(1);
#Just exit
return(-1);
}
Documentation
Fonts
Separate GUI and app
GUI wrapper vs coding to the actual GUI, different GUI toolkits etc.
setWindowState
How to get rid of the DOS box
wperl
associate plw
Perl programs cant' be compiled, not in the usual sense anyway, where the source is turned into machine code. But they can be compiled/packaged into a single binary with no external dependencies. That is very useful because installing Perl, not to mention the entire chain of dependencies your program requires, is a definite show stopper for ordinary users.
And the most common user of your GUI programs is probably a non-technical person who is only interested in solving her problem, not downloading and installing a lot of other complicated stuff. Even other developers in your organization who aren't fluent in Perl will think it's difficult or cumbersome to do all this for the first time. That doesn't make Perl look good. Perl stuff should just work. So we'll have to do it for them.
Fortunately there are a number of good solutions to this problem.
PerlApp is a commercial product from ActiveState. It's mature, flexible and works well. If your company uses Perl, the Perl Dev Kit is an obvious purchase.
<example>
It would work perfectly fine to zip the newly created .exe file along with the .gld files and other stuff your program needs. People could unzip the program and run it. But to complete the illusion that this is any ordinary Windows program, let's create an installer which will install the program on the user's computer, create a shortcut in the Start-menu etc.
There are a number of competent installer programs available for free.
This is beginning to look like an actual project, so we need to start treating it like one. Version Control is one of those things that are absolutely required in a team environment, but still very useful when programming on your own.
In this tutorial we'll use Subversion because it's free and pretty easy to use. Alternatives? CVS – Haven't tried it. SourceSafe – Avoid. No really. Don't go there.
SVN,
TortoiseSVN
We create a new directory for the repository: …/Repositories/VenetianBlindsRep and create the new Subversion repository.

Let's go to the existing source directory. First we make a backup of the entire directory tree we want to import. Let's just make sure SVN doesn't break anything. It's not paranoid if it's beta. Or just out of beta. Or whatever.

The browse button isn't very useful, so just copy the repository path from the Explorer and add "file:///".


Now the files are in the repository. But first we need to Checkout the files to the same location before starting to work with them. Rename the VenetianBlinds directory to VenetianBlinds_old and create a new empty directory VenetianBlinds. Select Subversion | Checkout…



Now we have three instances of all files: the original backup, the renamed imported directory, and the recently checked out version. When everything looks ok, move the two first directories to a safe place (if you're paranoid/defensive), or delete them.
Notice the nice symbols on the file and directory icons.

Link to the Subversion Book