This "Code hints" section contains useful examples on how to manipulate certain combination of widgets and/or calls to achieve a given result.
Simpler, one-widget / one-scenario examples are located in the Single widget examples section.
Largers examples with extension classes are located in the Code snippets section.
On to the hints !
This enables a user to activate the menu without using the mouse or combining keys, just by pressing ALT. This can be important for accessibility.
<?php
if (!extension_loaded('gtk')) {
dl( 'php_gtk.' . PHP_SHLIB_SUFFIX);
}
/**
* test functions
*/
function func1() {
$label = &new GtkLabel( 'Go selected');
$label->show();
$GLOBALS['vbox']->add($label);
}
function func2(){
$label = &new GtkLabel( 'Clear selected');
$label->show();
$GLOBALS['vbox']->add($label);
}
/**
* Body of code
*/
//simple menu items
$menu_info = array(
'_Test'=>array(
'_Go'=>'func1',
'_Clear'=>'func2',
'seperator'=>'',
'E_xit'=>array('gtk','main_quit'),
)
);
$window = &new GtkWindow();
$window->set_default_size(350, 450);
$window->connect_object('destroy', array('gtk', 'main_quit'));
//create accegroup for main window
$accelgroup = &new GtkAccelGroup();
$window->add_accel_group($accelgroup);
//add vbox
$vbox = &new GtkVBox(FALSE, 0);
$vbox->show();
$vbox->set_spacing(1);
$window->add($vbox);
$menubar = &new GtkMenuBar();
$menubar->set_shadow_type(GTK_SHADOW_ETCHED_IN);
//make menu
foreach ($menu_info as $title=>$items) {
$menu = &new GtkMenuItem($title);
$mlabel = $menu->child;
$mlabel_key = $mlabel->parse_uline($title);
if($mlabel_key) {
//add accel with Alt key
$menu->add_accelerator('activate_item', $accelgroup,
$mlabel_key, GDK_MOD1_MASK, 0);
$menu->lock_accelerators();
}
$menubar->append($menu);
$menu->show();
$submenu = &new GtkMenu();
//create a new accelgroup for submenus
$accel = $submenu->ensure_uline_accel_group();
foreach ($items as $sub_title=>$function) {
if($sub_title == 'seperator') {
$item =& new GtkMenuItem();
$item->set_sensitive(false);
} else {
$item =& new GtkMenuItem($sub_title);
$label = $item->child;
$label_key = $label->parse_uline($sub_title);
if (!empty($function)) {
$item->connect_object('activate',$function);
if($label_key){
$item->add_accelerator('activate_item', $accel, $label_key, 0, 0);
$item->lock_accelerators();
}
}
}
$submenu->append($item);
$item->show();
}
$menu->set_submenu($submenu);
}
$menubar->show();
$vbox->pack_start($menubar,FALSE,FALSE,0);
$window->show_all(); gtk::main();
?>You have to connect the button-release-event
after all other functions have worked.
<?php
// Connect signal
$this->arWidgets["lstExcludes"]->connect_after(
"button-release-event",
array(&$this, "OnClickList"));
// Get the current selection:
<?php
function OnClickList() {
$nSelRow = $this->arWidgets["lstExcludes"]->selection[0];
if( is_int( $nSelRow)) {
echo get_text( $nSelRow, 0);
}
} //function OnClickList()
?>The text in col 1 of the selected row is echoed now.
GtkWidgetparent::__construct, or you will have an error
(Fatal error: Cannot instantiate abstract class) for
primitive widgets (abstract ?) (GtkWidget),<?php
# simple code fragment (need to be completed)
class PrimitiveWidget extends GtkWidget {
function __construct() {
# Fatal error: Cannot instantiate abstract class
# PrimitiveWidget in line ... (__construct() line call)
# parent::__construct();
}
}
$w = new PrimitiveWidget();
?>GtkVbox for example<?php
class CompositeWidget extends GtkVbox {
function __construct() {
parent::__construct();
$this->label = new GtkLabel('test composite widget');
$this->add($this->label);
$this->add(new GtkLabel('an other label'));
$this->add(new GtkButton('Test me'));
$this->set_border_width(10);
}
}
$win = new GtkWindow();
$win->set_title('Composite Widget extension example');
$win->connect_simple('destroy', array('gtk', 'main_quit'));
$composite_widget = new CompositeWidget();
$vbox = new GtkVBox();
$win->add($vbox);
$vbox->pack_start($composite_widget, true);
$win->show_all();
Gtk::main();
?>Need to grab a screenshot in your program? Or maybe you
just need to create an image from an existing
GtkWidget. There's an easy way to
accomplish both tasks using
GdkPixbuf::get_from_drawable();
To use the method you'll need two things - an empty
GdkPixbuf and the "drawable"
(GdkDrawable) associated with your widget.
Most widgets will have a GdkWindow located
in $widget->window. You can get the
entire screen, however, by using
Gdk::get_default_root_window();.
Now for the code examples...
<?php
/**
* This comes first because we need to make sure all
* widgets are shown on the screen before we
* take a picture of them
*/
while (Gtk::events_pending())
{
Gtk::main_iteration();
}
// get the root gdkwindow (entire screen)
$root = Gdk::get_default_root_window();
// get the size of the screen
list($width, $height) = $root->get_size();
// create an empty pixbuf the same size
$pixbuf = new GdkPixbuf(Gdk::COLORSPACE_RGB, TRUE, 8,
$width, $height);
// grab a pixbuf from the screen
$pixbuf->get_from_drawable ($root, $root->get_colormap(), 0, 0,
0, 0, $width, $height);
?><?php
/**
* remember the widget MUST BE SHOWN AND DRAWN
* and not offscreen or you'll get weird black areas
*/
$widget->show();
while (Gtk::events_pending())
{
Gtk::main_iteration();
}
/**
* we'll use allocation information: not every widget has
* its own gdkwindow
*/
$alloc = $widget->allocation;
$pixbuf = new GdkPixbuf(Gdk::COLORSPACE_RGB, TRUE, 8,
$alloc->width, $alloc>height);
$pixbuf->get_from_drawable ($widget->window,
$widget->window->get_colormap(),
$alloc->x, $alloc->y,
0, 0,
$alloc->width, $alloc->height);
?>After your pixbuf is created you can save it to a file, or display
it in a GtkImage or manipulate it with
GdkPixbuf methods- have fun.
Hi, there is a way to use the gtkhtml component with glade / phpgtk.
In glade, create a
GtkScrolledWindow
and add a Custom component with
gtk_html_new as creation function name.
The following php code produced a segmentation fault, on my Debian :(
<?php
// $html is some text variable that
// contains html code
$html = "<html><body>foo</body></html>";
// generate a glade layout from
// the glade xml file
$layout = &new GladeXml("test.glade");
// retrieve the Custom component named "htmlcomponent"
$gtkhtml = &$layout->get_widget("htmlcomponent");
// gtkhtml component MUST have a content
// or the program will generate a
// segmentation fault (another one yes)
$stream = &$gtkhtml->begin();
$gtkhtml->write ($stream, $html, strlen($html) );
$gtkhtml->end ($stream, GTK_HTML_STREAM_OK);
?>To get rid of this segfault, I removed the GtkViewPort widget from the produced glade xml (I found no way to remove it from the glade interface).
The glade file is alway usuable within glade so you can modify the interface...
I hope this will help some coders :)
For a full list of gtkhtml callbacks and functions,
refer to gtkhtml.h file in gtkhtml-dev packages.
NOTE : This comment was taken directly from http://gtk.php.net/manual/en/glade.gladexml.php
This is a sample code to demonstrate the use of
Gtk::io_add_watch(). The main goal of this function
is to handle socket IO without blocking. Socket polling is done
in Gtk::main() loop. You don't need to care about socket polling.
This task is done by Gtk and Glib.
In this example, the function is used for building an simple IRC client that connect to an IRC server, identifying itself, connecting to #php-gtk, and doing some boring things.
Since this is just a use case for the API, there is no user interface.
There is a package on Gnope server based on this documentation and class.
io_id Gtk::io_add_watch($stream, $conditions, $callback)
$conditions parameter description : this is a mask of the following values :
Gtk::IO_IN : stream is ready for reading,Gtk::IO_OUT : stream is ready for writing,Gtk::IO_PRI : this is the high priority
channel for streamGtk::IO_ERR : stream is in error state,Gtk::IO_HUP : stream has been
disconnected (sighup)Gtk::IO_NVAL : (invalid command to socket ?)You can build mask like this :
$conditions = Gtk::IO_IN|Gtk::IO_OUT.
function io_callback($gio_channel, $conditions)$gio_channel is not usable with this
current API implementation ; should be used with
g_io_ functions not implemented.
But IO can be done with standard php functions.
<?php
error_reporting(E_ALL);
/*
$conditions : can be a mask of :
Gtk::IO_IN, Gtk::IO_OUT,
Gtk::IO_PRI, Gtk::IO_ERR,
Gtk::IO_HUP, Gtk::IO_NVAL
*/
/**
* Available syntaxes for io_add_watch:
*
$id = io_add_watch($stream, $condition, $callback);
$id = io_add_watch_priority($stream, $condition, $callback,
$priority);
*
*/
class GtkIO {
protected $gio_ids;
protected $fd;
protected $hostname;
protected $port;
protected $errno; # fsocketopen error status
protected $errstr;
function __construct() {
$this->gio_ids = array();
}
function connect($hostname, $port) {
$this->hostname = $hostname;
$this->port = $port;
$this->fd = fsockopen($hostname, $port,
$this->errno, $this->errstr);
if(!$this->fd)
trigger_error("GtkIO::connect : connexion error : "
. "{$this->errstr} ({$this->errno})");
else {
$this->io_setup();
}
return $this->fd;
}
function io_setup() {
$this->gio_ids[Gtk::IO_IN] =
Gtk::io_add_watch($this->fd, Gtk::IO_IN,
array($this, 'io_in'));
$this->gio_ids[Gtk::IO_OUT] =
Gtk::io_add_watch($this->fd, Gtk::IO_OUT,
array($this, 'io_out'));
$this->gio_ids[Gtk::IO_HUP] =
Gtk::io_add_watch($this->fd, Gtk::IO_HUP,
array($this, 'io_hup'));
$this->gio_ids[Gtk::IO_PRI] =
Gtk::io_add_watch($this->fd, Gtk::IO_PRI,
array($this, 'io_pri'));
$this->gio_ids[Gtk::IO_ERR] =
Gtk::io_add_watch($this->fd, Gtk::IO_ERR,
array($this, 'io_err'));
$this->gio_ids[Gtk::IO_NVAL] =
Gtk::io_add_watch($this->fd, Gtk::IO_NVAL,
array($this, 'ion_val'));
}
function write($data) {
return fwrite($this->fd, $data, strlen($data));
}
# very incomplete : need to handle errors ...
function read($size = 2048) {
return fread($this->fd, $size);
}
function eof() {
return feof($this->fd);
}
function io_in($gio_channel, $conditions) {
echo "GtkIO::io_in()\n";
}
function io_out($gio_channel, $conditions) {
echo "GtkIO::io_out()\n";
}
function io_hup($gio_channel, $conditions) {
echo "GtkIO::io_hup()\n";
}
function io_pri($gio_channel, $conditions) {
echo "GtkIO::io_pri()\n";
}
function io_err($gio_channel, $conditions) {
echo "GtkIO::io_err()\n";
}
}
define('GTK_IRC_CONNECTED', 1);
define('GTK_IRC_DISCONNECTED', 2);
class IrcProtocol extends GtkIO {
protected $nick;
protected $user;
protected $channels;
protected $timeout_id;
protected $irc_status;
function __construct() {
$this->timeout = 1000;
$this->timeout_id = Gtk::timeout_add($this->timeout,
array($this, 'timeout'));
$this->irc_status = GTK_IRC_DISCONNECTED;
}
function connect($hostname, $port,
$nick, $user, $channels) {
$status = parent::connect($hostname, $port);
if ($status === false)
die("can't connect to irc server");
$this->irc_status = GTK_IRC_CONNECTED;
$this->nick = $nick;
$this->user = $user;
# initial channels to join;
$this->channels = $channels;
$this->nick($nick);
$this->user($user);
$this->join($channels);
}
function send($str) {
echo "Irc::send($str)\n";
$this->write($str . "\n\r");
}
function timeout() {
static $count = 0;
echo "timeout ...\n";
$count++;
# debug - for gtk_io function monitor
if ($count > 3) {
$this->send_chan('#php-gtk', "I'm going out; bye ...");
$this->disconnect();
return;
}
if ($this->irc_status == GTK_IRC_CONNECTED
&& $this->fd != null)
$this->timeout_id = Gtk::timeout_add($this->timeout,
array($this, 'timeout'));
$this->send_chan('#php-gtk', "hello ; I'm php-gtk-irc bot");
}
function io_in($gio_channel, $conditions) {
$data = $this->read();
echo "$data\n";
}
function io_hup($gio_channel, $conditions) {
echo "irc : disconnected\n";
$this->fd = null;
Gtk::main_quit();
}
function disconnect() {
$this->send('QUIT');
$this->irc_status = GTK_IRC_DISCONNECTED;
Gtk::main_quit();
}
function send_chan($chan, $msg) {
$this->send("PRIVMSG $chan :$msg");
}
function nick($nick) {
$this->send("NICK $nick");
}
function user($user) {
$this->send("USER $user $user $user localhost");
}
function join($channels) {
foreach($channels as $chan)
$this->send("JOIN $chan");
}
}
$irc = new IrcProtocol();
/**
* You'll need to change these parameters
* maybe to connect to chat.freenode.net
*/
$irc->connect(
$server = 'irc.freenode.net',
$port = '6667',
$nick = 'mq-boot',
$user = 'Marc', # put you name here ...
$channels = array('#php-gtk', '#php'));
Gtk::main();
?>Notes :
GtkIO::read() is very incomplete to.
You can refer to thoses links for a complete documentation. Gtk::io_add_watch() is based on
Glib function io_add_watch().
io_add_watch.
Note that, although the function is available on all platforms, this small example doesn't completely work on Windows.
I had trouble finding this out, so here it is. If you want to manage a network connection (i.e. an IRC connection) you need a while (1) {} loop.
This cannot be done in PHP-GTK, because of the
gtk::main() function. So, there is the
gtk::timeout_add($time, $function)
that executes a function every $time milliseconds.
This solves our problem.
Your function must return TRUE else it will not be called again. Return FALSE to cancel the timeout.