• 26 May 2013 - Since the new version attracted too many spammy registrations (around 250 fake accounts/day), user registrations are now protected by Mollom's spam protection service. Contact us if this causes some trouble.
  • 01 May 2013 - After the site upgrade, all passwords were reset and you will need to ask the site for a login reset on your first connection.

PHP-GTK Glade object

Hi,

Does anybody know how to access the object attribute in a .glade file, i have tried googling and spent hours reading the manual, without much success. I would like to access the attribute to make my application dynamically load a class at the time the signal is sent, rather than have it all sitting in memory.

An extract from my glade file:

<signal name="clicked" handler="on_toolbarNew_clicked" object="myobject" last_modification_time="Sat, 12 May 2007 02:45:00 GMT"/>

How I envision its usage:
Button clicked -> signal caught by handler -> handler dynamically instanciates "myobject" -> "myobject" clicked method called -> handler destroys "myobject" instance

At the moment it seems from my research that only the name, and handler attributes are passed along when the button is clicked even though the object is a standard attribute from the glade file, and can be found in the signals panel of the glade "properties" window.

Thanks in advance for any help.

SimpleXML + XPath workaround

AFAIK, it is not even passed in the callback: look at the call stack, and you'll notice it is not in the parameters, neither in the parameters of the invoking function.

Don't let that deter you, though: you can still use the XML parser to read in the glade file independently of its loading via GTK. Small example here: look at the glade file:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--*- mode: xml -*-->
<glade-interface>
  <widget class="GtkWindow" id="window1">
    <property name="visible">True</property>
    <property name="title" translatable="yes">window1</property>
    <child>
      <widget class="GtkButton" id="button1">
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="label" translatable="yes">button1</property>
        <property name="use_underline">True</property>
        <signal name="clicked" handler="onClickButton" object="doofus"/>
      </widget>
    </child>
  </widget>
</glade-interface>

Now define the onClickButton handler:

<?php
function onClickButton() {
   
$ui = simplexml_load_file('foo.glade');
   
$xpath = "//widget[@id='button1']/signal[@name='clicked']/@object";
   
$elem = $ui->xpath($xpath);
    echo
$elem[0] . PHP_EOL;
?>

So you see it just takes 3 lines of code, one of which is not recurring:

  1. load the Glade file into the parser used by SimpleXML
  2. define an XPath expression matching the id of the object you want to handle
  3. query the document for the results ; you know there will be only one such, since
    • you selected an ID which you know is present,
    • IDs are necessarily unique in XML documents
    • the @object selector can not return more than one value

It's a pity it's not passed!

Thanks for the reply Frédéric,

That seems like a good workaround, i will have to look into it, however it does place extra workload so i'll have to test its performance hit aswell.

hmm.. I could parse the glade file using simplexml in a singleton pattern and then just reuse the instance

It's a pity that the object attribute is not passed to the callback, as IMO this could make the apps more intuitive, and if i knew how to do it i think i would add a patch for it!

Replacing or extending libglade

Actually, you could even replace libglade by a parsing of your own, to avoid duplicate parsing, and add features missing in libglade like, passing the object parameter back, or auto-creating widget variables for all widgets (or all widget with specific attributes, like "all top-level widgets" or "all widgets with at least one signal handler defined".

OTOH, libglade actually uses SAX parsing too, just like SimpleXML, and exposed it. Maybe there's a way to piggyback on this parsing to extend it ? See http://developer.gnome.org/doc/API/libglade/libglade-libglade-sax-parser...

How I use Glade

Hello I will explain how I use Glade with php-gtk.
  • I build my interface using Glade and generate an XML file,
  • I load this file with $glade = new GladeXml($file, $root_widget);
  • i give a specific name to all widgets which I need to access
    • buttons : button_quit, button_load, button_select ..
    • entries : entry_name, entry_title ...
  • if I don't want to access a given widget, I use this :
    $widget = $glade->get_widget($name);
    so :
    $entry = $glade->get_widget('entry_name');
    or :
    $glade->get_widget('button_quit')->connect_simple('clicked', array('Gtk', 'main_quit');
The goal of this method is to be as independant as possible of Glade features. So I just have to name some widgets and use a specific function to link any widget to my php code. In my scripts, this method is coded in a object oriented way.

How I now load glade

Thanks to Frédéric & Marc,

I had a look at the docs for libglade, and well i really don't have enough time to be looking at that right now, so that will have to wait, but at the same time i am still left with the same problem, i was following a similar method to what Marc has suggested!

What i have come up with now is a class that wraps the loading and connecting of widgets like the following:

glade file "example.glade"

<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">

<glade-interface>

<widget class="GtkWindow" id="window1">
  <property name="visible">True</property>
  <property name="title" translatable="yes">window1</property>
  <property name="type">GTK_WINDOW_TOPLEVEL</property>
  <property name="window_position">GTK_WIN_POS_NONE</property>
  <property name="modal">False</property>
  <property name="resizable">True</property>
  <property name="destroy_with_parent">False</property>
  <property name="decorated">True</property>
  <property name="skip_taskbar_hint">False</property>
  <property name="skip_pager_hint">False</property>
  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
  <property name="focus_on_map">True</property>
  <property name="urgency_hint">False</property>

  <child>
    <widget class="GtkVBox" id="vbox1">
      <property name="visible">True</property>
      <property name="homogeneous">False</property>
      <property name="spacing">0</property>

      <child>
<widget class="GtkEntry" id="entry1">
  <property name="visible">True</property>
  <property name="can_focus">True</property>
  <property name="editable">True</property>
  <property name="visibility">True</property>
  <property name="max_length">0</property>
  <property name="text" translatable="yes"></property>
  <property name="has_frame">True</property>
  <property name="invisible_char">●</property>
  <property name="activates_default">False</property>
  <signal name="insert_text" handler="on_entry1_insert_text" last_modification_time="Sun, 20 May 2007 23:32:27 GMT"/>
</widget>
<packing>
  <property name="padding">0</property>
  <property name="expand">False</property>
  <property name="fill">False</property>
</packing>
      </child>

      <child>
<widget class="GtkButton" id="button1">
  <property name="visible">True</property>
  <property name="can_focus">True</property>
  <property name="label" translatable="yes">button1</property>
  <property name="use_underline">True</property>
  <property name="relief">GTK_RELIEF_NORMAL</property>
  <property name="focus_on_click">True</property>
  <signal name="clicked" handler="on_button1_clicked" last_modification_time="Sun, 20 May 2007 23:31:42 GMT"/>
</widget>
<packing>
  <property name="padding">0</property>
  <property name="expand">False</property>
  <property name="fill">False</property>
</packing>
      </child>
    </widget>
  </child>
</widget>

</glade-interface>

Handler Class "window1.php"

<?php
class window1_handlers
{
    public function
on_entry1_insert_text()
    {
       
// Do insert text stuff here
   
}


    public function
on_button1_clicked()
    {
       
// Do button clicked stuff here
   
}
}
?>

Wrapper Class "wrapper.php"

<?php
class wrapper
{
    private static
$winsList        =    array();
    public static function
glade_load_autoconnect($gladeFile, $window)
    {
       
// I have removed error checking file exists etc for this example

       
$connectorFile        =    $window . '.php';
        include(
$connectorFile);
       
$instance            =    new $window.'_handlers';

       
self::$winsList[$window]    =    new GladeXML($gladeFile, $window);
       
self::$winsList[$window]->signal_autoconnect_instance($instance);
    }
}
?>

So now all i have to do to open and create the window, and connect all its handlers is

<?php
include("wrapper.php");
wrapper::glade_load_autoconnect('example.glade', 'window1');
gtk::main();
?>

I have obviously added methods to detroy the handler instances when the windows have closed but this is just a simple example.

Volby prohlížení komentářů

Vyberte si, jak chcete zobrazovat komentáře a klikněte na "Uložit změny".