Página siguiente Página anterior Índice general

15. El widget texto

El widget texto permite mostrar y editar multiples líneas de texto. Admite texto en varios colores y con varios tipos de letra, permitiendo mezclarlos de cualquier forma que desee. También hay un gran número de teclas para la edición de textos, que son compatibles con Emacs.

El widget texto admite copiar-y-pegar, incluyendo la utilización de doble y triple-click para seleccionar una palabra y una línea completa, respectivamente.

15.1 Creando y configurando un cuadro de texto

Sólo hay una función para crear un nuevo widget texto.

GtkWidget *gtk_text_new( GtkAdjustment *hadj,
                         GtkAdjustment *vadj );

Los argumentos nos permitirán dar al widget texto punteros a GtkAdjustement que pueden ser utilizados para controlar la visión de la posición del widget. Si le ponemos un valor NULL en cualquiera de los dos argumentos (o en los dos), la función gtk_text_new creará su propio ajuste.

void gtk_text_set_adjustments( GtkText       *text,
                               GtkAdjustment *hadj,
                               GtkAdjustment *vadj );

La función de arriba permite cambiar en cualquier momento el ajuste horizontal y vertical de un widget texto.

El widget texto no crea automáticamente sus propiar barras de desplazamiento cuando el texto a mostrar es demasiado largo para la ventana en la que se encuentra. Tenemos que crearlas y añadirlas a la capa del display nosotros mismos.

  vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
  gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
  gtk_widget_show (vscrollbar);

El trozo de código de arriba crea una nueva barra de desplazamiento vertical, y la conecta con el ajuste vertical del widget de texto, text. Entonces la empaqueta en un cuadro de la forma usual.

Observe que, actualmente el widget GtkText no admite barras de desplazamiento horizontal.

Principalmente hay dos maneras de utilizar un widget de texto: permitiendo al usuario editar el texto, o permitiéndonos mostrar varias líneas de texto al usuario. Para cambiar entre estos dos modos de operación, el widget de texto tiene las siguientes funciones:

void gtk_text_set_editable( GtkText *text,
                            gint     editable );

El argumento editable es un valor TRUE o FALSE que especifica si se permite al usuario editar los contenidos del widget texto. Cuando el widget texto se pueda editar, mostrará un cursor en la posición actual de inserción.

Sin embargo la utilización del widget en estos dos modos no es algo permanente, ya que puede cambiar el estado editable del widget texto e insertar texto en cualquier momento.

El widget texto corta las líneas de texto que son demasiado largas para que quepan en una sólo línea en la ventana. Su comportamiento por defecto es cortar las palabras donde se terminan las líneas. Esto puede cambiarse utilizando la siguiente función:

void gtk_text_set_word_wrap( GtkText *text,
                             gint     word_wrap );

Utilizando esta función podremos especificar que el widget texto debería cortar las líneas largas en los límites de las palabras. El argumento word_wrap es un valor TRUE o FALSE.

15.2 Manipulación de texto

El punto actual de inserción en un widget texto puede cambiarse utilizando

void gtk_text_set_point( GtkText *text,
                         guint    index );

donde index es la posición en la que poner el punto de inserción.

Análogamente tenemos la función para obtener la posición del punto de inserción:

guint gtk_text_get_point( GtkText *text );

Una función que es útil en combinación con las dos anteriores es

guint gtk_text_get_length( GtkText *text );

que devuelve la longitud actual del widget texto. La longitud es el número de caracteres que hay en el bloque de texto, incluyendo caracteres como el retorno de carro, que marca el final de las líneas.

Para insertar texto en la posición actual del cursor, tendrá que utilizar la función gtk_text_insert, que nos permitirá especificar los colores de fondo y de la letra y un tipo de letra para el texto.

void gtk_text_insert( GtkText    *text,
                      GdkFont    *font,
                      GdkColor   *fore,
                      GdkColor   *back,
                      const char *chars,
                      gint        length );

Pasar un valor NULL como el color de la letra (fore), el color de fondo (back) o el tipo de letra (font) hará que se utilicen los valores que indiquen el estilo del widget. Utilizar un valor de -1 para el parámetro length hará que se inserte todo el texto.

El widget texto es uno de los pocos de GTK que se redibuja a sí mismo dinámicamente, fuera de la función gtk_main. Esto significa que todos los cambios en el contenido del widget texto se manifestarán inmediatamente. Para permitirnos realizar varias actualizaciones del widget de texto sin que se redibuje continuamente, podemos congelar el widget, lo que hará que pare momentaneamente de redibujarse a sí mismo cada vez que haya algún cambio. Podemos descongelarlo cuando hayamos acabado con nuestras actualizaciones.

Las siguientes dos funciones realizarán la acción de congelar y descongelar el widget:

void gtk_text_freeze( GtkText *text );

void gtk_text_thaw( GtkText *text );         

Se puede borrar el texto que se encuentra en el punto actual de inserción del widget de texto mediante dos funciones. El valor devuelto es TRUE o FALSE en función del éxito de la operación.

gint gtk_text_backward_delete( GtkText *text,
                               guint    nchars );

gint gtk_text_forward_delete ( GtkText *text,
                               guint    nchars );

Si quiere recuperar el contenido del widget de texto, entonces la macro GTK_TEXT_INDEX(t, index) le permitirá obtener el carácter que se encuentra en la posición index del widget de texto t.

Para obtener mayores bloques de texto, podemos utilizar la función

gchar *gtk_editable_get_chars( GtkEditable *editable,
                               gint         start_pos,
                               gint         end_pos );   

Esta es una función de la clase padre del widget texto. Un valor de -1 en end_pos significa el final del texto. El índice del texto empieza en 0.

