Custom/Composed Widgets

In practice, one usually has to customize a widget to ones own needs. Furthermore, it is also useful to group widgets together to break up a complete user interface into manageable parts. Both use cases are discussed next.

Custom Widgets

You can subclass an existing Gtk type in Julia using the following code pattern:

mutable struct MyButton <: Gtk.GtkButton
    handle::Ptr{Gtk.GObject}
    other_fields
    function MyButton(label)
        btn = GtkButton(label)
        return Gtk.gobject_move_ref(new(btn), btn)
    end
end

This creates a MyButton type which inherits its behavior from GtkButton. The gobject_move_ref call transfers ownership of the GObject handle from GtkButton to MyButton in a gc-safe manner. Afterwards, the btn object is invalid and converting from the Ptr{GtkObject} to GtkObject will return the MyButton object.

Lets use this pattern to create a button that is initialized with a default text "My Button". The code would look like this.

mutable struct MyButton <: Gtk.GtkButton
    handle::Ptr{Gtk.GObject}

    function MyButton()
        btn = GtkButton("My Button")
        return Gtk.gobject_move_ref(new(btn.handle), btn)
    end
end

We can now add this button to e.g. a window or any layout container just as if MyButton would be a regular GtkWidget.

btn = MyButton()
win = GtkWindow("Custom Widget",400,200)
push!(win, btn)
showall(win)

Composed Widgets

While a pre-initialized button might look like an artificial use cases, the same pattern can be used to develop composed widgets. In that case one will typically subclass from a layout widget such as GtkBox or GtkGrid. Lets for instance build a new composed widget consisting of a text box and a button

mutable struct ComposedWidget <: Gtk.GtkBox
    handle::Ptr{Gtk.GObject}
    btn # handle to child
    tv # handle to child

    function ComposedWidget(label)
        vbox = GtkBox(:v)
        btn = GtkButton(label)
        tv = GtkTextView()
        push!(vbox,btn,tv)
        set_gtk_property!(vbox,:expand,tv,true)
        set_gtk_property!(vbox,:spacing,10)
        w = new(vbox.handle, btn, tv)
        return Gtk.gobject_move_ref(w, vbox)
    end
end

c = ComposedWidget("My Button")
win = GtkWindow("Composed Widget",400,200)
push!(win, c)
showall(win)

You will usually store the handles to all subwidgets in the composed type as has been done in the example. This will give you quick access to the child widgets when e.g. callback functions for ComposedWidget are called.