Introduction to PHP-GTK 2
Creating Desktop Applications with PHP
Scott Mattocks
Introduction to PHP-GTK 2
- What is PHP-GTK 2?
- Parent/Child Relationship
- Signals & Events
- Models & Views
- Customizing the Look & Feel
- Q & A
What is PHP-GTK 2?
- A PHP 5 wrapper around Gtk+2.0
- PHP 5
- Scripting language normally associated with web development
-
- Quick and easy application development
-
- Improved object handling
- Gtk+2.0
- The Gimp ToolKit
- C library for for displaying UI elements on screen
- Used to create standalone desktop applications
- Improved text handling and internationalization
- Model/View architecture to separate data from display
- PHP 5 + Gtk+2.0 = quick and easy development of desktop apps
- Where did it come from?
- Arose from a need for better interface for CLI scripts
- Natural progression from CLI scripts
- Provides a GUI for CLI scripts
Why use PHP-GTK 2?
- Some apps better suited off line
- Not dependent on other software like web server
- Speed and responsiveness
- CLI is ugly and hard to use
- Alternatives
- Java Swing - too much code for even the simplest app
- C - not cross platform
- PyGtk (and other wrappers) - don't have the ease of PHP
- Why use PHP-GTK 2?
- Not all applications need to be on a web server.
- Not everyone is connected to the Internet all the time
- Easier to maintain state (no need for sessions)
- Direct access to file system
Terminology
- Object - a class extending from GtkObject
- Widget - a class extending from GtkWidget
- Represent onscreen UI elements like windows or buttons
- Non-widgets represent abstract data structures like ranges, lists or trees
- All widgets are objects but all objects are not widgets
- Event - something that happens during program execution
- Signal - a notification that an event has occurred
The Simplest Application
Produces:
<?php
$window = new GtkWindow();
$window->connect_simple('destroy', array('Gtk', 'main_quit'));
$window->show_all();
Gtk::main();
?>
- Not very useful
- Add something to the window to make the app more exciting!
- Anatomy of an application
- Define application elements and relationship to one another
- Tell application how to react to certain events
- Hand contol over to PHP-GTK and wait for events to occur
Adding a GtkEntry
<?php
// Create a window.
$window = new GtkWindow();
// Set it up to close cleanly.
$window->connect_simple('destroy', array('Gtk', 'main_quit'));
// Create an entry to get the search term.
$entry = new GtkEntry();
// Add the entry to the window.
$window->add($entry);
// Show the window and all of its contents.
$window->show_all();
// Start the main loop.
Gtk::main();
?>
- GtkEntry is a widget for collecting one line of text
- GtkWindow is a bin, nothing else can be added
- Add a container that can hold multiple widgets
- Trying to add a second widget to window will fail (GtkWindow descends from GtkBin)
- Why do you have to add a container to a container?
- Everything in PHP-GTK is highly specialized
- The primary function of a bin is not to organize many children
- Specialized multi-child containers rarely do more than organize layout
Parents and Children
- Widgets that hold other widgets are called "containers"
- Container is the parent - Widget inside is the child
- Manage placement and order of children
- Control amount of screen space used by children
- Toplevel widgets are widgets that do not need a parent container
- GtkWindow
- GtkMenu
- GtkDialog (a subclass of GtkWindow)
- All other widgets must have one and only one parent container
- Containers that hold only one child are called "bins"
- What is a container?
- Provides a context for the child
- Tells child where to appear and how to behave (expand, fill, padding)
- A widget can only have one parent. Otherwise it would be in two places at once.
- Why have bins?
- Wrap an individual widget to provide some extra display (GtkFrame)
- Allows widgets to specialize. Managing one child is easier especially when you have other things to worry about (GtkWindow)
Multi-Child Container Classes
- GtkHBox/GtkVBox - display children single file line either horizontally or vertically
- GtkTable - displays children in rows and columns
- GtkNotebook - displays children as pages with tabs
- GtkFixed - children are placed in an exact location
- Boxes
- Boxes are normally nested.
- Two HBoxes in a VBox allows for two rows of widgets but doesn't allow columns to be aligned easily
- Hard to keep things looking nice when window is resized.
- Table
- Very similar to HTML tables, but specifically designed for layout not tabular data
- Children are attached to cells
- Cells can span multiple rows or columns
- Dimensions of a cell depend on other cells in row/column
- Notebook
- One page shown at a time, all others hidden
- Tabs can be moved to any side of notebook or hidden
- Used to easily swap out visible elements
- Fixed
- Similar to CSS position: absolute
- Children placed (x, y) pixels from upper left corner
- Children do not move as window is resized
- Used for precision positioning where window is not resizeable (splash screen)
Using a GtkTable for Layout
<?php
// Create a window.
$window = new GtkWindow();
// Set it up to close cleanly.
$window->connect_simple('destroy', array('Gtk', 'main_quit'));
// Create a new table.
$table = new GtkTable(2, 3);
// A little short cut.
$expandFill = Gtk::EXPAND | Gtk::FILL;
// Attach a place holder for the menu.
$table->attach(new GtkFrame('Menu'), 0, 2, 0, 1, $expandFill, 0, 0, 0);
// Attach a place holder for the toolbar.
$table->attach(new GtkFrame('Toolbar'), 0, 2, 1, 2, $expandFill, 0, 0, 0);
// Attach a place holder for the main section.
$table->attach(new GtkFrame('Main'), 0, 1, 2, 3);
// Attach a place holder for the weather section.
$table->attach(new GtkFrame('Weather'), 1, 2, 2, 3);
// Add the table to the window.
$window->add($table);
// Show the window and all of its contents.
$window->show_all();
// Start the main loop.
Gtk::main();
?>
- Table is meant for organization. Nothing added to children like GtkFrame or GtkWindow.
- Arguments 2-5 define placement
- Other arguments define expand, fill and padding in x/y diretions
- Size of window and cells will change when real contents are added
- Elements are added to the table, then table is added to window (example of nested containers)
Filling out the UI
- Replace GtkFrames with actual elements. Full details are inappropriate for an "intro".
- Show scripts/uiComplete.php
- Identify elements that were added
- At this point we just have a fancy somewhat interactive image. Need to make it responsive by adding signal handlers.
Making it Interactive
- HTML pages are request driven
- User makes request, data is returned, repeat
- Only user can initiate action
- Examples: GET - click a link, POST - submit a form
- PHP-GTK apps are event driven
- Event occurs, action is taken, action may trigger other events
- User or application can trigger events
- Examples: click a button, change text in a text box, select a new element from a list, destroy a widget, etc
Events & Signals
- Events cause signals to be emitted by widgets
- Signals are processed by signal handlers
- Signal handler - tells PHP-GTK to take specific action (callback) in response to a specific signal from a specific widget
- Multiple signal handlers can be created for each signal
- Widgets emit a predefined set of signals in response to events.
- Example: Clicking a button causes that particular button to emit the "clicked" signal
- Widget can be set up to take a specific action when it emits a specific signal
- Example: Send SOAP request when button A is clicked
- Main loop checks event queue, pops an event, calls signal handlers, iterates
- Main loop starts and checks event queue
-
- TextEntry A says, "Hey, my text value was changed!"
- Main loop checks to see if anything should be done when TextEntry A's text value chagnes. No. Nobody cares. Throw away event. Iterate loop
- Button B says, "Hey, I was clicked!"
- Main loop checks to se if anything should be done when Button B is clicked. Yes. Main loop calls all callbacks for this widget and signal as defined by signal handlers. Throw away event. Iterate loop
- Event queue is empty. Iterate loop. Repeat.
Creating a Signal Handler
- Signal handlers are created using
connect()
, connect_after()
, connect_simple()
and connect_simple_after()
- Signal handlers can be separated into two groups: "run first", "run second"
connect()
and connect_simple()
create signal handlers in the "run first" group
connect_after()
and connect_simple_after()
create signal handlers in the "run second" group
- Most events automatically pass data to signal handlers; usually the widget that emitted the signal
Example Signal Handlers
// ...
// Create the main menu bar.
$this->menu = new GtkMenuBar();
// Add a file menu.
$file = new GtkMenuItem('_File');
$this->menu->append($file);
// Add some options to the file menu.
// We need a menu to put them in.
$fileMenu = new GtkMenu();
// Set the menu as the sub menu.
$file->set_submenu($fileMenu);
// Add an EVDB login option. This should open a dialog.
$login = new GtkMenuItem('Login');
$fileMenu->append($login);
// Make the options do something when clicked.
// The login option should open a login dialog.
$login->connect_simple('activate', array($this, 'loginDialog'));
// ...
- Open application and show signal handlers for login (menu and toolbar).
Example Signal Handlers (cont'd)
// ...
// We need a button to initiate the search.
$search = GtkButton::new_from_stock(Gtk::STOCK_OK);
// Attach the button to the table.
$table->attach($search, 3, 4, 3, 4, 0, 0, 0, 0);
// Search for events when the user clicks the button.
// Organize things slightly.
$after = array($afterMonths, $afterDays, $afterYears);
$before = array($beforeMonths, $beforeDays, $beforeYears);
$search->connect_simple('clicked', array($this, 'searchEvents'),
$keyword, $after, $before
);
// ...
- Open application and show signal handler for searchEvents.
- $keywords, $after, and $before are widget or arrays of widgets passed to callback. Must pass actual widget to get realtime value.
- searchEvents() makes a WebService call to EVDB. Data returned is a list of events.
Models & Views
- Complex data can often be represented in different ways (trees, lists, multi-line text)
- For ease of use and flexibility, PHP-GTK 2 implements an MVC pattern
- Specialized objects for managing and manipulating data (GtkTreeStore, GtkListStore, GtkTextBuffer)
- Specialized widgets for displaying data (GtkTreeView, GtkTextView)
-
One model can be shown by many views
- GtkTreeModelSort: wraps a model to sort it without altering it
- GtkTreeModelFilter: wraps a model to hide certain rows without altering underlying model
Trees & Lists
- Trees are hierachical data structures
- Each node may have a parent, children, and siblings
- List is a tree of only one level
- Think of a list as an array and a tree as a multi-dimensional array
- Good for displaying structured data sets such as file systems or database rows
- Not good for data whose structure changes from one node the next (XML)
- Crisscott_Events can make good use of GtkTreeStore and GtkTreeView to show events
- Switch to source code
Multi-line Text
-
Managed by GtkTextBuffer
- Mark text from one point to another using GtkTextTag objects
- GtkTextTag describes attributes of text
- foreground color
- weight
- many others
- Displayed by GtkTextView
- GtkTextView also allows user to edit text
- Very powerful
- Too many features to discuss now
Customizing the Look & Feel
- Appearance of application can be modified for various reasons
- Draw attention to certain widgets
- Create visual groupings
- Make the application unique
- Customizing can be done on an application level or widget level
- Can customize colors, fonts, shapes
Styles
- Control colors for individual widgets
- Every widget has a default style
- Default can be overridden at run time
// ...
// We need a button to initiate the search.
$search = GtkButton::new_from_stock(Gtk::STOCK_OK);
// Make the button stand out a little.
$style = $search->get_style();
$style->bg[Gtk::STATE_NORMAL] = GdkColor::parse('#0A0A6A');
$style->fg[Gtk::STATE_NORMAL] = GdkColor::parse('#FFFFFF');
$search->set_style($style);
// ...
- Show app and point out change in button.
Resource Files
- Resource Files (RC files) can be used to set default styles
- Similar to CSS for PHP-GTK Apps
- Define rules and styles
- Styles are applied to widgets that match rules
- Open source code and uncomment parse RC line.
- Then restart app
More Information
Open floor for Q&A