La función reserva un espacio de memoria para el bloque de texto, por lo que no debe olvidarse de liberarlo con una llamada a g_free cuando haya acabado el bloque.

15.3 Atajos por teclado

El widget texto tiene ciertos atajos de teclado preinstalados para las funciones de edición estándar, movimiento y selección. Pueden utilizarse mediante combinaciones de las teclas Control y Alt.

Además, si se mantiene apretada la tecla de Control y se utilizan las teclas de movimiento, el cursor se moverá por palabras en lugar de por caracteres. Manteniendo apretada la tecla Shift, las teclas de movimiento harán que se extienda la selección.

Atajos para el movimiento

Atajos para la edición

Atajos de selección

15.4 Un ejemplo de GtkText

/* principio del ejemplo text text.c */

/* text.c */

#include <stdio.h>
#include <gtk/gtk.h>

void text_toggle_editable (GtkWidget *checkbutton,
                           GtkWidget *text)
{
  gtk_text_set_editable(GTK_TEXT(text),
                        GTK_TOGGLE_BUTTON(checkbutton)->active);
}

void text_toggle_word_wrap (GtkWidget *checkbutton,
                            GtkWidget *text)
{
  gtk_text_set_word_wrap(GTK_TEXT(text),
                         GTK_TOGGLE_BUTTON(checkbutton)->active);
}

void close_application( GtkWidget *widget, gpointer data )
{
       gtk_main_quit();
}

int main (int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *box1;
  GtkWidget *box2;
  GtkWidget *hbox;
  GtkWidget *button;
  GtkWidget *check;
  GtkWidget *separator;
  GtkWidget *table;
  GtkWidget *vscrollbar;
  GtkWidget *text;
  GdkColormap *cmap;
  GdkColor colour;
  GdkFont *fixed_font;

  FILE *infile;

  gtk_init (&argc, &argv);
 
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_usize (window, 600, 500);
  gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);  
  gtk_signal_connect (GTK_OBJECT (window), "destroy",
                      GTK_SIGNAL_FUNC(close_application),
                      NULL);
  gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
  gtk_container_border_width (GTK_CONTAINER (window), 0);
  
  
  box1 = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), box1);
  gtk_widget_show (box1);
  
  
  box2 = gtk_vbox_new (FALSE, 10);
  gtk_container_border_width (GTK_CONTAINER (box2), 10);
  gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
  gtk_widget_show (box2);
  
  
  table = gtk_table_new (2, 2, FALSE);
  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
  gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
  gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
  gtk_widget_show (table);
  
  /* Crear el widget GtkText */
  text = gtk_text_new (NULL, NULL);
  gtk_text_set_editable (GTK_TEXT (text), TRUE);
  gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
                    GTK_EXPAND | GTK_SHRINK | GTK_FILL,
                    GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  gtk_widget_show (text);

  /* Añadir una barra de desplazamiento vertical al widget GtkText */
  vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
  gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
                    GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  gtk_widget_show (vscrollbar);

  /* Obtener el mapa de colores del sistema y conseguir el color rojo */
  cmap = gdk_colormap_get_system();
  colour.red = 0xffff;
  colour.green = 0;
  colour.blue = 0;
  if (!gdk_color_alloc(cmap, &colour)) {
    g_error("couldn't allocate colour");
  }

  /* Cargar un fuente de tamaño fijo */
  fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");

  /* Al enviar la señal relize a un widget se crea una ventana para el
   * mismo, y nos permite insertar texto */
  gtk_widget_realize (text);

  /* Congela el widget text, lo que nos permite hacer varias
   * actualizaciones */
  gtk_text_freeze (GTK_TEXT (text));
  
  /* Insertamos algún texto coloreado */
  gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
                   "Supports ", -1);
  gtk_text_insert (GTK_TEXT (text), NULL, &colour, NULL,
                   "colored ", -1);
  gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
                   "text and different ", -1);
  gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
                   "fonts\n\n", -1);
  
  /* Cargamos el fichero text.c en la ventana de texto */

  infile = fopen("text.c", "r");
  
  if (infile) {
    char buffer[1024];
    int nchars;
    
    while (1)
      {
        nchars = fread(buffer, 1, 1024, infile);
        gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
                         NULL, buffer, nchars);
        
        if (nchars < 1024)
          break;
      }
    
    fclose (infile);
  }

  /* Descongelamos el widget text, permitiéndonos ver todos los
   * cambios */
  gtk_text_thaw (GTK_TEXT (text));
  
  hbox = gtk_hbutton_box_new ();
  gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);

  check = gtk_check_button_new_with_label("Editable");
  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
  gtk_signal_connect (GTK_OBJECT(check), "toggled",
                      GTK_SIGNAL_FUNC(text_toggle_editable), text);
  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
  gtk_widget_show (check);
  check = gtk_check_button_new_with_label("Wrap Words");
  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
  gtk_signal_connect (GTK_OBJECT(check), "toggled",
                      GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE);
  gtk_widget_show (check);

  separator = gtk_hseparator_new ();
  gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
  gtk_widget_show (separator);

  box2 = gtk_vbox_new (FALSE, 10);
  gtk_container_border_width (GTK_CONTAINER (box2), 10);
  gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
  gtk_widget_show (box2);
  
  button = gtk_button_new_with_label ("close");
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
                      GTK_SIGNAL_FUNC(close_application),
                      NULL);
  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_widget_grab_default (button);
  gtk_widget_show (button);

  gtk_widget_show (window);

  gtk_main ();
  
  return 0;       
}
/* fin del ejemplo */


Página siguiente Página anterior Índice general