SIL LSDev Linux Development

Language software for Linux and Mac OS X

Explorations in GTK# part 2

Glade and custom widgets

Glade and GTK# are a powerful combination. One that we are using for our Mono re-implementation of WorldPad. It’s quite possible to build a very functional application using just the standard widgets provided by GTK, but sometimes specific functionality is needed which is not found in the regular set of widgets.

In this instance, a "custom widget" can be inserted into a Glade interface. This is easy to do, but filling in the custom widget with something useful is a bit more tricky.

Custom widgets in Glade
Above: Custom widgets in Glade.
Below: Custom widgets being implemented as "ColorPickerButton"s in the application.
Custom widgets in use

How do we implement the custom widget?

If you’re still following this, I’ll assume that you already know how to create and use Glade files.

In our case, we needed a custom colour picking widget. (Note that GTK does have a colour selection button, but we wanted something simpler, to more closely follow WorldPad). All that is needed is to stick a custom widget from the "GTK+ Additional" set into your window or dialog. You can then set a few generic string and integer properties that can be used when the widget is instantiated.

If you have custom controls in your glade file, an XMLCustomWidgetHandler should be registered and will be called when you run load the Glade file. This function accepts a few parameters, most usefully the name of the widget and the properties that you may have defined in Glade.

To register the handler, create a method (we called ours on_custom_widget_found()*) and set the static property Glade.XML.CustomWidgetHandler to a new XMLCustomWidgetHandler constructed with the above method as a parameter

In our program, we simply took the name of the widget and used it to decide which widget to create and set up**. The widget is then returned by the function, et voila! Any widget you can construct using GTK# can appear in your Glade application.

*Gtk.Widget on_custom_widget_found(XML xml, string func_name, string name, string string1, string string2, int int1, int int2)

**Each widget was constructed, had an event attached, and was displayed using Show().

4 Responses to “Explorations in GTK# part 2”

  1. metator says:

    Hi,

    I’m trying to use this functionality but with no success. I’ve managed to create a catalog file with a custom widget and it shows up on the glade palette. I created a simple glade file with 1 custom widget on a Window.
    Then i created a C# project in order to test the custom widgets instantiation. Here’s the class i’m trying to AutoConnect:

    public class Windget {

    [Glade.Widget()]
    private Gtk.Window window1;

    public virtual Gtk.Window Window1 {
    get {
    return this.window1;
    }
    set {
    this.window1 = value;
    }
    }

    [Glade.Widget()]
    private Gtk.VBox vbox1;

    public virtual Gtk.VBox Vbox1 {
    get {
    return this.vbox1;
    }
    set {
    this.vbox1 = value;
    }
    }

    [Glade.Widget()]
    private DataButton databutton1; //The custom widget

    public virtual DataButton Databutton1 {
    get {
    return this.databutton1;
    }
    set {
    this.databutton1 = value;
    }
    }

    public Windget() {
    XML.CustomHandler = CustomWidgetHandler;
    XML gui = new XML(“main.glade”, “window1″, null);
    gui.Autoconnect(this);

    }

    public static Widget CustomWidgetHandler(XML xml, string func_name, string name, string string1, string string2, int int1, int int2) {
    return new Widget(IntPtr.Zero);
    }
    }
    }

    What’s happening here is that the method CustomWidgetHandler is never called and the application throws a System.ArgumentException when it tries to AutoConnect with the message: “Object of type ‘Gtk.Label’ cannot be converted to type ‘Gtk.DataButton’.”.
    I don’t have a clue why glade isn’t detecting the custom widget. Do i need to specify anything else in the glade file or in the catalog file?

    Here’s my glade file (main.glade):

    True

    True
    True
    True
    button
    0
    Test

    1

    And here’s the glade catalog i created:

    glade_standard_string_spec

    Thanks in advanced. Regards

  2. metator says:

    The file contents weren’t submitted properly. I’m trying it again:

    Here’s my glade file (main.glade):

    <?xml version=”1.0″ encoding=”UTF-8″ standalone=”no”?>
    <!DOCTYPE glade-interface SYSTEM “glade-2.0.dtd”>
    <glade-interface>
    <widget class=”GtkWindow” id=”window1″>
    <child>
    <widget class=”GtkVBox” id=”vbox1″>
    <property name=”visible”>True</property>
    <child>
    <widget class=”DataButton” id=”databutton1″>
    <property name=”visible”>True</property>
    <property name=”can_focus”>True</property>
    <property name=”receives_default”>True</property>
    <property name=”label” translatable=”yes”>button</property>
    <property name=”response_id”>0</property>
    <property name=”boundary_mappings”>Test</property>
    </widget>
    <packing>
    <property name=”position”>1</property>
    </packing>
    </child>
    <child>
    <placeholder/>
    </child>
    </widget>
    </child>
    </widget>
    </glade-interface>

    And here’s the glade catalog i created:

    <?xml version=”1.0″ encoding=”UTF-8″?>
    <glade-catalog name=”databind” depends=”gtk+” icon-prefix=”gtk” domain=”glade3″ book=”gtk”>
    <glade-widget-classes>
    <glade-widget-class name=”DataButton” parent=”GtkButton” generic-name=”databutton” title=”Data Button”>
    <properties>
    <property id=”boundary-mappings” name=”Boundary Mappings” default=”Test”>
    <spec>glade_standard_string_spec</spec>
    </property>
    </properties>
    </glade-widget-class>
    </glade-widget-classes>
    <glade-widget-group name=”gtk-databinding” title=”Bound Controls”>
    <glade-widget-class-ref name=”DataButton” />
    </glade-widget-group>
    </glade-catalog>

    Regards

  3. metator says:

    I found out that this CustomWidgetHandler only fires when it finds a Custom widget (which is on Gtk+ Obsolete group in the glade palette).
    If i go this way i only get the Custom widget properties and events. Moreover, Custom widget is just a placeholder, with no graphics.
    Is there any way to “mark” a widget as custom?

  4. Neil Mayhew says:

    Not that we’ve found. We’ve been using only the Custom widget as Andy described, and haven’t tried the catalog approach you used. We did, however, use the “func_name” property to store the actual class name and used reflection to create an object of that type in a generic custom_widget_handler.

    Note that the Glade library is now obsolete and has been superseded by GtkBuilder in the GTK library (Gtk.Builder in C#). See this blog post.

Leave a Reply