Home > Gtk3, PyGObject, python > PyGObject: Gtk.Builder

PyGObject: Gtk.Builder

13 Aprile 2020

torna all’indice appunti

Builder

Un Gtk.Builder è un oggetto che legge una descrizione testuale di una UI e ne istanzia gli
oggetti, in essa descritti.
Per creare un Gtk.Builder da una descrizione testuale, si utilizza il metodo
Gtk.Builder.new_from_file(), se la stringa che descrive la UserInterface è
contenuta in un file, oppure Gtk.Builder.new_from_resource(), oppure
Gtk.Builder.new_from_string() se abbiamo un’unica stringa descrittiva.
Il Gtk.Builder tiene un riferimento di tutti gli oggetti che crea fino a che non finalizza la UI.
Le funzioni Gtk.Builder.get_object() e Gtk.Builder.get_objects()
vengono usate per accedere ai widgets della UI, grazie ai nomi assegnati ad essi all’interno della
descrizione testuale della UI.
Le Toplevel windows ritornate da queste funzioni rimarranno “vive” fino a chè l’utente non le
distruggerà esplicitamente con il metodo Gtk.Widget.destroy().
Se la UI definition viene inserita in un file, è convenzione dara a tale file, estensione “.ui”
Faremo riferimento a questa descrizione come “Gtk.Builder UI definitions” e non sarà da confondere
con “GtkUIManager UI Definitions”, che è molto più limitata.

Gtk.Builder UI definitions Syntax

Gtk.Builder esegue l’analisi (parsing) della descrizione testuale della UI in formato XML secondo
lo schema seguente:

L’elemento toplevel è

<interface>

.
Opzionalmente accetta un attributo “domain” che farà cercare al builder le stringhe tradotte in
base al dominio specificato. Questo si ottiene anche chiamando il metodo
Gtk.Builder.set_translation_domain().
Gli oggetti sono descritti nei tag , che possono contenere elementi , che descrivono le proprietà
degli oggetti (elementi), che connettono i segnali agli handlers, ed elementi , che descrivono i
child objects (molto spesso i widgets dentro ai contenitori, ma anche le actions dentro agli
action group, o le colonne nel tree-model).
Banalmente un elemento contiene un altro elemento elemento che descrive il child object.
La versione del toolkit viene descritta dall’elemento

<requires>

.
L’attributo “lib” specifica la libreria dei widget (attualmente l’unica supportata è “gtk+”).
L’attributo “version” specifica la versione in formato

<major>.<minor>

.
Se i requisiti di versione non vengono raggiunti, il builder darà errore.

Il tipo di oggetto rappresentato da un elemento viene specificato dall’attributo “class”.
Se il tipo di oggetto non è ancora stato caricato, GTK+ tenta di trovare il metodo
get_type() dal nome della classe; questo funziona quasi sempre, in caso contrario
è possibile specificare il nome della funzione get_type() esplicitamente, usando l’attributo
“type-func”.
Come caso speciale, Gtk.Builder permette di usare un oggetto che è stato costruito da un
Gtk.UIManager in un’altra parte della definizione UI, specificando l’id del
Gtk.UIManager nell’attributo “constructor” ed il nome dell’oggetto,
nell’attributo “id”.

Agli oggetti è possibile dare un nome con l’attributo “id”, che a sua volta permette all’app di
recuperare l’oggetto, tramite il medodo del builder Gtk.Builder.get_object(id).

Il settaggio delle properties degli oggetti è molto semplice grazie all’elemento

<property>

.
L’attributo “name” è il nome della property e il contenuto dell’elemento, il suo valore.
Se l’attributo “translatable” è settato a True, GTK+ userà gettext()
(o dgettext() se il builder ha settato un translation domain) per la traduzione del valore.
Gtk.Builder può fare l’analisi di testi che rappresentino i tipi più comuni di properties:
caratteri, stringhe, interi, numeri floating-point, booleans (stringhe come “True”, “t”, “yes”,
“y”, “1” sono interpretate come True, mentre stringhe come “False”, “f”, “no”, “n”, “0”,
interpretate come False), enums (possono essere specificati con il loro “name”, “nick” o
valore intero), flags (possono essere specificate dal loro “name”, “nick”, valore intero,
opzionalmente combinate con “|”, ad esempio “GTK_VISIBLE|GTK_REALIZED”) e colori (in un formato
leggibile con Gdk.RGBA.parse()).
GVariants vengono specificati nel formato leggibile da GLib.Variant.parse(), e
pixbufs specificati come filename di un file immagine da caricare.

