We haven't used most of PHP5 powerful object oriented features so far. Let's make an application that opens a text file and displays its contents to you: a simple notepad-kind-of application. Please note that is a very very simple application meant for educational purposes and has no practical functionality! Here is the code, read it, and don't be intimidated by its size. A detailed explanation follows the code:
<?php class Notepad extends GtkWindow { protected $currentFile; protected $buffer; protected $status; protected $context; protected $lastid; function __construct($fileName = null) { parent::__construct(); $mainBox = new GtkVBox(); $textBuff = new GtkTextBuffer(); $textView = new GtkTextView($textBuff); $statusBar= new GtkStatusBar(); $mainBox->pack_start($this->buildMenu(), false, false); $mainBox->pack_start($textView, true, true); $mainBox->pack_start($statusBar, false, false); $this->currentFile = $fileName; $this->buffer = $textBuff; $this->status = $statusBar; $this->connect_simple('destroy', array($this, 'quit')); $this->set_title('Simple Notepad'); $this->maximize(); $this->add($mainBox); $this->show_all(); $this->loadFile(); } function buildMenu() { $menuBar = new GtkMenuBar(); $fileMenu = new GtkMenu(); $menuName = new GtkMenuItem('_File'); $quit = new GtkImageMenuItem('gtk-quit'); $quit->connect_simple('activate', array($this, 'quit')); $quit->connect_simple('enter_notify_event', array($this, 'updateStatus'), 1); $quit->connect_simple('leave_notify_event', array($this, 'updateStatus'), 0); $fileMenu->append($quit); $menuName->set_submenu($fileMenu); $menuBar->add($menuName); return $menuBar; } function loadFile() { if($this->currentFile != null) { $contents = file_get_contents($this->currentFile); $this->buffer->set_text($contents); } } function updateStatus($enter) { if($enter) { $id = $this->status->get_context_id("Message"); $lastMsg = $this->status->push($id, "Quits the Application"); $this->context = $id; $this->lastid = $lastMsg; } else { $this->status->remove($this->context, $this->lastid); } } function quit() { Gtk::main_quit(); } } new Notepad('simple.phpw'); Gtk::main(); ?> |
The class structure is similar to what we have seen before, except the addition of some class properties and functions. Let's first have a look at the constructor. The constructor takes a single optional argument that defaults to null. That parameter is (path of) the file name that we wish to open. If you don't pass a parameter to the constructor, it will simply open nothing.
OK, so we first construct the parent (a GtkWindow) and then create some widgets that we will use. A GtkVBox for our layout, a GtkTextBuffer and a GtkTextView to display the contents of the file and a GtkStatusBar to display some messages. We setup the layout and add the respective widgets to the VBox.
Next we set the class properties:
$this->currentFile = $fileName; $this->buffer = $textBuff; $this->status = $statusBar; |
Simply extend this concept to other widgets too. Basically, you need to assign class properties to widgets that you think will need the entire class as its scope. Actually, class properties can also be used efficiently to store any data that you may need across the entire class. One example of this in our applications is the currentFile property. This will simply store the path of the current file opened, or null if none is. We can then find out the name of the current file opened in any function of the class. Class properties have other uses too, one such use I can think of is a flag. For our notepad application, you may want to add a class property called saved which will have Boolean values to indicate whether the current file has been saved to disk or not.
Note that all the class properties have been defined as protected. This is simply a good object oriented practice. We don't want them to be public but we also want any classes that extends ours to be able to access them.
And finally, we set the title of the window, maximize it, add the layout and display all the widgets. And then we call the loadFile() function to display the contents of our file in the text buffer that we had created.
Note how we had called this function from the constructor:
$mainBox->pack_start($this->buildMenu(), false, false); |
In this function, we just create our menu bar, add a simple file menu with a single "Quit" button to it. Let's have a look at these lines:
$quit->connect_simple('activate', array($this, 'quit')); $quit->connect_simple('enter_notify_event', array($this, 'updateStatus'), 1); $quit->connect_simple('leave_notify_event', array($this, 'updateStatus'), 0); |
$wnd->connect_simple('destroy', array('gtk', 'main_quit')); |
Sometimes, it is possible to pass parameters to functions in order to use those objects in the function. As a rule of thumb, if you have more than one function that uses a particular object, it is better to dedicate a class property to it; but if there is only a single function that requires the object, it is better to pass the object as a parameter instead. A common occurrence of this situation is while connecting signals to callbacks. Have a look at the tutorial on signals and callbacks for more on this and how to pass custom parameters to the callbacks.
Getting back to the function, we return the top-most widget in our menu: the menu bar, after adding the sub-menu to it. The constructor then receives this object and adds it to the main VBox.
This function's purpose is to load the contents of the file to be opened and display them in the text view. Fairly straight-forward, we first check whether the class property currentFile is not null, and then use set_text() on the buffer class property.
This function serves as the callback for the enter-notify-event and leave-notify-event signals. Here we access the status bar via the status class property and add/remove a message depending on whether mouse is entering or leaving the Quit menu button.
This is the most simple function of all, only a single that quits the GTK main loop. You may wonder why we have a one-line function called 'quit' when we could have connected the signals directly to main_quit like:
$this->connect_simple('destroy', array('Gtk', 'main_quit')); |