📄 gtk_tut_it-19.html
字号:
guint gtk_dial_get_type (void);GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);void gtk_dial_set_update_policy (GtkDial *dial, GtkUpdateType policy);void gtk_dial_set_adjustment (GtkDial *dial, GtkAdjustment *adjustment);#ifdef __cplusplus}#endif /* __cplusplus */#endif /* __GTK_DIAL_H__ */</PRE></CODE></BLOCKQUOTE><P>Essendoci più cose da fare con questo widget, rispetto al precedente,abbiamo più cambi nella struttura dati, ma le altre cose sono abbastamza simili.<P>Dopo aver incluso i file di header e aver dichiarato alcune costanti,dobbiamo fornire alcune funzioni circa il widget e la suainizializzazione.<P><BLOCKQUOTE><CODE><PRE>#include <math.h>#include <stdio.h>#include <gtk/gtkmain.h>#include <gtk/gtksignal.h>#include "gtkdial.h"#define SCROLL_DELAY_LENGTH 300#define DIAL_DEFAULT_SIZE 100/* Dichiarazioni di funzioni successive */[ omesse per salvare spazio ]/* variabili locali. */static GtkWidgetClass *parent_class = NULL;guintgtk_dial_get_type (){ static guint dial_type = 0; if (!dial_type) { GtkTypeInfo dial_info = { "GtkDial", sizeof (GtkDial), sizeof (GtkDialClass), (GtkClassInitFunc) gtk_dial_class_init, (GtkObjectInitFunc) gtk_dial_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info); } return dial_type;}static voidgtk_dial_class_init (GtkDialClass *class){ GtkObjectClass *object_class; GtkWidgetClass *widget_class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; parent_class = gtk_type_class (gtk_widget_get_type ()); object_class->destroy = gtk_dial_destroy; widget_class->realize = gtk_dial_realize; widget_class->expose_event = gtk_dial_expose; widget_class->size_request = gtk_dial_size_request; widget_class->size_allocate = gtk_dial_size_allocate; widget_class->button_press_event = gtk_dial_button_press; widget_class->button_release_event = gtk_dial_button_release; widget_class->motion_notify_event = gtk_dial_motion_notify;}static voidgtk_dial_init (GtkDial *dial){ dial->button = 0; dial->policy = GTK_UPDATE_CONTINUOUS; dial->timer = 0; dial->radius = 0; dial->pointer_width = 0; dial->angle = 0.0; dial->old_value = 0.0; dial->old_lower = 0.0; dial->old_upper = 0.0; dial->adjustment = NULL;}GtkWidget*gtk_dial_new (GtkAdjustment *adjustment){ GtkDial *dial; dial = gtk_type_new (gtk_dial_get_type ()); if (!adjustment) adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); gtk_dial_set_adjustment (dial, adjustment); return GTK_WIDGET (dial);}static voidgtk_dial_destroy (GtkObject *object){ GtkDial *dial; g_return_if_fail (object != NULL); g_return_if_fail (GTK_IS_DIAL (object)); dial = GTK_DIAL (object); if (dial->adjustment) gtk_object_unref (GTK_OBJECT (dial->adjustment)); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);}</PRE></CODE></BLOCKQUOTE><P>Notate che questa funzione <CODE>init()</CODE> fa meno rispetto all'analoga delwidget Tictactoe, essendo questo un widget non composto, e la funzione <CODE>new()</CODE> fa di più, essendoci un argomento. Inoltre, notate che quando memorizziamo un puntatore all'oggetto Adjustment,incrementiamo il conteggio dei suoi riferimenti(e corrispondentemente lo decrementato quando non lo usiamo più) così che GTK può tener traccia di quando è possibile distruggerlo senza causare guai.<P><P>Inoltre, ci sono alcune funzioni per manipolare le opzioni del widget:<P><BLOCKQUOTE><CODE><PRE>GtkAdjustment*gtk_dial_get_adjustment (GtkDial *dial){ g_return_val_if_fail (dial != NULL, NULL); g_return_val_if_fail (GTK_IS_DIAL (dial), NULL); return dial->adjustment;}voidgtk_dial_set_update_policy (GtkDial *dial, GtkUpdateType policy){ g_return_if_fail (dial != NULL); g_return_if_fail (GTK_IS_DIAL (dial)); dial->policy = policy;}voidgtk_dial_set_adjustment (GtkDial *dial, GtkAdjustment *adjustment){ g_return_if_fail (dial != NULL); g_return_if_fail (GTK_IS_DIAL (dial)); if (dial->adjustment) { gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial); gtk_object_unref (GTK_OBJECT (dial->adjustment)); } dial->adjustment = adjustment; gtk_object_ref (GTK_OBJECT (dial->adjustment)); gtk_signal_connect (GTK_OBJECT (adjustment), "changed", (GtkSignalFunc) gtk_dial_adjustment_changed, (gpointer) dial); gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", (GtkSignalFunc) gtk_dial_adjustment_value_changed, (gpointer) dial); dial->old_value = adjustment->value; dial->old_lower = adjustment->lower; dial->old_upper = adjustment->upper; gtk_dial_update (dial);}</PRE></CODE></BLOCKQUOTE><P><H3><CODE>gtk_dial_realize()</CODE></H3><P>Abbiamo ora raggiunto alcuni nuovi tipi di funzione. In primo luogo,abbiamo una funzione che crea la finestra di X. Noterete che vienepassata alla funzione <CODE>gdk_window_new()</CODE> una maschera che specifica quali campi della struttura GdkWindowAttr non sono vuoti (ai rimanenti campi può essere dato il valore predefinito). Anche il modo con cui la maschera degli eventi del widget creata non ècomplicato. Chiameremo <CODE>gtk_widget_get_events()</CODE> per sapere la maschera degli eventi che l'utente ha specificato per questo widget(con <CODE>gtk_widget_set_events()</CODE>) e aggiungeremo gli eventi che ci possono interessare.<P><P>Dopo aver creato la finestra, settiamo lo stile e lo sfondo,e creiamo un puntatore al widget nel campo dei dati utente (user data)del GdkWindow. Quest'ultimo passo permette a GTK di mandare gli eventi della finestra al widget corretto.<P><BLOCKQUOTE><CODE><PRE>static voidgtk_dial_realize (GtkWidget *widget){ GtkDial *dial; GdkWindowAttr attributes; gint attributes_mask; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_DIAL (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); dial = GTK_DIAL (widget); attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); widget->style = gtk_style_attach (widget->style, widget->window); gdk_window_set_user_data (widget->window, widget); gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);}</PRE></CODE></BLOCKQUOTE><P><H3>Negoziazione della dimensione</H3><P>Prima di visualizzare per la prima volta la finestra, e se il layout della finestra cambia, GTK chiede ad ogni widget, incluso nellafinestra, la propria dimensione. Questa richiesta è fatta dallafunzione <CODE>gtk_dial_size_request()</CODE>. Non essendo il nostro widget un contenitore, e non avendo dei veri limiti per la propriadimensione, restituiamo semplicemnte un valore ragionevole.<P><BLOCKQUOTE><CODE><PRE>static void gtk_dial_size_request (GtkWidget *widget, GtkRequisition *requisition){ requisition->width = DIAL_DEFAULT_SIZE; requisition->height = DIAL_DEFAULT_SIZE;}</PRE></CODE></BLOCKQUOTE><P><P>Dopo che tutti i widget hanno restituito una dimensione ideale, viene calcolata la disposizione della finestra e ad ogni widget figlio ènotificata la propria dimensione attuale . Usualmente, questo sarà almeno quanto richiesto, ma occasionalmente può essere più piccolo. La notifica della dimensione viene fatta dalla funzione<CODE>gtk_dial_size_allocate()</CODE>. Notate che questa funzione è utilizzataanche quando la finestra X del widget è spostata o modificata come dimensione.<P><BLOCKQUOTE><CODE><PRE>static voidgtk_dial_size_allocate (GtkWidget *widget, GtkAllocation *allocation){ GtkDial *dial; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_DIAL (widget)); g_return_if_fail (allocation != NULL); widget->allocation = *allocation; if (GTK_WIDGET_REALIZED (widget)) { dial = GTK_DIAL (widget); gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); dial->radius = MAX(allocation->width,allocation->height) * 0.45; dial->pointer_width = dial->radius / 5; }}</PRE></CODE></BLOCKQUOTE>.<P><H3><CODE>gtk_dial_expose()</CODE></H3><P>Come menzionato sopra, tutto il lavoro di questo widget viene fatto nellagestione dell'evento ``expose''. Non c'è molto da notare su questo eccettol'uso della funzione <CODE>gtk_draw_polygon</CODE> per disegnare il puntatore con un'ombreggiatura a tre dimensioni in accordo con il colorememorizzato nello stile del wiget.<P><BLOCKQUOTE><CODE><PRE>static gintgtk_dial_expose (GtkWidget *widget, GdkEventExpose *event){ GtkDial *dial; GdkPoint points[3]; gdouble s,c; gdouble theta; gint xc, yc; gint tick_length; gint i; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); if (event->count > 0) return FALSE; dial = GTK_DIAL (widget); gdk_window_clear_area (widget->window, 0, 0, widget->allocation.width, widget->allocation.height); xc = widget->allocation.width/2; yc = widget->allocation.height/2; /* Draw ticks */ for (i=0; i<25; i++) { theta = (i*M_PI/18. - M_PI/6.); s = sin(theta); c = cos(theta); tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2; gdk_draw_line (widget->window, widget->style->fg_gc[widget->state], xc + c*(dial->radius - tick_length), yc - s*(dial->radius - tick_length), xc + c*dial->radius, yc - s*dial->radius); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -