Página siguiente Página anterior Índice general

7. Ajustes

Existen diferentes widgets en GTK+ que pueden ser ajustados visualmente por el usuario mediante el ratón o el teclado. Un ejemplo son los widgets de selección descritos en la sección Widgets de selección de rango. También hay otros widgets que pueden ser ajustados parcialmente, por ejemplo el widget de texto o el viewport.

Como es lógico el programa tiene que poder reaccionar a los cambios que el usuario realiza. Mediante señales especiales se podría conseguir saber qué y cúanto ha sido ajustado, pero en el caso de que se quiera conectar la señal con diferentes widgets, de manera que todos cambien al mismo tiempo, el proceso puede ser un poco tedioso.

El ejemplo más obvio es conectar una barra de desplazamiento a una región con texto. Si cada widget posee su propia forma de establecer u obtener sus valores de ajuste el programador puede que tenga que escribir sus propios controladores de señales para traducir el resultado de la señal producida por un widget como el argumento de una función usada para determinar valores en otro widget.

Para resolver este problema GTK+ usa objetos del tipo GtkAdjustment. Con ellos se consigue almacenar y traspasar información de una forma abstracta y flexible. El uso más obvio es el de almacenes de párametros para widgets de escala (barras deslizantes y escalas). Como los GtkAdjustment derivan de GtkObject poseen cualidades intrínsecas que les permiten ser algo más que simples estructuras de datos. Lo más importante es que pueden emitir señales que a su vez pueden ser usadas tanto para reaccionar frente al cambio de datos introducidos por el usuario como para transferir los nuevos valores de forma transparente entre widgets ajustables.

7.1 Creando un ajuste

Los ajustes se pueden crear usando:

GtkObject *gtk_adjustment_new( gfloat value,
                               gfloat lower,
                               gfloat upper,
                               gfloat step_increment,
                               gfloat page_increment,
                               gfloat page_size );

El argumento value es el valor inicial que le queremos dar al ajuste. Normalmente se corresponde con las posiciones situadas más arriba y a la izquierda de un widget ajustable. El argumento lower especifica los valores más pequeños que el ajuste puede contener. A su vez con step_increment se especifica el valor más pequeño en el que se puede variar la magnitud en cuestión (valor de paso asociado), mientras que page_increment es el mayor. Con page_size se determina el valor visible de un widget.

7.2 Forma sencilla de usar los ajustes

Los widgets ajustábles se pueden dividir en dos categorias diferentes, aquellos que necesitan saber las unidades de la cantidad almacenada y los que no. Este último grupo incluye los widgets de tamaño (barras deslizantes, escalas, barras de estado, o botones giratorios). Normalmente estos widgets son ajustados ``directamente'' por el usuario. Los argumentos lower y upper serán los limites dentro de los cuales el usuario puede manipular los ajustes. Por defecto sólo se modificará el value (valor) de un ajuste.

El otro grupo incluye los widgets de texto, la lista compuesta o la ventana con barra deslizante. Estos widgets usan valores en pixels para sus ajustes, y normalmente son ajustados ``indirectamente'' mediante barras deslizantes. Aunque todos los widgets pueden crear sus propios ajustes o usar otros creados por el programador con el segundo grupo suele ser conveniente dejarles que creen sus propios ajustes. Normalmente no tendrán en cuenta ninguno de los valores de un ajuste proporcionado por el programador, excepto value, pero los resultados son, en general, indefinidos (entiendase que tendrá que leer el código fuente para saber que pasa con cada widget).

Probablemente ya se habrá dado cuenta de que como los widgets de texto (y todos los widgets del segundo grupo), insisten en establecer todos los valores excepto value, mientras que las barras deslizantes sólo modifican value, si se comparte un objeto de ajuste entre una barra deslizante y un widget de texto al manipular la barra se modificará el widget de texto. Ahora queda completamente demostrada la utilidad de los ajustes. Veamos un ejemplo:

  /* creamos un ajuste */
  text = gtk_text_new (NULL, NULL);
  /* lo usamos con la barra deslizante */
  vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);

7.3 Descripción detallada de los ajustes

Puede que se esté preguntando cómo es posible crear sus propios controladores para responder a las modificaciones producidas por el usuario y cómo obtener el valor del ajuste hecho por este. Para aclarar esto y otras cosas vamos a estudiar la estructura del ajuste

struct _GtkAdjustment
{
  GtkData data;
  
  gfloat lower;
  gfloat upper;
  gfloat value;
  gfloat step_increment;
  gfloat page_increment;
  gfloat page_size;
};     

Lo primero que hay que aclarar es que no hay ninguna macro o función de acceso que permita obtener el value de un GtkAdjustment, por lo que tendrá que hacerlo usted mismo. Tampoco se preocupe mucho porque la macro GTK_ADJUSTMENT (Object) comprueba los tipos durante el proceso de ejecución (como hacen todas las macros de GTK+ que sirven para comprobar los tipos).

Cuando se establece el value de un ajuste normalmente se quiere que cualquier widget se entere del cambio producido. Para ello GTK+ posee una función especial:

void gtk_adjustment_set_value( GtkAdjustment *adjustment,
                               gfloat         value );

Tal y como se mencionó antes GtkAdjustment es una subclase de GtkObject y por tanto puede emitir señales. Así se consigue que se actualicen los valores de los ajustes cuando se comparten entre varios widgets. Por tanto todos los widgets ajustables deben conectar controladores de señales a sus señales del tipo value_changed. Esta es la definición de la señal como viene en struct _GtkAdjustmentClass

  void (* value_changed) (GtkAdjustment *adjustment);

Todos los widgets que usan GtkAdjustment deben emitir esta señal cuando cambie el valor de algún ajuste. Esto sucede cuando el usuario cambia algo o el programa modifica los ajustes mediante. Por ejemplo si queremos que rote una figura cuando modificamos un widget de escala habría que usar una respuesta como esta:

void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
{
  set_picture_rotation (picture, adj->value);
...

y conectarla con el ajuste del widget de escala mediante:

gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
                    GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
¿Qué pasa cuando un widget reconfigura los valores upper o lower (por ejemplo cuando se añade más texto)? Simplemente que se emite la señal changed, que debe ser parecida a:

  void (* changed)       (GtkAdjustment *adjustment);

Los widgets de tamaño normalmente conectan un controlador a esta señal, que cambia el aspecto de éste para reflejar el cambio. Por ejemplo el tamaño de la guía en una barra deslizante que se alarga o encoge según la inversa de la diferencia de los valores lower y upper.

Probablemente nunca tenga que conectar un controlador a esta señal a no ser que esté escribiendo un nuevo tipo de widget. Pero si cambia directamente alguno de los valores de GtkAdjustment debe hacer que se emita la siguiente señal para reconfigurar todos aquellos widgets que usen ese ajuste:

gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");


Página siguiente Página anterior Índice general