Desktop Application Development with PHP-GTK
What is PHP-GTK?
PHP-GTK 2 is out, and with it, a fantastic means for PHP
developers to build useful, reliable cross-platform desktop
applications. In this tutorial, I’ll show you how to get up and running
with PHP-GTK in no time and build your first desktop application.
Before you continue, have a brief read through my previous article on building desktop applications in PHP,
for a bit of background to this tutorial. PHP-GTK is a PHP extension
that provides bindings for the GTK window system. GTK, or Gimp ToolKit,
provides a collection of visual elements called "controls" which you
can use in your PHP application – essentially, these provide the
visuals. The PHP bindings from PHP-GTK allow us as developers to
manipulate these controls programatically, and from within PHP.
This is all very well, but what does it mean for you? In short, you
can take all your existing PHP skills, and reuse your existing PHP
code, but build complete desktop applications. In my previous article,
I elaborate on the benefits of desktop applications and why you might
want to build them; but consider being able to achieve everything Flash
objects and Java applets can without having to learn a new language.
Getting started with PHP-GTK
Binary files for the PHP-GTK extension are available, but the best way to get started under Windows is to grab a copy of Gnope,
an all-in-one PHP-GTK environment installer, similar to XAMPP. If your
development machine runs Linux, you may need to get a copy from CVS and
compile from source – see the PHP-GTK website‘s
download page for further details. I’ll try and follow along with
guidance for users of Linux, but I’ll focus on Windows here.
I’ll be working with Gnope 1.5.1′s copy of PHP-GTK, but the code
should function on any recent PHP-GTK 2 build, including the betas.
Linux users, remember to change references to "php.exe" with "php"
or the path to your PHP binary, then skip over to the next section -
"Your first PHP-GTK application".
Head to Gnope.org, download the installer and open it. You should see this screen:
Follow the prompts; when it comes to choosing options, make sure you
select the "PHP Extensions" and "PHP-Gtk2 Demo Scripts" options; others
aren’t necessary. Move to the next screen and choose where you want to
install; I recommend the default C:Gnope for simplicity, as I’ll be
referring to it throughout the article.
Your first PHP-GTK application
Load up your favourite text editor and bash out the following:
$wndMain = new GtkWindow();
$wndMain->connect_simple('destroy', array('gtk', 'main_quit'));
$lblHello = new GtkLabel("Hello World!rnBuilt using my very first PHP-GTK script!");
$wndMain->add($lblHello);
$wndMain->show_all();
Gtk::main();
Save the file as "helloworld.php", either in C:Gnope (Windows) or
your home directory (Linux). (This is merely for consistency throughout
this tutorial; It doesn’t actually matter where you save the file.).
Open up a command prompt / terminal (Start > Run > "cmd" on
Windows) and switch to the directory where you saved the file – "cd C:Gnope" (Windows) or "cd ~" (Linux). Execute "php helloworld.php" and you should see something like this:
It isn’t terribly attractive, but it isn’t too bad for six lines of code either.
(If you get a fatal error, "call to undefined function
connect_simple()", you’re using PHP-GTK 1. Grab the binaries for /
compile from source PHP-GTK 2 and try again.)
Play around with the window a little bit. Try resizing it:
So, what’s going on here? Let’s take a look back at the code:
$wndMain = new GtkWindow();
$wndMain->connect_simple('destroy', array('gtk', 'main_quit'));
First, this section creates a new GTK window. The GTK toolkit is
comprised of a variety of different controls, from text boxes to drop
down menus and just basic text labels. A window itself is (in a way)
one of these controls, and handling it somewhat generically gives us a
lot of flexibility. GTK works with containers, inside of which you can
place controls, and a window is a special type of container.
Most items have some special events, and GTK calls those events
"signals". Just like you can bind to events in Javascript, you can
assign callbacks for signals. In this case, the "destroy" signal -
called when the user clicks the close button on the window – links to
the callback gtk::main_quit(), which will handle garbage collection and
allow us to end gracefully. See this documentation page on signals for more details.
$lblHello = new GtkLabel("Hello World!rnBuilt using my very first PHP-GTK script!");
$wndMain->add($lblHello);
Now we get to start working with controls. We’ll start with a label,
a simple non-editable text field. Where in HTML you can output text
anywhere and control it via CSS elsewhere, desktop applications are a
little more strict.
To work with controls in PHP-GTK, we use classes. When we create a
new object of a control class, it’s stored in memory but doesn’t
actually appear anywhere – because GTK doesn’t know where we want it to
appear. We then need to go back to our window and instruct PHP-GTK to
add the label to the window. PHP-GTK takes care of the rest; when we
resize the window, it simply centers the label within the container, no
messy Javascript or unreliable CSS hacks.
$wndMain->show_all();
Gtk::main();
Finally, we tell GTK to actually display the window – otherwise it
just sits in memory. Once we’re done, however, we need GTK to take over
and just wait. Unlike a web-based script, which continues processing
and finishes, to maintain the state of a desktop application window and
wait for user input we need some kind of an infinite loop or
wait-for-event system. While I won’t go into details of internals here,
suffice to say a call to Gtk::main()allows PHP-GTK to take over and we launch into our application.
So how powerful is this PHP-GTK?
We just finished writing hello world in six lines of code, and
haven’t got anything terribly interesting yet. So what is PHP-GTK
capable of? If you installed Gnope, you’ll have a new folder in your
start menu, "PHP-Gtk2". Find it and load up "Applications". You should
see the Gnope application launcher:
Scroll down and double-click on PHP-Gtk2 Demos. The Gnope folks have
compiled some demonstrations of PHP GTK, including use of the controls
and some interesting tricks. Each demo has a brief summary, a
functioning inline demo and the source code that powers it. For
example, here’s the combo box example:
You aren’t limited to plain old interfaces, either. Drawing is also an option:
Leaving the demos for a moment, building entire applications in PHP-GTK is not out of the question:
Of course, when you reach this level of complexity there are other
considerations to take into account, such as performance when working
with highly complex interfaces. This Notepad was very snappy, but only
on my recent Centrino Duo laptop; running on an old PIII box with
Windows 2000 was a somewhat delayed-response affair, and even slight
lag in simple operations such as copying and pasting can frustrate
users.
Building a real application in PHP-GTK
We’ve gone through all the usual Hello World, and taken a look at
what PHP-GTK can do. But let’s do this for real; PHP has a lot of
useful inbuilt functionality, so let’s take some of it and put it in a
useful desktop mini-app. An MD5 hash is always useful, and the md5() function is simple enough, so we’ll build a simple application to take a string and generate its MD5 hash.
Interface
When building any desktop application, you should always plan the
interface before you start development. In this case, all we need is a
text box and a button to click. We can reuse the textbox for the MD5
hash, just for simplicity’s sake, although in a production application
you might want to put it in an alert box. This is the tricky part of
PHP-GTK.
Bashing out code is all very well, but when we develop applications
in PHP-GTK we need to think about how the window will be laid out. A
standard GtkWindow is what we call a bin container, or a container that
can only have one child. That is, you could put a label in it, or a
text box, but not both. In our hello world demonstration, we only had
one label, so we could put this directly inside the window, like so:
As you can see based on this (oversized) diagram, we have a
GtkWindow with a single child control, the GtkLabel. But we can’t just
pack labels inside windows together, as a window is a bin container.
Instead, we can use horizontal and vertical boxes, as well as tables. A
special button box is also available just for buttons. PHP-GTK’s
different containers all use classes, and in true PHP style make use of
full OOP with liberal extending of classes. Navigate the subclass tree
from the GtkBox section of the documentation onwards to see what sort of containers are on offer.
Our text entry for the string to be MD5 encoded can appear right
next to the button to encode, so we don’t need any complex structures,
just a horizontal container. Inside this horizontal container we’ll put
a text box and button. Think of it like this:
I find that putting together visual diagrams similar to this is very
helpful when planning interfaces to be implemented with pure PHP-GTK.
Some simple HTML with inline CSS thrown together in Firebug’s realtime
editing allowed me to quickly put together these simple yet effective
diagrams. Each box is a div with a border, and each label a span inside the div with position: relative
to move it up to the border. Of course, there’s an alternative to all
this complicated wireframing which I’ll explain in a moment.
So, we’ve now worked out what our application is going to look like. Time to get coding!
And that alternative to all this tricky interface diagramming? Well,
here it is, and you’re going to love it. First, check out the screenshot.
All the controls / containers / windows / etc. in an easily-accessible
panel on the left, drag and drop application design, tree hierarchy to
represent all these parent-child structures? We call it Rapid
Application Development, and I’m sure you can guess why! Head over to the official Glade site for more details, and check out this tutorial on how to use Glade with PHP-GTK.
Coding the application
Developing the application is very easy. As we’ve covered the hello
world example in detail, I’ll launch into the code here and explain the
important points as we go along.
First, we need to create our window:
$wndHash = new GtkWindow();
$wndHash->connect_simple('destroy', array('gtk', 'main_quit'));
Nothing special here, almost identical to the above. We’ll call our window variable $wndHash
to avoid conflicts in case we need to run multiple PHP-GTK applications
in the same execution. Next, we start creating controls:
$txtString = new GtkEntry();
$btnEncode = new GtkButton('Encode');
For our textbox, where the user will enter a string to be hashed, we’ll use a GtkEntry object.
A GtkEntry is a fairly standard single-line text entry field, just as
you’d expect from, say, your Firefox search bar (besides the search
functionality, of course). We also need a button, and a GtkButton object is about our only option here. Next, we need to connect up a signal so that our button can actually do something once clicked:
When we wanted to connect the "destroy" signal, we only passed two
parameters – the first was the signal name, "destroy", and the second
was the callback, Gtk:;main_quit(). However, our callback may need to
be given a reference to the objects on the form, and instead of messy
global variables, the signal connect methods give us an easy way to
pass parameters to the callback function. In this case, our callback
function is encode(), and we pass it $txtString from the
current scope, which it will then take a reference too. We can pass as
many arguments to the callback function as needed; just keep adding
parameters to connect_simple().
Of course, we also need to write this callback function encode(). We have a reference to the text box, which, as an instance of GtkEntry, has the methods get_text() and set_text(). All we need to do is work out what is in the text box, run it through md5() and put the hash back into the text box. Pretty simple stuff:
function encode(GtkEntry &$txtString)
{
$md5 = md5($txtString->get_text());
$txtString->set_text($md5);
}
We now have our window and the objects that will be on it ready. But
we still need to manage layout! Remember that wireframe diagram of the
interface we put together? Well, constructing that in code is easier
than you think. We first need a container, a GtkHBox (Gtk Horizontal
Box). We then need to put inside it first the text box, and then the
button. A GtkHBox has an (inherited) method pack_start() (also pack_end())
which tells it to pack in another object inside the container from the
start of the container. For a horizontal box, the start is the left. If
we used the end counterpart, it would start packing in from the right.
Therefore, if we put in first a textbox, and then a button, we’ll get a
horizontal box filled with a textbox on the left and a button right
next to it, ready to put inside our GtkWindow (after a while, you’ll
start to think of application windows by their PHP-GTK class names
too!).
$ctrMain = new GtkHBox();
$ctrMain->pack_start($txtString);
$ctrMain->pack_start($btnEncode);
$wndHash->add($ctrMain);
With that all ready, it’s time to put all this inside our GtkWindow, hand over to Gtk::main(), and away we go!
$wndHash->show_all();
Gtk::main();
Here’s the final code:
$wndHash = new GtkWindow();
$wndHash->connect_simple('destroy', array('gtk', 'main_quit'));
$txtString = new GtkEntry();
$btnEncode = new GtkButton('Encode');
$ctrMain = new GtkHBox();
$ctrMain->pack_start($txtString);
$ctrMain->pack_start($btnEncode);
$wndHash->add($ctrMain);
$wndHash->show_all();
Gtk::main();
Save this is md5.php, load it up via command-line/terminal (Win
"C:Gnopephp-win.exe md5.php" or *nix "php md5.php") and you should
see something like the following:
Play around with it a little, and check all is in order: