XFORMS (FORM LIBRARY) Toolkit per la costruzione di interfacce grafiche (GUI) nel sistema X Window. Principali vantaggi: - Software di pubblico dominio, disponibile su diverse piattaforme - Si basa su libreria Xlib - Molte funzionalita' - Semplice e intuitivo - Comprende un Form Designer per la creazione interattiva di GUI A differenza di altri toolkit (per es. Motif), nasconde completamente X al programmatore: non e' necessario conoscere X per programmare in XForms. +---------------+ +---------------+ |Applicazione | |Applicazione | +----------+--+-+ +---------------+ |Motif | | | | | +----------+ | | |XForms | |Xt intrinsics| | | | +-------------+ | +---------------+ |Xlib | |Xlib | +---------------+ +---------------+ Concetti base (Terminologia): - Una form e' una finestra-contenitore in cui sono sistemati vari oggetti; una form e' una finestra X situata a top-level, e gestita dal window manager - Gli oggetti sono elementi di interfaccia contenuti in una form, attraverso i quali si svolge l'interazione tra utente e applicazione; es: bottoni, campi di inserimento, ecc. un oggetto e' una sotto-finestra X, avente un certo aspetto distintivo e certe capacita' di interazione (sensibile a certi eventi) XForms non adopera il termine "widget". OGGETTI Oggetti statici (non hanno capacita' di interazione, servono solo per visualizzare) - Box: area rettangolare contenente testo - Frame: cornice racchiudente area rettangolare (puo' racchiudere altri oggetti - Text: testo alfanumerico - Bitmap: immagine raster B/N (matrice di bit) - Pixmap: immagine raster a colori o a livelli di grigio - Clock: orologio analogico o digitale - Chart: area rettangolare destinata a contenere grafici a linea, a barre, a torta, ecc. Bottoni (interazione col mouse tramite click) - Button: varie classi e tipi di bottoni (ved. piu' avanti) Quantificatori (interazione col mouse mediante click o trascinamento, permettono di introdurre un valore numerico) - Slider: vari tipi di potenziometri lineari - Dial: vari tipi di potenziometri rotanti - Counter: potenziometro digitale - Positioner: fornisce non un singolo valore, ma una coppia di coordinate (x,y) in un'area rettangolare indicata Campi di input (attivazione col mouse, input da tastiera) - Input: campo di una o piu' linee contenente un cursore Selezionatori (interazione col mouse tramite click, permettono di immettere una scelta tra un insieme predefinito) - Menu: diversi tipi di menu' (push, pulldown, touch) - Choice: stessa funzione dei menu', ma ha un unico bottone che mostra in ogni momento la scelta corrente, la scelta corrente puo' essere cambiata ciclando sull'insieme delle scelte possibili - Browser: si una per lunghe liste di scelte, permette di muoversi attraverso la lista e selezionare elementi attraverso un cursore (scrollbar) Inoltre: - Timer: contatore alla rovescia - XYPlot: consente di disegnare e modificare agevolmente funzioni - Canvas: sottofinestra utilizzabile per output grafico; in un canvas posso utilizzare X direttamente, scavalcando XForms; in particolare, posso usare altri pacchetti grafici operanti sotto X. Noi useremo un canvas per fare grafica in OpenGL. STRUTTURA DI UN PROGRAMMA IN XFORMS Un programma applicativo che utilizza XForms deve contenere le seguenti parti: -A- Inizializzazione: stabilisce connessione tra programma e X-server, e inizializza strutture interne di XForms -B- Definizione delle (una o piu') form necessarie al programma, con tutti i loro oggetti -C- Visualizzazione delle form per rendere visibile la GUI -D- Interazione (main loop): gestione dell'interazione con l'utente e delle operazioni che il programma deve compiere di conseguenza INTERAZIONE CON L'UTENTE: PRINCIPIO DI FUNZIONAMENTO (ci torneremo) - utente interagisce con gli oggetti generando evevnti - XForms pesca gli eventi dalla coda di X e li associa agli oggetti - a questo punto deve essere chiamato il codice applicativo che gestisce l'evento; vi sono due vie possibili: 1) il programmatore definisce (nella fase -B-) callback associate a ogni oggetto, e demanda a XForms il compito di chiamare la callback opportuna in risposta all'evento 2) in assenza di callback, XForms passa il controllo al programma, che dovra' guardare di che evento ed oggetto si tratta, e agire di conseguenza - il controllo passa quindi alle procedure applicative (siano esse callback o no) per il tempo necessario a compiere tali operazioni - quindi XForms riprende il controllo per gestire gli eventi successivi Nota: XForms si pone sempre come "cuscinetto" tra applicazione e Xlib, Xlib rimane trasparente al programmatore. Vediamo le funzioni di XForms relative alle 4 fasi. INIZIALIZZAZIONE fl_initialize ( &argc, argv, , 0, 0); argc, argv = argomenti passati al main da command line = titolo dell'applicazione (char *) DEFINIZIONE DELLE FORMS FL_FORM * fl_bgn_form(, w, h); = tipo di form (costante simbolica) w, h = larghezza e altezza (in pixel) FL_OBJECT * fl_add_XXXX(....); XXXX = tipo di oggetto che aggiungo alla form .... = parametri per definire l'oggetto void fl_end_form(); Tra fl_bgn_form e fl_end_form trovano posto le definizioni di tutti gli oggetti contenuti nella form (mediante fl_add_XXXX). VISUALIZZAZIONE DELLE FORM fl_show_form(
, , , ); = la form da visualizzare (FL_FORM * ritornato da fl_bgn_form quando ho definito la form) = indica come deve essere posizionata di preferenza la form (costante simbolica) = indica che tipo di bordo deve essere aggiunto di preferenza alla form (costante simbolica) fl_hide_form(); MAIN LOOP FL_OBJECT * fl_do_forms(); Attende che un evento accada in qualche oggetto. In assenza di callback, non appena accade un evento esce e ritorna l'oggetto in cui l'evento e' accaduto. Il programma poi agira' di conseguenza. Se invece ho definito una callback per l'oggetto in cui l'evento si e' verificato, la callback e' eseguita automaticamente, senza che si esca dal ciclo. ESEMPIO DI PROGRAMMA SENZA CALLBACK (ved. file yesno.c) Crea una form con un titolo testuale "Do you want to quit?" e due bottoni "Yes" e "No". Visualizza la form, poi chiama fl_do_forms(). Quando uno dei due bottoni viene premuto, fl_do_forms() esce e lo ritorna. Se il bottone premuto e' "Yes", il programma esce, altrimenti chiama nuovamente fl_do_forms(), e cosi' via. #include "forms.h" FL_FORM *form; FL_OBJECT *yes, *no, *but; main (int argc, char *argv[]) { /*** Inizializzazione ***/ fl_initialize ( &argc, argv, "FormDemo", 0, 0); /*** Definizione forms ***/ form = fl_bgn_form(FL_UP_BOX, 320, 120); /* crea form con aspetto di box tridimensionale sporgente da schermo, larga 320 pixel e alta 120 */ fl_add_box(FL_NO_BOX, 160, 40, 0, 0, "Do you want to quit?"); /* aggiunge alla form che sto definendo un box contenente la scritta "Do you want to quit?" */ yes = fl_add_button(FL_NORMAL_BUTTON, 40, 70, 80, 30, "Yes"); /* aggiunge alla form un bottone di etichetta "Yes", posizionato con l'angolo in alto a sinistra nel punto 40,70 della form, largo 80 pixel e alto 30 */ no = fl_add_button(FL_NORMAL_BUTTON, 200, 70, 80, 30, "No"); /* analogo per bottone "No" */ fl_end_form(); /*** Visualizzazione forms ***/ fl_show_form(form, FL_PLACE_MOUSE,FL_TRANSIENT,"Question"); /* FL_TRANSIENT causa un tipo di bordo adatto a finestre che devono stare visualizzate per poco tempo */ /*** Main loop ***/ while ( (but = fl_do_forms()) != yes ) ; /* fintanto che il bottone cliccato non e' yes, continua a ciclare */ /*** Terminazione ***/ fl_hide_form(form); return 0; } INTERAZIONE La procedura FL_OBJECT * fl_do_forms() gestisce l'interazione con l'utente nel seguente modo: -1- tiene il controllo da quando viene invocata a quando si verifica un evento proveniente da un oggetto usato nel programma -2a- a tale oggetto il programmatore potrebbe aver associato una callback, nel qual caso fl_do_forms() chiama automaticamente la callback, e al termine della callback riprende il controllo -2b- se l'oggetto in cui si e' verificato l'evento non ha una callback associata, allora fl_do_forms() esce, restituendo l'oggetto, e il controllo passa al programma Una callback e' una procedura del programma applicativo che viene associata a un oggetto in fase di definizione e che viene eseguita ogni volta che tale oggetto genera un evento. Una procedura di callback accetta due parametri (che vengono passati automaticamente da XForms): - un oggetto (tipo FL_OBJECT *) ---> quello che ha generato l'evento - un intero (tipo long) ---> deciso dal programmatore quando ha associato la callback all'oggetto, e' usato come switch per poter adoperare la stessa callback per diversi eventi La procedura callback (nel caso -2a-) o il programma (nel caso -2b-) deve interpretare l'evento che si e' verificato interrogando l'oggetto che lo ha prodotto con apposite procedure, in modo da poter decidere che cosa fare. Nota: un oggetto ha una sola callback per tutti gli eventi a cui e' sensibile, il tipo di evento lo devo determinare io interrogando l'oggetto. STESSO ESEMPIO DI PRIMA RISCRITTO USANDO CALLBACK (ved. file yncallbk.c) #include "forms.h" FL_FORM *form; void yes_callback(FL_OBJECT *ob, long user_data) { printf("Yes is pushed\n"); fl_finish(); exit(0); } void no_callback(FL_OBJECT *ob, long user_data) { printf("No is pushed\n"); } main (int argc, char *argv[]) { FL_OBJECT *obj; /*** Inizializzazione ***/ fl_initialize ( &argc, argv, "FormDemo", 0, 0); /*** Definizione forms ***/ form = fl_bgn_form(FL_UP_BOX, 320, 120); /* crea form con aspetto di box tridimensionale sporgente da schermo, larga 320 pixel e alta 120 */ fl_add_box(FL_NO_BOX, 160, 40, 0, 0, "Do you want to quit?"); /* aggiunge alla form che sto definendo un box contenente la scritta "Do you want to quit?" */ obj = fl_add_button(FL_NORMAL_BUTTON, 40, 70, 80, 30, "Yes"); /* aggiunge alla form un bottone di etichetta "Yes", posizionato con l'angolo in alto a sinistra nel punto 40,70 della form, largo 80 pixel e alto 30 */ fl_set_object_callback(obj, yes_callback, 0); /* assegna al bottone "Yes" la callback */ obj = fl_add_button(FL_NORMAL_BUTTON, 200, 70, 80, 30, "No"); fl_set_object_callback(obj, no_callback, 0); /* analogo per bottone "No" */ fl_end_form(); /*** Visualizzazione forms ***/ fl_show_form(form, FL_PLACE_MOUSE,FL_TRANSIENT,"Question"); /* FL_TRANSIENT causa un tipo di bordo adatto a finestre che devono stare visualizzate per poco tempo */ /*** Main loop ***/ fl_do_forms(); /* poiche' ogni oggetto capace di catturare eventi ha una callback, fl_do_forms() non esce mai, la terminazione del programma avviene dentro la callback di "Yes" */ } SCHEMI DI PROGRAMMA NELLE DUE MODALITA' DI GESTIONE DELL'INTERAZIONE Interazione semplice: while (!ready) { obj = fl_do_forms(); } Interazione con callback: fl_do_forms(); ESEMPIO DI INTERAZIONE SEMPLICE (ved. file demo05.c) Visualizza una form contenente uno slider, un box la cui etichetta mostra il valore corrente dello slider (aggiornato da programma ogni volta che l'utente interagisce con lo slider), e un bottone "Exit". #include #include "forms.h" int main(int argc, char *argv[]) { FL_FORM *form; FL_OBJECT *retobj, *slider, *button, *value; char str[30]; fl_initialize(&argc, argv, "FormDemo", 0, 0); form = fl_bgn_form(FL_UP_BOX,240,400); /* aggiunge slider alla form corrente */ slider = fl_add_slider(FL_VERT_SLIDER,40,40,60,320,""); /* assegna valori limite dello slider */ fl_set_slider_bounds(slider,-1,1); /* assegna valore iniziale dello slider */ fl_set_slider_value(slider,0); /* assegna attributo colore del cursore */ fl_set_object_color(slider,FL_SLIDER_COL1,FL_GREEN); /* aggiunge box, per ora con etichetta nulla */ value = fl_add_box(FL_DOWN_BOX,120,180,100,30,""); /* assegna attributo allineamento della label del box */ fl_set_object_lalign(value,FL_ALIGN_CENTER); /* aggiunge bottone "Exit" */ button = fl_add_button(FL_RETURN_BUTTON,120,290,100,30,"Exit"); fl_end_form(); fl_show_form(form,FL_PLACE_CENTER,FL_NOBORDER,"Slider"); do { sprintf(str,"%f",fl_get_slider_value(slider)); fl_set_object_label(value,str); retobj = fl_do_forms(); } while (retobj != button); fl_hide_form(form); return 0; } TIPI DI FORMS (per fl_bgn_form) FL_UP_BOX FL_DOWN_BOX FL_BORDER_BOX FL_FLAT_BOX ... POSIZIONI DI UNA FORM (per fl_show_form) FL_PLACE_FREE FL_PLACE_MOUSE FL_PLACE_FULLSCREEEN FL_PLACE_ICONIC ... AGGIUNGERE OGGETTI DENTRO UNA FORM Box FL_OBJECT * fl_add_box(, x,y, w,h,