vai alla Homepage di Apogeonline

 



Cos'è OpenPress
Glossario
Linux-FAQ
Documenti:

Open Source Definition

GNU General Public License

La cattedrale e il bazaar

Colonizzare la noosfera

Il calderone magico


Libri:

Italian crackdown

Open Sources

MediaMorfosi

GTK+/GNOME
sviluppo applicazioni


Telematica per la pace

Linux HOWTO: Installazione e configurazione

Linux HOWTO: Networking


Risorse
Feedback
vai alla Homepage di Apogeo Editore

Vai alla homepage di OpenPress

GTK+ / Gnome Sviluppo di Applicazioni


Controllo dei tipi e loro creazione

GTK+ ha un sistema di tipi molto esteso, che è indipendente dal sistema di oggetti. Tuttavia, il sistema ad oggetti fa largo uso di questo: ciascun oggetto ha un tipo, e ogni tipo ha un numero intero identificatore unico. Quando si scrive un GtkObject, è caldamente consigliato scrivere una funzione che restituisca l'identificatore del tipo.

Nel caso di GtkButton, questa è la funzione:


GtkType gtk_button_get_type();

La prima volta che questa funzione viene chiamata, verrà registrato un tipo GtkButton con il sistema ad oggetti, e restituito il suo identificatore. Le chiamate successive restituiscono semplicemente quest'ultimo. GtkType è un typedef (l'attuale lunghezza degli identificatori di tipo di GTK+ è unsigned int).

Il sistema di tipi permette a GTK+ di controllare la validità dei cast. Per facilitare questa operazione, gli oggetti solitamente forniscono delle macro come queste nei file header:


#define GTK_TYPE_BUTTON            (gtk_button_get_type ())
#define GTK_BUTTON(obj)            (GTK_CHECK_CAST ((obj), \
                                    GTK_TYPE_BUTTON, GtkButton))
#define GTK_BUTTON_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), \
                                    GTK_TYPE_BUTTON, GtkButtonClass))
#define GTK_IS_BUTTON(obj)         (GTK_CHECK_TYPE ((obj),  \
                                    GTK_TYPE_BUTTON))
#define GTK_IS_BUTTON_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass),  \
                                    GTK_TYPE_BUTTON))


Invece di eseguire il semplice cast, potete utilizzare la macro GTK_BUTTON(). Se GTK_NO_CHECK_CASTS viene definito, queste macro sono equivalenti ai semplice cast. Altrimenti, ottengono l'identificatore del tipo di oggetto e lo comparano con il tipo verso il quale volete eseguite il cast.

GTK+ fornisce inoltre utilissimi controlli a runtime, attraverso la macro GTK_IS_BUTTON(). Questa è spesso utilizzata nelle precondizioni. Ad esempio, una funzione che aspetta un pulsante come argomento può contenere questo controllo all'inizio:


  g_return_if_fail(GTK_IS_BUTTON(widget));

Le funzioni delle librerie GTK+ e Gnome utilizzano tantissimi di questi controlli. È inoltre possibile utilizzare la macro per effettuare determinate condizioni sul tipo dell'oggetto, anche se questo risulta una cattiva idea dal punto di vista della progettazione.

Per darvi una idea di che tipo di informazioni GTK+ gestisce per ciascun tipo di oggetto, ecco l'implementazione di gtk_button_get_type():


GtkType
gtk_button_get_type (void)
{
  static GtkType button_type = 0;

  if (!button_type)
    {
      static const GtkTypeInfo button_info =
      {
        "GtkButton",
        sizeof (GtkButton),
        sizeof (GtkButtonClass),
        (GtkClassInitFunc) gtk_button_class_init,
        (GtkObjectInitFunc) gtk_button_init,
        /* Riservato 1 */ NULL,
        /* Riservato 22 */ NULL,
        (GtkClassInitFunc) NULL,
      };

      button_type = gtk_type_unique (GTK_TYPE_BIN, &button_info);
      gtk_type_set_chunk_alloc (button_type, 16);
    }

  return button_type;
}


Il codice riempie una struttura di dati con informazioni riguardo la classe, quindi utilizza la struttura per ottenere un identificatore del tipo (GtkType). Sono necessari solo sei componenti della struttura GtkTypeInfo. GtkButton fornisce a GTK+ un nome umanamente leggibile, per poterlo utilizzare nei messaggi di errore; la dimensione dell'istanza e la struttura della classe; una funzione per inizializzare la struttura della classe e un'altra per inizializzare ciascuna nuova istanza. Il sesto e settimo membro della struttura (Riservato 1 e Riservato 2) sono obsoleti, mantenuti solo per questioni di compatilibità. Il membro finale è un puntatore alla funzione di inizializzazione della classe di base, utilizzato per inizializzare la struttura della classe di qualunque sottoclasse.

gtk_type_unique() registra un nuovo tipo e ne ottiene un identificatore. L'argomento GTK_TYPE_BIN è una macro contenente il tipo della classe superiore di GtkButton, GtkBin. La chiamata a gtk_type_set_chunk_alloc() ottimizza l'allocazione di memoria per questo tipo. Non è mai richiesta, e dovrebbe essere utilizzata unicamente per tipi allocati molto di frequente, come appunto GtkButton.

Una volta registrato il tipo GtkButton, il seguente codice crea una nuova istanza del tipo:


GtkWidget*
gtk_button_new (void)
{
  return GTK_WIDGET (gtk_type_new (gtk_button_get_type ()));
}


Il nascituro GtkButton verrà inizializzato come nuova istanza. La funzione che ne inizializza ogni istanza viene chiamata ogni volta che una istanza di tipo viene creata:


static void
gtk_button_init (GtkButton *button)
{
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS);
  GTK_WIDGET_UNSET_FLAGS (button, GTK_NO_WINDOW);

  button->child = NULL;
  button->in_button = FALSE;
  button->button_down = FALSE;
  button->relief = GTK_RELIEF_NORMAL;
}


Ricordate che gtk_button_init() è stata passata come argomento a gtk_type_unique() quando abbiamo creato il tipo GtkButton. GTK+ registra il puntatore a funzione e lo utilizza per creare le istanze di GtkButton.

Le strutture per le istanze sono create inizialmente con tutti i bit posti uguali a zero. Non è quindi strettamente necessario porli manualmente uguali a zero oppure a NULL.

Le funzioni per l'inizializzazione della classe e della classe di base richiedono una descrizione aggiuntiva per essere comprese. Saprete come scriverle dopo aver letto questo capitolo.


Copyright © 1995-1999 Apogeo srl, Milano