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:
<?phpfunction 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:
@objectselector can not return more than one valueIt'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
- I build my interface using Glade and generate an XML file,
- I load this file with
- 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 :
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.$glade = new GladeXml($file, $root_widget);$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');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
<?phpinclude("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.