Creating GUI code for Padre - A walk through a new feature

Alias on 2009-09-17T18:15:39

One of the most common problems people who have only recently arrived on the Padre team have is the creation of Wx code that, well, doesn't suck ass.

The API is rather opaque, badly documented (for now) and it's behaviour isn't always entirely obvious.

So when Sewi, who's been trying to make headway on a Padre::File API (for doing remote SSH/FTP/etc file operations), demonstrated quite possibly the worst textbox entry dialog ever seen, he was more than happy for someone else to produce a better one.

Since it's a relatively straight forward job, I thought that it might be a good idea to demonstrate how to do Wx GUI code in a reasonably efficient and decent looking way.

You can follow the set of commits, and see graphical diffs of each, at the following:

http://fisheye2.atlassian.com/changelog/user/author=adamk,date=2009-09-18T00%3A00%3A00/padre

The implementation starts at commit 7970.

I start by mocking up the layout in wxGlade. The Perl code generated by this Python application is... well... questionable. While it technically works (thankfully) you'd struggle to build a scalable application using the style of code it produces.

HOWEVER, once you get past the horrible boilerplate, what it does generate is pretty much perfect code for creating the various widgets and sizers. This is the most verbose and annoying part, so having something to copy and paste liberally from makes a huge difference.

In commit 7971 I drop in a basic class skeleton for a dialog. This is just a cut and paste job from the Find dialog, and does nothing more than create the dialog itself, sucking in a role that simplifies a few things for dialogs that are direct children of the main window.

Commit 7975 sucks in the code from wxGlade for the actual form components. We do this first because the layout doesn't matter until we have the parts that actually do work in place.

Unfortunately, the code doesn't actually work, because the wxGlade code uses wxCONSTANT values directly and Padre does not. It turns out exporting 5000 constants into 300 classes results in a rather ugly memory overhead, so in Padre we use Wx::wxCONSTANT directly.

So in commit 7976 I drop in a temporary "use Wx 'everything';" so the constants work.

Commit 7978 drops in the wxGlade layout code, which should pretty much just work as is.

Some of the objects use horrible auto-generated "sizer_1" variables. But oddly, I find for some of the stuff like the border sizers it doesn't really matter that much, since there's really not much better meaning you can use instead.

And now to the clean up.

First up, wxGlade likes to make more things accessors than are really necessary. So in 7980 we convert them over to regular lexicals that will just exist in the C heirachy of the application, not the Perl heirachy.

Next, in commit 7983 I'll separate, comment, group and layout the sizer code into something that's actually maintainable.

Note that I'm doing pretty much all of this without actually running anything, although I do bother to at least run the test script which checks that the code compiles. We'll get to the running of code later.

But in anticipation of that day (and now that all the cut and pasting is done) we do a standardisation pass.

In commit 7989 we finish converting all the wxCONSTANTS to Wx::wxCONSTANTS, and add in the standard Padre copyright fragments to the Debian people don't get annoyed with us. :)

Now to the actual functionality.

Copy/paste again from the Find dialog gives us a working cancel button in commit 7989 and a working OK button in commit 7999.

Having reached this point, we pause briefly to watch azawawi blatantly steal commit 8000 and quietly loath and envy him.

Anyway, onwards again.

So now we can start to actually run the code. And of course, as soon as I tried to do that I discovered that the dialog really should run modally. So in commit 8005 we do some refactoring to make the dialog modal (and to give it a top level easy to use method for starting and stopping the dialog).

Now, finally, we start running it for real. So the final commit 8011 is debugging, plus replacing the old dialog in the main window class.

The result? A great looking "Open URL" menu entry that does absolutely nothing at all other than spit out a "this doesn't work" message box.

But then that's the main point. By making a working chunk of UI ready for Sewi to step in and take over, I've removed a major obstacle from his completing the feature that he REALLY cares about.

And hopefully this entry can serve as something of a template for others needing to create simple to medium complexity gui code.


That doesn't sound much better than the "hard" way

TeeJay on 2009-09-18T14:13:35

.. that I blogged previously

Maybe it's just me, but I find GUI Designers cumbersome, much nicer to play around with demos and samples - no boiler plate, learn about the API instead of leaving a trail of boilerplate and cargo-culted code.