I originally used PHP-GTK, but with its lack of support on Linux distributions (i.e. it isn't included by default nor is there an available package to install to make it easier to install PHP-GTK), I decided to switch to using PyGTK, as Python as well as PyGTK are installed on most Linux distributions out of the box, including Debian (including Ubuntu, Linux Mint, etc) as well as many other Linux distributions. On Windows, your users can easily and conveniently download a single installer that installs PyGTK for them. On Mac OS X, there are many easy tutorials on the Web to install Python and PyGTK on the OS X platform, too.
Here's the end result of the following application:
I must first forewarn you will need to have experience in object oriented programming (OOP). Essentially object oriented programming is a structural methodology that really starts to make sense as your applications become complex and large, where organisational structure is really essential to make maintenance and development continuity of your application as easy and seamless as possible for you (and possibly) other developers.
Going onto the application itself, the code is as follows:
Code:
import gtk
class PyGTKApp:
button = gtk.Button("Click Here!")
hBox = gtk.HBox()
vBox = gtk.VBox()
def __init__(self):
self.window = gtk.Window()
self.window.set_title("Hello world")
self.window.connect("destroy", gtk.main_quit)
self.window.set_size_request(400,100)
self.window.add(self.vBox)
self.vBox.pack_start(self.hBox,0)
self.hBox.pack_start(gtk.HBox(),1,0)
self.hBox.pack_start(self.button,0,0)
self.hBox.pack_start(gtk.HBox(),1,0)
self.window.show_all()
PyGTKApp()
gtk.main()
Okay, so what does this all mean? Well, first:
This imports the
gtk namespace in order to be able to use
gtk classes, such as
Window,
Button, etc etc.
This is the definition of the
class. Now I am sure most people will at least know the basics of object oriented programming, but I'll explain briefly what a class is. A class is simply a container for programming logic and functionality and can be considered as a container for related functionality of a specific element or function of your application. The logic and functionality within a class are the
methods or
functions (these two terms can generally be used interchangeably to refer to the same thing, but strictly speaking, they are called methods). So again, we create a class to contain
our functionality for the application. The
gtk namespace that we have to import at the start of our file contains hundreds of its own classes and subsequent methods, etc.
Code:
button = gtk.Button("Click Here!")
hBox = gtk.HBox()
vBox = gtk.VBox()
These are not within a method but within the class body. These are class level variables. Class level variables are different from instance variables, which are variables within the method itself. The difference being are that class level variable values apply coherently to all active instances of that particular class, whereas instance variables apply to each active instance of the particular class. So, to put some context to this, if you change the value of a class level variable, if you
print the variable from another object instance it will output the new value that you set from a different object instance. Whereas any changes to instance variables only apply to the instance where the change was applied.
So what are we instantiating here then? Well, first, we're instantiating a Button (of the
Button class of the
gtk namespace). Second, a horizontal box to hold multiple widgets and third, a vertical box that can also hold multiple widgets. The reason for both is explained later.
"Object" refers to an active instance of a class commonly assigned to a variable (i.e. a class you have instantiated)
Code:
def __init__(self):
This is the method itself. Methods in Python start with
def. But you may wonder what the heck
__init__ is (that is two underscores on either side). Well, the
__init__ method is the class constructor. This is an ordinary method but this particular method (the constructor) is executed as soon as the class is instantiated, without having to call a separate method as you create an object of a class. So if you have specific code logic you need to execute as soon as a class is instantiated, use the constructor.
You may wonder why there is an argument (parameter) supplied with the constructor. In other programming languages, such as PHP, have a specific, reserved variable that you can use to refer to the current class. In Python, the first parameter (or argument) of a method refers to the current class, and so you can set the first parameter argument to whatever you want, but the convention is to use
self.
Code:
self.window = gtk.Window()
self.window.set_title("Hello world")
self.window.connect("destroy", gtk.main_quit)
self.window.set_size_request(400,100)
So, note here these are instance variables. Note that if you simply use
window = gtk.Window it will be a normal variable, and as such, the scope of the variable is limited to the method itself. In simpler terms, this means you won't be able to call upon the variable from an object, whereas with instance variables above, you can (as well as in other methods of a class).
So the first line is where we are creating a new window. We are creating a new instance of the
Window class. The second line we are setting the title of the window through the
set_title() method. The third line is where things get a bit more complicated.
We're connecting a signal ("event") to when the window is destroyed, and when the signal is called, the
gtk.main_quit() method is executed. Why? Well, the reason being is because by default, when you close the main window (the
Window) via the graphical user interface, it only destroys the widget and does not terminate the application. So this line of code ensures the application is actually terminated upon the
Window being destroyed as the
x button is pressed on the top corner of the window.
The
set_size_request() method on the fourth line sets the minimum size (width and height, respectively), of the
Window.
Code:
self.window.add(self.vBox)
self.vBox.pack_start(self.hBox,0)
self.hBox.pack_start(gtk.HBox(),1,0)
self.hBox.pack_start(self.button,0,0)
self.hBox.pack_start(gtk.HBox(),1,0)
The
Window itself can only contain one widget or container, whereas
HBox and
VBox can contain multiple widgets and containers. We first pack the hBox (that is a class-level variable above the constructor method) to the
vBox. Now, anything packed in a
VBox will be placed line by line (i.e. one widget/container per line) since it is a
vertical box.
On the second line, we then add one
HBox (directly from within the first argument of the
self.hBox.pack_start()) to the
hBox. We then add the button next and another
HBox afterwards. Now, you may notice the second line in the code above has its second argument set to
false (or
0). The reason being is to prevent the hBox expanding to fill the entire available space (which is the entire window, as of now). The reason being is so on the third line the HBox being added will only expand width-wise, and not height-wise too. In the third line, the second argument is set to
TRUE to
expand but not
fill (i.e. height). The fourth line is for the button, and both arguments are set to
FALSE to ensure the button stays a standard button size. And the last line is the same as the HBox being added before the button. What's the end result? A centred button! Yes, this is the way you have to do it in order to centre widgets, etc.
And there we have it

. If you want to detect when a button is pressed, research PyGTK signals/events. You may wonder if there is an easier way of drawing up the graphical user interface, and of course there is - it's called
Glade. Read more about Glade
on Wikipedia.