Después de que ha instalado GTK+, hay un par de cosas que pueden facilitarle el desarrollo de aplicaciones con él. Está el Tutor de GTK+ <http://www.gtk.org/tutorial/>, el cual está en desarrollo activo. Este tutorial le introducirá en la escritura de aplicaciones utilizando C.
El Tutor no contiene (todavía) información sobre todos los widgets que existen en GTK+. Para código de ejemplo sobre la utilización básica de todos los widgets de GTK+, debe ver el archivo gtk/testgtk.c (y archivos fuentes asociados) en la distribución GTK+. Ver estos ejemplos le dará una buena base sobre lo que pueden hacer los widgets.
El Tutor de GTK+ lista los siguientes widgets:
GtkObject +GtkData | +GtkAdjustment | `GtkTooltips `GtkWidget +GtkContainer | +GtkBin | | +GtkAlignment | | +GtkEventBox | | +GtkFrame | | | `GtkAspectFrame | | +GtkHandleBox | | +GtkItem | | | +GtkListItem | | | +GtkMenuItem | | | | `GtkCheckMenuItem | | | | `GtkRadioMenuItem | | | `GtkTreeItem | | +GtkViewport | | `GtkWindow | | +GtkColorSelectionDialog | | +GtkDialog | | | `GtkInputDialog | | `GtkFileSelection | +GtkBox | | +GtkButtonBox | | | +GtkHButtonBox | | | `GtkVButtonBox | | +GtkHBox | | | +GtkCombo | | | `GtkStatusbar | | `GtkVBox | | +GtkColorSelection | | `GtkGammaCurve | +GtkButton | | +GtkOptionMenu | | `GtkToggleButton | | `GtkCheckButton | | `GtkRadioButton | +GtkCList | `GtkCTree | +GtkFixed | +GtkList | +GtkMenuShell | | +GtkMenuBar | | `GtkMenu | +GtkNotebook | +GtkPaned | | +GtkHPaned | | `GtkVPaned | +GtkScrolledWindow | +GtkTable | +GtkToolbar | `GtkTree +GtkDrawingArea | `GtkCurve +GtkEditable | +GtkEntry | | `GtkSpinButton | `GtkText +GtkMisc | +GtkArrow | +GtkImage | +GtkLabel | | `GtkTipsQuery | `GtkPixmap +GtkPreview +GtkProgressBar +GtkRange | +GtkScale | | +GtkHScale | | `GtkVScale | `GtkScrollbar | +GtkHScrollbar | `GtkVScrollbar +GtkRuler | +GtkHRuler | `GtkVRuler `GtkSeparator +GtkHSeparator `GtkVSeparator
Aunque GTK+, como la mayoría de los juegos de herramientas para X, no es seguro ante múltiples hilos, esto no prohibe el desarrollo de aplicaciones con múltiples hilos con GTK+.
Rob Browning (rlb@cs.utexas.edu) describe técnicas de hilamiento que pueden utilizarse con GTK+ (levemente modificado):
Básicamente existen dos enfoques principales, el primero es sencillo, y el segundo complicado. En el primero, simplemente hay que asegurarse de que todas las interacciones de GTK+ (o X) se manejan por un, y solo un, hilo. Cualquier otro hilo que desee dibujar algo tiene que notificarlo de alguna manera al hilo "GTK+", y dejarlo que maneje el trabajo real.
El segundo enfoque le permite llamar funciones de GTK+ (o X) desde cualquier hilo, pero requiere sincronización cuidadosa. La idea básica es crear una exclusión mutua de protección para X, de manera que nadie haga llamadas X sin primero adquirir esta exclusión mutua.
Observe que se trata de un pequeño esfuerzo, pero que le permitirá ser potencialmente más eficiente que un GTK+ completamente seguro ante múltiples hilos. Usted decide la granularidad del bloqueo de hilos. También debe asegurarse que el hilo que llama a gtk_main mantiene la cerradura cuando llama a gtk_main.
Lo siguiente por lo que hay que preocuparse ya que se tenía agarrada la exclusión mutua global cuando se entró a gtk_main, es que todos los callbacks también la tendrán. Esto significa que el callback debe soltarla si va a llamar a cualquier otro código que pueda readquirirla. De otra manera obtendrá un bloqueo mortal. También hay que tener agarrada la exclusión mutua cuando finalmente regresa del callback.
Para permitir a otros hilos, además del que llama a gtk_main, tener acceso a la exclusión mutua, necesitamos registrar una función de trabajo con GTK que nos permita liberar la exclusión mutua periódicamente.
¿Por qué GTK+ no puede ser seguro ante múltiples hilos de manera nativa?
Complejidad, sobrecarga, y mano de obra. La proporción de programas con hilos es todavía razonablemente pequeña, y conseguir seguridad ante hilos es muy difícil y le quita tiempo valioso al trabajo principal de obtener una buena librería gráfica terminada. Sería muy agradable que GTK+ fuera seguro ante hilos "al sacarlo de la caja", pero no es práctico ahora mismo, y haría a GTK+ sustancialmente menos eficiente si no se maneja cuidadosamente.
De cualquier manera, no es una prioridad esencial ya que existen remedios relativamente buenos.
Utilize gtk_container_disable_resize y gtk_container_enable_resize alrededor del código donde quiere cambiar varias cosas. Esto resultará en mayor velocidad ya que prevendrá tener que darle el tamaño otra vez a la jerarquía de widget por completo.
Tim Janik escribió a la lista gtk-list (ligeramente modificado):
Defina un manejador de señal:
gint
signal_handler_event(GtkWiget *widget, GdkEvenButton *event, gpointer func_data)
{
if (GTK_IS_LIST_ITEM(widget) &&
(event->type==GDK_2BUTTON_PRESS ||
event->type==GDK_3BUTTON_PRESS) ) {
printf("I feel %s clicked on button %d\",
event->type==GDK_2BUTTON_PRESS ? "double" : "triple",
event->button);
}
return FALSE;
}
Y conecte el manejador a su objeto:
{
/* lista, asuntos de inicializacion de articulos de lista */
gtk_signal_connect(GTK_OBJECT(list_item),
"button_press_event",
GTK_SIGNAL_FUNC(signal_handler_event),
NULL);
/* y/o */
gtk_signal_connect(GTK_OBJECT(list_item),
"button_release_event",
GTK_SIGNAL_FUNC(signal_handler_event),
NULL);
/* algo mas */
}
y, Owen Taylor escribió:
Observe que se recibirá la pulsación del botón de antemano, y si está haciendo esto para un botón, también obtendrá una señal de "tecleado" para el botón. (Esto es cierto para cualquier juego de herramientas, ya que las computadoras no son buenas para leer la mente de cada quien.)
Consiga la selección con algo como esto:
GList *sel;
sel = GTK_LIST(list)->selection;
Así es como GList está definido (sacado de glist.h):
typedef struct _GList GList;
struct _GList
{
gpointer data;
GList *next;
GList *prev;
};
Una estructura GList es simplemente una estructura para listas doblemente enlazadas. Existen varias funciones g_list_*() para modificar una lista enlazada en glib.h. Sin embargo, la selección GTK_LIST(MyGtkList)->selection es mantenida por las funciones gtk_list_*() y no deben ser modificadas.
El selection_mode del GtkList determina las facilidades de selección de un GtkList y por lo tanto los contenidos de GTK_LIST(AnyGtkList)->selection:
selection_mode GTK_LIST()->selection contents ------------------------------------------------------ GTK_SELECTION_SINGLE) la selección es NULL o contiene un puntero GList* para un artículo seleccionado individualmente GTK_SELECTION_BROWSE) la selección es NULL si la lista no contiene widgets, de otra manera contiene un puntero GList* para una estructura GList. GTK_SELECTION_MULTIPLE) la selección es NULL si no se seleccionan listitems para un apuntador GList* para el primer artículo seleccionado. Eso en su lugar apunta a una estructura GList para el segundo artículo seleccionado y continúa GTK_SELECTION_EXTENDED) la selección es NULL.
El campo data de la estructura GList GTK_LIST(MyGtkList)->selection apunta al primer GtkListItem que es seleccionado. De manera que si quiere determinar cuales listitems están seleccionados debe hacer esto:
Durante la in>
Para tener conocimiento de la inicialización:
{
GList *items;
items=GTK_LIST(list)->selection;
printf("Selected Items: ");
while (items) {
if (GTK_IS_LIST_ITEM(items->data))
printf("%d ", (guint)
gtk_object_get_user_data(items->data));
items=items->next;
}
printf("\n");
}
El comportamiento de GTK+ (sin recorte) es una consecuencia de sus intentos para conservar recursos de X. Los widgets etiqueta (entre otros) no tienen su propia ventana X - simplemente dibujan su contenido en la ventana de su padre. Aunque sería posible hacer que ocurran recortes al establecer la máscara de recorte antes de dibujar el texto, esto podría causar una penalización substancial en el rendimiento.
Es posible que, a largo plazo, la mejor solución a tales problemas sea simplemente cambiar gtk para que le de ventanas X a las etiquetas. Un remedio a corto plazo es poner el widget de etiqueta dentro de otro widget que sí obtiene su propia ventana - un candidato posible puede ser el widget viewport.
viewport = gtk_viewport (NULL, NULL);
gtk_widget_set_usize (viewport, 50, 25);
gtk_viewport_set_shadow_type (GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
gtk_widget_show(viewport);
label = gtk_label ("a really long label that won't fit");
gtk_container_add (GTK_CONTAINER(viewport), label);
gtk_widget_show (label);
Si estuviera haciendo esto para un montón de widgets, querrá copiar gtkviewport.c y arrancar la funcionalidad de sombra y ajuste (tal vez quiera llamarlo GtkClipper).
De: Peter Mattis
La razón por la cuál los botones no mueven a su hijo abajo y a la derecha cuando son presionados es porque no me parece que eso es lo que ocurre visualmente. Mi visión de los botonos es que los miras de manera recta. O sea, la interface de usuario tiende sobre un plano y tú estás sobre él observándolo de manera recta. Cuando un botón es presionado se mueve directamente lejos de tí. Para ser absolutamente correcto supongo que el hijo debería encojerse un poquito. Pero no veo por qué el hijo debería moverse abajo y a la izquierda. Recurda, el hijo se supone que está pegado a la superficie del botón. No es bueno que luzca como si el hijo se resbala sobre la superficie del botón.
En una nota más práctica, ya implanté esto una vez y determiné que no se veía bien y lo quité.
Revise el Tutor para información sobre como crear menús.
Sin embargo, para crear una línea de separación en un menú, simplemente inserte un artículo de menú vacío:
menuitem = gtk_menu_item_new();
gtk_menu_append(GTK_MENU(menu), menuitem);
gtk_widget_show(menuitem);
Utilice algo como lo que sigue:
menu_path = gtk_menu_factory_find (factory, "<MyApp>/Help");
gtk_menu_item_right_justify(menu_path->widget);
Después de haber creado su ventana, haga gtk_grab_add(my_window). Y después de cerrar la ventana haga gtk_grab_remove(my_window).
Probablemente usted está haciendo todos los cambios dentro de una función sin devolver el control a gtk_main. La mayoría de las actualizaciones de dibujo se colocan simplemente en una cola, la cual es procesada dentro de gtk_main. Puede forzar que se procese la cola de dibujado utilizando algo como:
while (gtk_events_pending())
gtk_main_iteration();
dentro de la función que cambia el widget.
Lo que el fragmento anterior hace es correr todos los eventos pendientes y funciones ociosas de alta prioridad, luego regresa de inmediato (el dibujado se realiza en una función ociosa de alta prioridad).