I Signal handlers sono settati con l’elemento

<signal>

.
L’attributo “name” specifica il nome del segnale, e l’attributo “handler”, specifica la funzione
da connettere al segnale.

A volte è necessario fare riferimento a widget che sono stati costruiti in maniera implicita da
GTK+ come parte di un widget composto, per settare le properties su di essi aggiungere ulteriori
children (ad esempio il vbox di un Gtk.Dialog).
Questo può essere ottenuto settando la property “internal-child” dell’elemento a True.

I widgets hanno posti diversi dove aggiungere un child (ad esempio i contenuti di tabs e page nei
notebooks). Questo può essere definito nella “UI definition” specificando l’attributo “type”
nell’elemento

<child>

.

Un esempio di UI Definition per Gtk.Builder

<interface>
  <object class="GtkDialog" id="dialog1">
    <child internal-child="vbox">
      <object class="GtkBox" id="vbox1">
        <property name="border-width">10</property>
        <child internal-child="action_area">
          <object class="GtkButtonBox" id="hbuttonbox1">
            <property name="border-width">20</property>
            <child>
              <object class="GtkButton" id="ok_button">
                <property name="label">gtk-ok</property>
                <property name="use-stock">TRUE</property>
                <signal name="clicked" handler="ok_button_clicked"/>
              </object>
            </child>
          </object>
        </child>
      </object>
    </child>
  </object>
</interface>

Le properties principali sono:

Name Type Flags Short Description
translation-domain str r/w Il translation domain usato da gettext()

Metodi

Oltre ai soliti getter e setter relativi alle properties dell’oggetto Gtk.Builder,
i principali metodi sono:

new()

Crea un nuovo oggetto Gtk.Builder vuoto.
Questo metodo è utile nel caso si vogliano caricare porzioni di descrizione derivanti da fonti
diverse, con metodi come Gtk.Builder.add_from_file(),
Gtk.Builder.add_from_resource(), o Gtk.Builder.add_from_string().
Qualora la sorgente dovesse essere unica, sarebbero più comodi i class_methods
Gtk.Builder.new_from_file(), Gtk.Builder.new_from_resource(),
o Gtk.Builder.new_from_string().

new_from_file(filename)

Costruisce la UI definition presente nel filename passato come argomento.
Parametri:
filename: il nome del file contenente la UI description

new_from_resource(resource_path)

Costruisce la UI definition presente alla resource_path.
Parametri:
resource_path: l’oggetto Gio.Resource con il resource path;

new_from_string(string, length)

Costruisce la UI definition descritta dalla stringa.
Parametri:
string: la stringa contenente la UI definition (XML);
length: la lunghezza della stringa, o -1 se la stringa è None-terminated;

>>> TOOLBAR_INFO = """
... <?xml version="1.0" encoding="UTF-8"?>
... <interface>
...   <!-- interface-requires gtk+ 3.0 -->
...   <object class="GtkToolbar" id="toolbar">
...     <property name="visible">True</property>
...     <property name="can_focus">False</property>
...     <property name="hexpand">True</property>
...     <property name="show_arrow">False</property>
...     <child>
...       <object class="GtkToolButton" id="new_button">
...         <property name="use_action_appearance">False</property>
...         <property name="visible">True</property>
...         <property name="can_focus">False</property>
...         <property name="use_action_appearance">False</property>
...         <property name="is_important">True</property>
...         <property name="action_name">win.new</property>
...         <property name="label" translatable="yes">New</property>
...         <property name="use_underline">True</property>
...         <property name="stock_id">gtk-new</property>
...       </object>
...       <packing>
...         <property name="expand">False</property>
...         <property name="homogeneous">True</property>
...       </packing>
...     </child>
...   </object>
... </interface>
... """
>>> builder = Gtk.Builder.new_from_string(TOOLBAR_INFO, -1)

add_callback_symbol(callback_name, callback_symbol)

Aggiunge il callback_symbol allo scope del builder sotto il nome della callback.
Questo metodo sovrascrive cioò che è stato settato con il metodo Gtk.Builder.connect_signals(),
per ogni callback symbols che viene aggiunto.
L’utilizzo di questo metodo permette un miglior incapsulamento inquanto non occorre dichiarare i
callback symbols nel global namespace.
Parametri:
callback_name: il nome della callback, come previsto nell’XML;
callback_symbol: il GObject.Callback, ovver il callback pointer;

add_from_file(filename)

Esegue l’analisi di un file contenente una UI definition e la unisce con il contenuto corrente del
builder. Se la UI definition risiede in un unico file è consigliabile l’utilizzo di
Gtk.Builder.new_from_file().
Parametri:
filename: il nome file di cui analizziamo il contenuto (parsing);

add_from_resource(resource_path)

Analizza un resource file con una UI definition e la unisce al contenuto corrente del builder.
Se la UI definition risiede in un unico resource file è consigliabile l’utilizzo di
Gtk.Builder.new_from_resource().
Parametri:
resource_path: il percorso del resource file da analizzare;

add_from_string(buffer, length=-1)

Analizza una stringa contenente una UI definition e la unisce al contenuto corrente del builder.
Se la UI definition risiede in un unica stringa è consigliabile l’utilizzo di
Gtk.Builder.new_from_string().
Parametri:
buffer: la stringa da analizzare;
length: la lunghezza del buffer;

add_objects_from_file(filename, object_ids)

Analizza un file contenente una UI definition costruendo solo gli oggetti richiesti e li unisce
al contenuto corrente del builder. Se stiamo aggiungendo un oggetto che dipende da un oggetto che
non è suo child (ad esempio un Gtk.TreeView che dipende dal proprio Gtk.TreeModel), dobbiamo
metterlo esplicitamente nella lista object_ids.
Parametri:
filename: il nome del file da analizzare;
object_ids: una lista di stringhe con gli oggetti da costruire;

add_objects_from_resource(resource_path, object_ids)

Analizza un resource file contenente una UI definition costruendo solo gli oggetti richiesti e li
unisce al contenuto corrente del builder. Se stiamo aggiungendo un oggetto che dipende da un
oggetto che non è suo child (ad esempio un Gtk.TreeView che dipende dal proprio Gtk.TreeModel),
dobbiamo metterlo esplicitamente nella lista object_ids.
Parametri:
resource_path: il percorso del resource file da analizzare;
object_ids: la lista “nul-terminated” di stringhe corrispondenti
agli oggetti da costruire;

add_objects_from_string(buffer, object_ids)

Analizza una stringa contenente una UI definition costruendo solo gli oggetti richiesti e li
unisce al contenuto corrente del builder. Se stiamo aggiungendo un oggetto che dipende da un
oggetto che non è suo child (ad esempio un Gtk.TreeView che dipende dal proprio Gtk.TreeModel),
dobbiamo metterlo esplicitamente nella lista object_ids.
Parametri:
buffer: la stringa da analizzare;
object_ids: una lista di stringhe con gli oggetti da costruire;

connect_signals(self, obj_or_map)

Connette i segnali specificati ai rispettivi handler, come indicato nel dizionario passato come
argomento. L’handler (value) del segnale (key), può anche essere una tupla in forma
(handler [,arg1 [,argN]]), se all’handler è necessario passare degli argomenti.
esempio di applicazione:

builder.connect_signals({'on_clicked': (on_clicked, arg1, arg2)})

Parametri:
obj_or_map: il dizionario dove chiave/valore sono rispettivamente
il segnale e l’handler corrispondente;

connect_signals_full(func, *user_data)

Utilizza una funzione per connettere i segnali.
Parametri:
func: l’oggetto Gtk.BuilderConnectFunc, cioè la funzione usata
per connettere i segnali;
user_data: i dati che possono essere passati alla funzione;

expose_object(name, object)

Aggiunge un oggetto all’ oggetto condiviso del builder cosicchè possa essere
referenziato dagli altri oggetti costruiti dal builder.
Parametri:
name: il nome dell’oggetto “esposto” al builder;
object: l’oggetto da esporre;

get_application()

Ritorna l’oggetto Gtk.Application associato al builder, oggetto utilizzato per creare i proxies
delle actions come richiesto dall’XML che il builder sta caricando. Di default, il builder usa
l’application di default (Gio.Application.get_default()).
Se vuoi usare un’altra application per la costruzione dei proxies, usare il metodo
Gtk.Builder.set_application().

get_object(name)

Ritorna l’oggetto con il nome passato come argomento.
Parametri:
name: il nome dell’oggetto che vogliamo recuperare dal builder;

>>> builder.get_object("new_button")
<Gtk.ToolButton object at 0x00000000035b5f40 (GtkToolButton at 0x000000000318d1c0)>
>>> builder.get_object("new_button").get_label()
'New'

get_objects()

