El widget Notebook es una colección de `páginas' que se solapan las unas a las otras, cada unas con un contenido diferente. Este widget se ha vuelto cada vez más común últimamente en la programación de interfaces gráficos de usuario (GUI en inglés), y es una buena forma de mostrar bloques de información similar que necesitan aparecer de forma separada.
La primera función que necesita conocer, como probablemente ya habrá adivinado, se utiliza para crear un nuevo widget notebook.
GtkWidget *gtk_notebook_new( void );
Una vez haya crear el libro de notas, hay 12 funciones que se pueden utilizar para trabajar con él. Echémosles un vistazo una a una.
La primera que estudiaremos será la que nos permita establecer la posición de los indicadores de la página. Estos indicadores se pueden poner en cuatro lugares diferentes: arriba, abajo, a la derecha o a la izquierda.
void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
GtkPositionType pos );
GtkPositionType
debe tener uno de los valores siguientes (su significado
está bastante claro):
GTK_POS_TOP es el valor por defecto.
Lo siguiente que estudiaremos es como añadir páginas al libro de notas. Hay tres formas de añadirle páginas al widget. Veamos las dos primeras formas (son muy parecidas).
void gtk_notebook_append_page( GtkNotebook *notebook,
GtkWidget *child,
GtkWidget *tab_label );
void gtk_notebook_prepend_page( GtkNotebook *notebook,
GtkWidget *child,
GtkWidget *tab_label );
Estas funciones le añaden páginas al libro de notas insertándolas desde
el fondo del libro (añadiéndolas), o desde parte superior del libro
(preañadiéndolas). child
es el widget que se mete en la página
del libro de notas, y tab_label
es la etiqueta para la página que
estamos añadiendo.
La función que queda que sirve para añadir una página contiene todas las propiedades de las anteriores, pero además permite especificar en que posición quiere que esté la página dentro del libro de notas.
void gtk_notebook_insert_page( GtkNotebook *notebook,
GtkWidget *child,
GtkWidget *tab_label,
gint position );
Los parámetros son los mismos que habían en las funciones _append_ y
_prepend_ excepto que hay uno más que antes, position
. Este
parámetro se utiliza para especificar en que lugar debe introducirse
la página.
Ahora que sabemos como añadir un página, veamos como podemos eliminar una página del libro de notas.
void gtk_notebook_remove_page( GtkNotebook *notebook,
gint page_num );
Esta función coge la página especificada por page_num
y la
elimina del widget al que apunta notebook
.
Para saber cual es la página actual del libro de notas utilice la función:
gint gtk_notebook_current_page( GtkNotebook *notebook );
Las dos funciones siguientes sirven para ir a la página siguiente o a
la anterior del libro de notas. Para utilizarlas sólo hay que
proporcionar el widget notebook que queremos manipular. Nota:
cuando el libro de notas está en la última página y se llama a
gtk_notebook_next_page
, se pasará a la primera página. Sin
embargo, si el libro de notas está en la primera página, y se llama a
gtk_notebook_prev_page
, no se pasará a la última página.
void gtk_notebook_next_page( GtkNoteBook *notebook );
void gtk_notebook_prev_page( GtkNoteBook *notebook );
La siguiente función establece la página `activa'. Si quiere que se abra el libro de notas por la página 5, por ejemplo, debe utilizar esta función. Si no utiliza esta función el libro de notas empezará por defecto en la primera página.
void gtk_notebook_set_page( GtkNotebook *notebook,
gint page_num );
Las dos funciones siguientes añaden o eliminan los indicadores de las páginas o el borde del libro, respectivamente.
void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
gint show_tabs);
void gtk_notebook_set_show_border( GtkNotebook *notebook,
gint show_border );
show_tabs
y show_border
puede ser TRUE o FALSE.
Ahora echémosle un vistaza a un ejemplo, sacado del código de
testgtk.c
que viene con la distribución de GTK, y que muestra
la utilización de las 13 funciones. Este pequeño programa crea una
ventana con un libro de notas y seis botones. El libro de notas
contiene 11 páginas, incluidas de tres formas diferentes, añadidas,
insertadas, y preañadidas. Los botones le permiten rotar las
posiciones de los indicadores, añadir y eliminar los indicadores y el
borde, eliminar una página, cambiar páginas hacia delante y hacia
detrás, y salir del programa.
/* principio del ejemplo notebook notebook.c */
#include <gtk/gtk.h>
/* Esta función rota la posición de los indicadores */
void rotate_book (GtkButton *button, GtkNotebook *notebook)
{
gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
}
/* Añade/Elimina los indicadores de la página y los bordes */
void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
{
gint tval = FALSE;
gint bval = FALSE;
if (notebook->show_tabs == 0)
tval = TRUE;
if (notebook->show_border == 0)
bval = TRUE;
gtk_notebook_set_show_tabs (notebook, tval);
gtk_notebook_set_show_border (notebook, bval);
}
/* Elimina una página del libro de notas */
void remove_book (GtkButton *button, GtkNotebook *notebook)
{
gint page;
page = gtk_notebook_current_page(notebook);
gtk_notebook_remove_page (notebook, page);
/* Hay que redibujar el widget --
Esto fuerza que el widget se autoredibuje */
gtk_widget_draw(GTK_WIDGET(notebook), NULL);
}
void delete (GtkWidget *widget, GtkWidget *event, gpointer data)
{
gtk_main_quit ();
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *table;
GtkWidget *notebook;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *checkbutton;
int i;
char bufferf[32];
char bufferl[32];
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (delete), NULL);
gtk_container_border_width (GTK_CONTAINER (window), 10);
table = gtk_table_new(2,6,TRUE);
gtk_container_add (GTK_CONTAINER (window), table);
/* Crea un nuevo libro de notas, indicando la posición de los
indicadores */
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
gtk_widget_show(notebook);
/* le añadimos un montón de páginas al libro de notas */
for (i=0; i < 5; i++) {
sprintf(bufferf, "Append Frame %d", i+1);
sprintf(bufferl, "Page %d", i+1);
frame = gtk_frame_new (bufferf);
gtk_container_border_width (GTK_CONTAINER (frame), 10);
gtk_widget_set_usize (frame, 100, 75);
gtk_widget_show (frame);
label = gtk_label_new (bufferf);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (label);
label = gtk_label_new (bufferl);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
}
/* Ahora añadimos una página en punto específico */
checkbutton = gtk_check_button_new_with_label ("Check me please!");
gtk_widget_set_usize(checkbutton, 100, 75);
gtk_widget_show (checkbutton);
label = gtk_label_new ("Add spot");
gtk_container_add (GTK_CONTAINER (checkbutton), label);
gtk_widget_show (label);
label = gtk_label_new ("Add page");
gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
/* Y finalmente preañadimos páginas en el libro de notas */
for (i=0; i < 5; i++) {
sprintf(bufferf, "Prepend Frame %d", i+1);
sprintf(bufferl, "PPage %d", i+1);
frame = gtk_frame_new (bufferf);
gtk_container_border_width (GTK_CONTAINER (frame), 10);
gtk_widget_set_usize (frame, 100, 75);
gtk_widget_show (frame);
label = gtk_label_new (bufferf);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (label);
label = gtk_label_new (bufferl);
gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
}
/* Decimos en que página empezar (página 4) */
gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
/* creamos un montón de botones */
button = gtk_button_new_with_label ("close");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (delete), NULL);
gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("next page");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_notebook_next_page,
GTK_OBJECT (notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("prev page");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_notebook_prev_page,
GTK_OBJECT (notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("tab position");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("tabs/border on/off");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) tabsborder_book,
GTK_OBJECT (notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("remove page");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) remove_book,
GTK_OBJECT(notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
gtk_widget_show(button);
gtk_widget_show(table);
gtk_widget_show(window);
gtk_main ();
return 0;
}
/* fin del ejemplo */
Espero que la explicación le ayude de alguna manera a crear libros de notas en sus aplicaciones GTK.
Las ventanas con barras de desplazamiento se utilizan para crear una zona con barras de desplazamiento dentro de una ventana real. Puede insertar cualquier tipo de widget en una ventana con barras de desplazamiento, y podrá utilizarlo sin importar su tamaño gracias a las barras de desplazamiento.
La función siguiente se utiliza para crear una nueva ventana con barras de desplazamiento.
GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
GtkAdjustment *vadjustment );
Donde el primer argumento es el ajuste para la dirección horizontal, y el segundo es el ajuste para la dirección vertical. Casi siempre valen NULL.
void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
GtkPolicyType hscrollbar_policy,
GtkPolicyType vscrollbar_policy );
Esta función establece la política que se utilizará con respecto a las barras de desplazamiento. El primer argumento es la ventana con barras de desplazamiento sobre la que queremos actuar. El segundo establece la política para la barra de desplazamiento horizontal, y el tercero la política para la barra de desplazamiento vertical.
La política puede ser GTK_POLICY_AUTOMATIC, o GTK_POLICY_ALWAYS. GTK_POLICY_AUTOMATIC decidirá automáticamente si necesita barras de desplazamiento, mientras que GTK_POLICY_ALWAYS pondrá siempre las barras de desplazamiento.
Aquí tenemos un ejemplo sencillo que empaqueta 100 botones de selección en una ventana con barras de desplazamiento. Solamente he comentado las partes que debería ser nuevas para usted.
/* principio del ejemplo scrolledwin scrolledwin.c */
#include <gtk/gtk.h>
void destroy(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
int main (int argc, char *argv[])
{
static GtkWidget *window;
GtkWidget *scrolled_window;
GtkWidget *table;
GtkWidget *button;
char buffer[32];
int i, j;
gtk_init (&argc, &argv);
/* Crea un nuevo cuadro de diálogo para que la ventana con barras de
* desplazamiento se meta dentro. Un cuadro de diálogo es como una
* ventana normal excepto que tiene dentro una vbox y un separador
* horizontal. Es sólo un atajo para crear cuadros de diálogo */
window = gtk_dialog_new ();
gtk_signal_connect (GTK_OBJECT (window), "destroy",
(GtkSignalFunc) destroy, NULL);
gtk_window_set_title (GTK_WINDOW (window), "dialog");
gtk_container_border_width (GTK_CONTAINER (window), 0);
gtk_widget_set_usize(window, 300, 300);
/* crea una nueva ventana con barras de desplazamiento. */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
/* la política es GTK_POLICY_AUTOMATIC, o GTK_POLICY_ALWAYS.
* GTK_POLICY_AUTOMATIC decidirá automáticamente si necesita
* barras de desplazamiento, mientras que GTK_POLICY_ALWAYS pondrá
* siempre las barras de desplazamiento. El primer argumento se
* refiere a la barra horizontal, el segundo a la vertical. */
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
/* El cuadro de diálogo se crea con una vbox dentro de él. */
gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
TRUE, TRUE, 0);
gtk_widget_show (scrolled_window);
/* crea una tabla de 10 por 10 casillas. */
table = gtk_table_new (10, 10, FALSE);
/* pone el espacio en x y en y a 10 */
gtk_table_set_row_spacings (GTK_TABLE (table), 10);
gtk_table_set_col_spacings (GTK_TABLE (table), 10);
/* empaqueta la tabla en la ventana con barras de desplazamiento */
gtk_container_add (GTK_CONTAINER (scrolled_window), table);
gtk_widget_show (table);
/* crea una rejilla de botones de selección en la tabla para
* demostrar la ventana con barras de desplazamiento. */
for (i = 0; i < 10; i++)
for (j = 0; j < 10; j++) {
sprintf (buffer, "button (%d,%d)\n", i, j);
button = gtk_toggle_button_new_with_label (buffer);
gtk_table_attach_defaults (GTK_TABLE (table), button,
i, i+1, j, j+1);
gtk_widget_show (button);
}
/* Añade un botón "close" en la parte de abajo del cuadro de
* diálogo */
button = gtk_button_new_with_label ("close");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_widget_destroy,
GTK_OBJECT (window));
/* hace que el botón puede ser elegido por defecto. */
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
/* Hace que el botón sea el elegido por defecto. Con pulsar la
* tecla "Enter" se activará este botón. */
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show (window);
gtk_main();
return(0);
}
/* fin del ejemplo */
Juegue un poco redimensionando la ventana. Vea como actuan las barras
de desplazamiento. También puede utilizar la función
gtk_widget_set_usize()
para poner el tamaño por defecto de la
ventana o de cualquier otro widget.
El widget ventana dividida es útil para cuando se quiere dividir una zona en dos partes, con un tamaño relativo controlado por el usuario. Entre las dos porciones de la ventana se dibuja un separador con un botoncito que el usuario puede arrastrar para cambiar el tamaño de cada zona. La división puede ser horizontal (HPaned) o vertical (VPaned).
Para crear una nueva ventana dividida, utilice una de las siguientes funciones:
GtkWidget *gtk_hpaned_new (void);
GtkWidget *gtk_vpaned_new (void);
Después de crear el widget ventana dividida, tiene que añadirle un widget hijo a cada mitad. Para hacerlo, utilice:
void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
gtk_paned_add1()
añade el widget hijo a la mitad que se
encuentra en la parte izquierda o superior de la ventana
dividida. gtk_paned_add2()
añade el widget a la mitad que
hay en la parte derecha o inferior de la ventana.
Por ejemplo, si queremos crear una parte del interface de usuario de
un programa de correo-e imaginario. Dividiremos verticalmente una
ventana en dos partes, teniendo en la parte superior una lista de los
mensajes de correo-e y en la parte inferior el texto de uno de estos
mensajes. El programa es bastante fácil de entender. Solo un par de
cosillas: no se puede añadir texto en un widget de texto (Text)
si no se ha hecho antes gtk_widget_realize()
, pero como
demostración de una técnica alternativa, para añadir el texto
conectaremos un manipulador a la señal ``realize''. Y tenemos que
añadir la opción GTK_SHRINK
a algunos de los elementos que hay en
la tabla con la ventana de texto y sus barras de desplazamiento, así
cuando la porción de abajo se haga más pequeña, se encogerá
correctamente en lugar de desaparecer por la parte de abajo de la
ventana.
/* principio del ejemplo paned paned.c */
#include <gtk/gtk.h>
/* Crear la lista de "messages" */
GtkWidget *
create_list (void)
{
GtkWidget *scrolled_window;
GtkWidget *list;
GtkWidget *list_item;
int i;
char buffer[16];
/* Crear una nueva ventana con barras de desplazamiento si hacen
falta */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
/* Crear una nueva lista y poner en ella la ventana con barras */
list = gtk_list_new ();
gtk_container_add (GTK_CONTAINER(scrolled_window), list);
gtk_widget_show (list);
/* Añadir algunos mensajes a la ventana */
for (i=0; i<10; i++) {
sprintf(buffer,"Message #%d",i);
list_item = gtk_list_item_new_with_label (buffer);
gtk_container_add (GTK_CONTAINER(list), list_item);
gtk_widget_show (list_item);
}
return scrolled_window;
}
/* Añadir algún texto a nuestro widget de texto - esta función se
invoca cada vez que se produce una señal realize en la
ventana. Podemos forzar esta señal mediante gtk_widget_realize, pero
primero tiene que formar parte de una jerarquía */
void
realize_text (GtkWidget *text, gpointer data)
{
gtk_text_freeze (GTK_TEXT (text));
gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
"From: pathfinder@nasa.gov\n"
"To: mom@nasa.gov\n"
"Subject: Made it!\n"
"\n"
"We just got in this morning. The weather has been\n"
"great - clear but cold, and there are lots of fun sights.\n"
"Sojourner says hi. See you soon.\n"
" -Path\n", -1);
gtk_text_thaw (GTK_TEXT (text));
}
/* Creamos una zona con texto que muestra un "message" */
GtkWidget *
create_text (void)
{
GtkWidget *table;
GtkWidget *text;
GtkWidget *hscrollbar;
GtkWidget *vscrollbar;
/* Crea una tabla para contener el widget de texto y las barras de
desplazamiento */
table = gtk_table_new (2, 2, FALSE);
/* Pone un widget de texto en la esquina superior izquierda.
Observe la utilización de GTK_SHRINK en la dirección y */
text = gtk_text_new (NULL, NULL);
gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
GTK_FILL | GTK_EXPAND,
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
gtk_widget_show (text);
/* Pone una HScrollbar en la esquina inferior izquierda */
hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (hscrollbar);
/* Y una VScrollbar en la esquina superior derecha */
vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
gtk_widget_show (vscrollbar);
/* Y un manejador para poner un mensaje en el widget de texto
cuando reciba realize */
gtk_signal_connect (GTK_OBJECT (text), "realize",
GTK_SIGNAL_FUNC (realize_text), NULL);
return table;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vpaned;
GtkWidget *list;
GtkWidget *text;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
gtk_container_border_width (GTK_CONTAINER (window), 10);
/* crea un widget vpaned y lo añade a nuestra ventana superior */
vpaned = gtk_vpaned_new ();
gtk_container_add (GTK_CONTAINER(window), vpaned);
gtk_widget_show (vpaned);
/* Ahora crea los contenidos de las dos mitades de la ventana */
list = create_list ();
gtk_paned_add1 (GTK_PANED(vpaned), list);
gtk_widget_show (list);
text = create_text ();
gtk_paned_add2 (GTK_PANED(vpaned), text);
gtk_widget_show (text);
gtk_widget_show (window);
gtk_main ();
return 0;
}
/* fin del ejemplo */
Las barras de herramientas acostumbran a agrupar un conjunto de widgets para hacer más sencilla la personalización de su aspecto y composición. Típicamente una barra de herramientas consiste en botones con iconos, etiquetas y tips para los iconos (pequeño texto descriptivo que aparece cuando se mantiene el ratón sobre el icono), pero en realidad en una barra se puede poner cualquier tipo de widget. Finalmente, los elementos se pueden disponer de forma horizontal o vertical, y los botones pueden mostrar iconos, etiquetas o ambos.
La creación de una barra de herramientas se hace (como puede que ya haya sospechado) mediante la función siguiente:
GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
GtkToolbarStyle style );
donde orientation
puede ser:
GTK_ORIENTATION_HORIZONTAL
GTK_ORIENTATION_VERTICAL
y style
:
GTK_TOOLBAR_TEXT
GTK_TOOLBAR_ICONS
GTK_TOOLBAR_BOTH
La variable style
se aplica a todos los botones que se crean con las
funciones `item' (pero no a los botones insertados en la barra de
herramientas como widgets separados).
Después de crear una barra de herramientas, se pueden añadir, preañadir e insertar elementos (o sea, botones) en la misma. Los campos que describen un elemento son el texto de la etiqueta, el texto del tip, un texto para el tip privado, un icono para el botón y una función de llamada para el mismo. Por ejemplo, para añadir un elemento puede utilizar la siguiente función:
GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
const char *text,
const char *tooltip_text,
const char *tooltip_private_text,
GtkWidget *icon,
GtkSignalFunc callback,
gpointer user_data );
Si quiere utilizar gtk_toolbar_insert_item
, el único parámetro
adicional que debería especificar es la posición en la que quiere que
se introduzca el elemento.
Para añadir un espacio en blanco entre los elementos de la barra de herramientas, puede utilizar la función siguiente:
void gtk_toolbar_append_space( GtkToolbar *toolbar );
void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
void gtk_toolbar_insert_space( GtkToolbar *toolbar,
gint position );
Y el tamaño del espacio en blanco puede establecerse globalmente para toda una barra de herramientas con la función:
void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
gint space_size) ;
Si tiene que establecer la orientación de una barra de herramientas y su estilo, puede hacerlo `al vuelo' con las funciones siguientes:
void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
GtkOrientation orientation );
void gtk_toolbar_set_style( GtkToolbar *toolbar,
GtkToolbarStyle style );
void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
gint enable );
Para mostrar algunas otras cosas que pueden hacerse con una barra de herramientas, vamos a ver el siguiente programa (interrumpiremos el listado con alguna explicación adicional):
#include <gtk/gtk.h>
#include "gtk.xpm"
/* Esta función está conectada al botón Close o a la acción de cerrar
* la ventana desde el WM */
void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_main_quit ();
}
Este principio ya debería de sonarle familiar, a no ser que éste sea su primer programa GTK. En nuestro programa no habrá ninguna novedad, salvo un bonito dibujo XPM que utilizaremos como icono para todos los botones.
GtkWidget* close_button; // este botón emitirá la señal de cerrar el programa
GtkWidget* tooltips_button; // para activar/desactivar los tooltips
GtkWidget* text_button,
* icon_button,
* both_button; // botones circulares para el estilo de la barra
GtkWidget* entry; // un widget para meter texto para mostrar como
// empaquetar widgets en la barra de herramientas
En realidad no necesitamos todos los widgets que acabo de poner, pero para aclarar las cosas un poco más los he puesto todos.
/* Esto es fácil... cuando uno de los botones cambia, sólo
* tenemos que comprobar quien está activo y hacer que el estilo
* de la barra de herramientas esté acorde con la elección
* ATENCIÓN: ˇnuestra barra de herramientas es data !
void radio_event (GtkWidget *widget, gpointer data)
{
if (GTK_TOGGLE_BUTTON (text_button)->active)
gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
else if (GTK_TOGGLE_BUTTON (icon_button)->active)
gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
else if (GTK_TOGGLE_BUTTON (both_button)->active)
gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
}
/* todavía más fácil, sólo hay que comprobar el botón de selección
* y activar/desactivar los tooltips */
void toggle_event (GtkWidget *widget, gpointer data)
{
gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
GTK_TOGGLE_BUTTON (widget)->active );
}
Lo de arriba son sólo dos funciones de llamada que se invocarán cuando se presione uno de los botones de la barra de herramientas. Todo esto ya debería resultarle familiar si ha utilizado alguna vez los botones de selección (o los botones circulares)
int main (int argc, char *argv[])
{
/* Aquí está nuestra ventana principal (un cuadro de diálogo) y una
* caja flotante */
GtkWidget* dialog;
GtkWidget* handlebox;
/* De acuerdo, necesitamos una barra de herramientas, un icono con
* una máscara (una para todos los botones) y un widget icono donde
* meter el icono (crearemos un widget diferente para cada botón) */
GtkWidget * toolbar;
GdkPixmap * icon;
GdkBitmap * mask;
GtkWidget * iconw;
/* a esta función se le llama en todas las aplicación GTK */
gtk_init (&argc, &argv);
/* crear una ventana nueva con un título y el tamaño adecuado */
dialog = gtk_dialog_new ();
gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
/* salimos si alguien intenta cerrarnos */
gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
GTK_SIGNAL_FUNC ( delete_event ), NULL);
/* tenemos que mandar la señalo realize porque utilizamos pixmaps
* para los elementos que hay en la barra de herramientas */
gtk_widget_realize ( dialog );
/* para hacerlo más bonito ponemos la barra de herramientas en la
* caja flotante, para que así se pueda desatar de la ventana
* principal */
handlebox = gtk_handle_box_new ();
gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
handlebox, FALSE, FALSE, 5 );
Lo de arriba debería ser parecido en cualquier aplicación GTK. Sólo está la inicialización de GTK, la creación de la ventana, etc... Solamente hay una cosa que probablemente necesite una explicación: una barra de herramientas flotante. Una barra de herramientas flotante sólo es otra barra donde pueden empaquetarse widgets. La diferencia que tiene con una barra típica es que puede desatarse de la ventana padre (o, de hecho, la barra de herramientas flotante permanece en el padre, pero reducida a un rectángulo muy pequeño, mientras que todos sus contenidos se pasan a una nueva ventana flotante). Es bonito tener una barra de herramientas flotante, por lo que estos dos widgets suelen aparecer juntos.
/* la barra de herramientas será horizontal, con iconos y texto, y
* con un espacio de 5pxl entre elementos y finalmente, la ponemos en
* nuestra caja flotante */
toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
GTK_TOOLBAR_BOTH );
gtk_container_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
/* ahora creamos el icono con la máscara: utilizaremos el widget
* icon con todos los elementos de la barra de herramientas */
icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
&dialog->style->white, gtk_xpm );
Bien, lo que acabamos de escribir es la inicialización del widget de la barra de herramientas y la creación de un pixmap GDK con su máscara. Si quiere saber algo más sobre la utilización de pixmaps, vea la documentación de GDK o la sección Pixmaps en este tutorial.
/* nuestro primer elemento es el botón <close> */
iconw = gtk_pixmap_new ( icon, mask ); // icon widget
close_button =
gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), // nuestra barra
"Close", // etiqueta del botón
"Closes this app", // tooltip para el botón
"Private", // cadena privada del tooltip
iconw, // widget del icono
GTK_SIGNAL_FUNC (delete_event), // una señal
NULL );
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); // espacio después del elemento
En el trozo de código de arriba puede ver como se hace la acción más
simple: añadir un botón a la barra de herramientas. Justo antes de
añadir un nuevo elemento, tenemos que construir un widget
pixmap para que sirva como icono para este elemento; este paso
tendrá que repetirse para cada nuevo elemento. Después del elemento
añadiremos un espacio en blanco en la barra de herramientas, para que
los elementos que añadamos a continuación no se toquen los unos a los
otros. Como puede ver, gtk_toolbar_append_item
devuelve un
puntero al widget de nuestro nuevo botón recien creado, por
lo que podremos trabajar con él como siempre.
/* ahora, vamos a hacer nuestro grupo de botones circulares... */
iconw = gtk_pixmap_new ( icon, mask );
icon_button =
gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
GTK_TOOLBAR_CHILD_RADIOBUTTON, // un tipo de elemento
NULL, // puntero al widget
"Icon", // etiqueta
"Only icons in toolbar", // tooltip
"Private", // cadena privada del tooltip
iconw, // icono
GTK_SIGNAL_FUNC (radio_event), // señal
toolbar); // dato para la señal
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
Aquí empezamos creando un grupo de botones circulares. Para hacerlo
hemos utilizado gtk_toolbar_append_element
. De hecho, utilizando
esta función se pueden añadir tanto elementos simples como espacios en
blanco (tipo = GTK_TOOLBAR_CHILD_SPACE o GTK_TOOLBAR_CHILD_BUTTON). En
el caso de arriba, hemos empezado creando un grupo de botones circulares.
Para crear más botones circulares para este grupo
necesitaremos un puntero al botón anterior del grupo, mediante el que
podremos construir fácilmente una lista de botones (ver la sección
Botones circulares que se encuentra
más adelante en este tutorial).
/* following radio buttons refer to previous ones */
iconw = gtk_pixmap_new ( icon, mask );
text_button =
gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
GTK_TOOLBAR_CHILD_RADIOBUTTON,
icon_button,
"Text",
"Only texts in toolbar",
"Private",
iconw,
GTK_SIGNAL_FUNC (radio_event),
toolbar);
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
iconw = gtk_pixmap_new ( icon, mask );
both_button =
gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
GTK_TOOLBAR_CHILD_RADIOBUTTON,
text_button,
"Both",
"Icons and text in toolbar",
"Private",
iconw,
GTK_SIGNAL_FUNC (radio_event),
toolbar);
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(both_button),TRUE);
Al final hemos activado manualmente uno de los botones (en caso contrario los botones permanecerían todos en estado activo, impidiéndonos poder cambiar de uno a otro).
/* aquí tenemos un sencillo botón de selección */
iconw = gtk_pixmap_new ( icon, mask );
tooltips_button =
gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
NULL,
"Tooltips",
"Toolbar with or without tips",
"Private",
iconw,
GTK_SIGNAL_FUNC (toggle_event),
toolbar);
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
Un botón de selección puede crearse de una forma obvia (si ya sabe como crear botones circulares).
/* para empaquetar un widget en la barra de herramientas, sólo
* tenemos que crearlo y añadirlo en la barra con el tooltip
* apropiado */
entry = gtk_entry_new ();
gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
entry,
"This is just an entry",
"Private" );
/* bien, no se ha creado con la barra, así que debemos mostrarlo
* explicitamente */
gtk_widget_show ( entry );
Como puede ver, añadir cualquier tipo de widget a la barra de herramientas es fácil. Lo único que debe recordar es que este widget debe mostrarse manualmente (al contrario que los demás elementos que se mostrarán junto con la barra de herramientas).
/* ˇ Eso es ! mostremos algo. */
gtk_widget_show ( toolbar );
gtk_widget_show (handlebox);
gtk_widget_show ( dialog );
/* quedémonos en gtk_main y ˇesperemos a que empiece la diversión! */
gtk_main ();
return 0;
}
Y ya estamos en el final del tutorial sobre la barra de herramientas. Por supuesto, para apreciar completamente el ejemplo, necesita además del código este precioso icono XPM que le mostramos a continuación:
/* XPM */
static char * gtk_xpm[] = {
"32 39 5 1",
". c none",
"+ c black",
"@ c #3070E0",
"# c #F05050",
"$ c #35E035",
"................+...............",
"..............+++++.............",
"............+++++@@++...........",
"..........+++++@@@@@@++.........",
"........++++@@@@@@@@@@++........",
"......++++@@++++++++@@@++.......",
".....+++@@@+++++++++++@@@++.....",
"...+++@@@@+++@@@@@@++++@@@@+....",
"..+++@@@@+++@@@@@@@@+++@@@@@++..",
".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
".+##++@@@@+++@@@+++++@@@@@@@@$@.",
".+###++@@@@+++@@@+++@@@@@++$$$@.",
".+####+++@@@+++++++@@@@@+@$$$$@.",
".+#####+++@@@@+++@@@@++@$$$$$$+.",
".+######++++@@@@@@@++@$$$$$$$$+.",
".+#######+##+@@@@+++$$$$$$@@$$+.",
".+###+++##+##+@@++@$$$$$$++$$$+.",
".+###++++##+##+@@$$$$$$$@+@$$@+.",
".+###++++++#+++@$$@+@$$@++$$$@+.",
".+####+++++++#++$$@+@$$++$$$$+..",
".++####++++++#++$$@+@$++@$$$$+..",
".+#####+++++##++$$++@+++$$$$$+..",
".++####+++##+#++$$+++++@$$$$$+..",
".++####+++####++$$++++++@$$$@+..",
".+#####++#####++$$+++@++++@$@+..",
".+#####++#####++$$++@$$@+++$@@..",
".++####++#####++$$++$$$$$+@$@++.",
".++####++#####++$$++$$$$$$$$+++.",
".+++####+#####++$$++$$$$$$$@+++.",
"..+++#########+@$$+@$$$$$$+++...",
"...+++########+@$$$$$$$$@+++....",
".....+++######+@$$$$$$$+++......",
"......+++#####+@$$$$$@++........",
".......+++####+@$$$$+++.........",
".........++###+$$$@++...........",
"..........++##+$@+++............",
"...........+++++++..............",
".............++++..............."};
El widget aspect frame (marco proporcional) es como el widget frame (marco), excepto que conserva las proporciones (esto es, la relación entre el ancho y el alto) del widget hijo, añadiendo espacio extra en caso de ser necesario. Esto es útil, por ejemplo, si quiere hacer una vista previa de una gran imagen. El tamaño de la vista previa debería variar cuando el usuario redimensione la ventana, pero la proporción tiene que coincidir con la de la imagen original.
Para crear un nuevo marco proporcional utilice:
GtkWidget *gtk_aspect_frame_new( const gchar *label,
gfloat xalign,
gfloat yalign,
gfloat ratio,
gint obey_child);
xalign
e yalign
indican la alineación exactamente igual que
con los widgets Alignment. Si obey_child
es TRUE, la
proporción de un widget hijo será la misma que la proporción del
tamaño ideal que éste pida. En caso contrario, vendrá dada por
ratio
.
Para cambiar las opciones de un marco proporcional ya existente, puede utilizar:
void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
gfloat xalign,
gfloat yalign,
gfloat ratio,
gint obey_child);
Como por ejemplo, el siguiente programa utiliza un marco proporcional para mostrar una zona de dibujo cuyas proporciones siempre será de 2:1, no importa como el usuario redimensione la ventana.
/* principio del ejemplo aspectframe aspectframe.c */
#include <gtk/gtk.h>
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *aspect_frame;
GtkWidget *drawing_area;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
gtk_container_border_width (GTK_CONTAINER (window), 10);
/* Crear un aspect_frame y añadirlo a nuestra ventana superior */
aspect_frame = gtk_aspect_frame_new ("2x1", /* etiqueta */
0.5, /* centro x */
0.5, /* centro y */
2, /* tamañox/tamañoy = 2 */
FALSE /* ignorar el aspecto del hijo */);
gtk_container_add (GTK_CONTAINER(window), aspect_frame);
gtk_widget_show (aspect_frame);
/* Añadir un widget hijo al marco proporcional */
drawing_area = gtk_drawing_area_new ();
/* Pediremos una ventana de 200x200, pero el marco proporcional
* sólo no dejará una ventana de 200x100, ya que tenemos una
* relación de 2x1 */
gtk_widget_set_usize (drawing_area, 200, 200);
gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
gtk_widget_show (drawing_area);
gtk_widget_show (window);
gtk_main ();
return 0;
}
/* fin del ejemplo */