Ritorna tutti gli oggetti che sono stati costruiti dal builder.

>>> for obj in builder.get_objects():
...     print(type(obj))
...     
<class 'gi.overrides.Gtk.ToolButton'>
<class 'gi.repository.Gtk.Toolbar'>

get_translation_domain()

Ritorna il translation domain del builder.

get_type_from_name(type_name)

Ritorna il tipo di oggetto (GObject.GType) dal nome passato come argomento, o GObject.TYPE_INVALID
se nessun tipo viene trovato.
Parametri:
type_name: il nome da cui ricavare il tipo di oggetto;

>>> builder.get_type_from_name("GtkToolbar")
<GType GtkToolbar (80271280)>
>>> builder.get_type_from_name("GtkToolButton")
<GType GtkToolButton (54634240)>

set_application(application)

Associa l’applicazione al builder.
Questo metodo si usa solo se ci sono più di un oggetto Gio.Application nel nostro processo.
Parametri:
application: l’oggetto Gtk.Application da associare al builder,
non può essere None;

set_translation_domain(domain)

Setta il translation domain del builder.
Parametri:
domain: la stringa con il translation domain o None;

value_from_string(pspec, string)

Questa funzione converte la rappresentazione XML di un valore, nell’oggetto di default
(demarshal). In pratica il metodo chiama GObject.Value.init()
sul valore, così non deve essere inizializzato anticipatamente.
Questa funzione può gestire i tipi di valore str, uchar, boolean, int, uint, long, ulong, enum,
flags, float, double, string, Gdk.Color, Gdk.RGBA e Gtk.Adjustment
Parametri:
pspec: l’oggetto GObject.ParamSpec per la property;
string: la stringa che rappresenta il valore;

value_from_string_type(type, string)

Come il metodo Gtk.Builder.value_from_string(), questo esegue il demarshal di un
valore da una stringa, ma prende un oggetto GObject.GType invece di un oggetto
GObject.ParamSpec.
In pratica il metodo chiama GObject.Value.init() sul valore, così non deve
essere inizializzato anticipatamente.
Parametri:
type: il GObject.GType del valore;
string: la stringa che rappresenta il valore;

Ecco un codice di esempio:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gio


TOOLBAR_INFO = """
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <object class="GtkToolbar" id="toolbar">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="hexpand">True</property>
    <property name="show_arrow">False</property>
    <child>
      <object class="GtkToolButton" id="new_button">
        <property name="use_action_appearance">False</property>
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="use_action_appearance">False</property>
        <property name="is_important">True</property>
        <property name="action_name">win.new</property>
        <property name="label" translatable="yes">New</property>
        <property name="use_underline">True</property>
        <property name="stock_id">gtk-new</property>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="homogeneous">True</property>
      </packing>
    </child>
    <child>
      <object class="GtkToolButton" id="open_button">
        <property name="use_action_appearance">False</property>
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="use_action_appearance">False</property>
        <property name="is_important">True</property>
        <property name="action_name">win.open</property>
        <property name="label" translatable="yes">Open</property>
        <property name="use_underline">True</property>
        <property name="stock_id">gtk-open</property>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="homogeneous">True</property>
      </packing>
    </child>
  </object>
</interface>
"""


class AppWindow(Gtk.ApplicationWindow):
    def __init__(self):
        super().__init__(title="Toolbar Example")
        self.set_default_size(250, 100)

        builder = Gtk.Builder.new_from_string(TOOLBAR_INFO, -1)

        act_new = Gio.SimpleAction.new(name='new', parameter_type=None)
        act_open = Gio.SimpleAction.new(name='open', parameter_type=None)
        self.add_action(act_new)
        self.add_action(act_open)

        tool_bar = builder.get_object('toolbar')
        tool_bar.set_style(Gtk.ToolbarStyle.BOTH)
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.pack_start(tool_bar, False, False, 0)
        self.add(box)

        # bindings
        act_new.connect('activate', self.on_menu)
        act_open.connect('activate', self.on_menu)
        self.connect('destroy', Gtk.main_quit)

    def on_menu(self, action, value):
        print("INFO: menu <%s>" % action.props.name)


if __name__ == "__main__":
    win = AppWindow()
    win.connect("destroy", Gtk.main_quit)
    win.show_all()
    Gtk.main()

link di riferimento:

torna all’indice degli appunti
Gtk3 Builder

Categorie:Gtk3, PyGObject, python Tag: , ,
I commenti sono chiusi.