Taryn Fox
jewelfox@fursona.net 2012
Aprenda cómo distribuir componentes de la IU, como imágenes y etiquetas.

# 2. Bienvenido a la rejilla

        Este tutorial le mostrará cómo crear widgets básicos, o partes de la interfaz de usuario de GNOME, como imágenes y etiquetas. Después aprenderá cómo ordenarlas en una rejilla, que le permite poner widgets exactamente donde los quiere.
        ¿Ya ha hecho el primer tutorial en esta serie? Querrá hacerlo antes de continuar.

# Pasar a nativo

En el último tutorial, se creó básicamente una ventana de GNOME como marco para una aplicación web. Todo el código específico de GNOME que necesitó aprender trataba del poner la «WebView» (el widget que contenía la aplicación) en una «ApplicationWindow», y decirle que la muestre. La aplicación en sí estaba escrita en HTML y JavaScript, al igual que la mayoría de las páginas en la web.

Esta vez, solo se van a usar widgets nativos de GNOME. Un widget sólo es una cosa, como una casilla de verificación o una imagen, y GNOME tiene una amplia variedad para elegir. Se llaman widgets «nativos» para distinguirlos de cosas como el botón y la cabecera en la aplicación web que escribió. Porque en lugar de usar código web, estos van a ser 100% GNOME, usando Gtk+.

Gtk+ stands for "GIMP Toolkit." It's like a toolbox of widgets that you can reach into, while building your applications. It was originally written for the GIMP, which is a free software image editor.

# Creando la aplicación

Antes de sacar ningún widget de la caja de herramientas de GTK+, se necesita escribir el código plantilla que la aplicación requiere.

#!/usr/bin/gjs

const Gtk = imports.gi.Gtk; const Lang = imports.lang;

Esta parte siempre va al inicio del código. Dependiendo de qué va a hacer con él, puede querer declarar más importaciones aquí. Este ejemplo es bastante básico, por lo que esto es todo lo que necesita; «Gtk» para los widgets, y «Lang» para poder usar «Lang.bind» para conectar las señales de activación e inicio de la aplicación a las funciones requeridas.

Hablando de eso:

const WelcomeToTheGrid = new Lang.Class({ Name: 'Welcome to the Grid',

// Create the application itself _init: function() { this.application = new Gtk.Application();

// Connect 'activate' and 'startup' signals to the callback functions this.application.connect('activate', Lang.bind(this, this._onActivate)); this.application.connect('startup', Lang.bind(this, this._onStartup)); },

// Callback function for 'activate' signal presents windows when active _onActivate: function() { this._window.present(); },

// Callback function for 'startup' signal builds the UI _onStartup: function() { this._buildUI (); },

Este es el inicio de la aplicación en sí, y la función «_init» que la crea. Le dice a «_buildUI» que cree una «ApplicationWindow», a la que se llamará «_window», y le dice a la ventana que se presente cuando se la necesite.

Esta parte, nuevamente, es principalmente copiar y pegar, pero siempre querrá darle a su aplicación un nombre único.

// Build the application's UI _buildUI: function() {

// Create the application window this._window = new Gtk.ApplicationWindow({ application: this.application, window_position: Gtk.WindowPosition.CENTER, border_width: 10, title: "Welcome to the Grid"});

Finalmente, se arranca la función «_buildUI» creando una «ApplicationWindow» nueva. Se especifica que va con esta aplicación, que debe aparecer en el centro de la pantalla, y que debe haber al menos 10 píxeles entre el borde exterior y cualquier widget dentro de ella. También se le da un título, que aparecerá en la parte superior de la ventana.

# Usar la caja de herramientas de GTK+

¿Qué widgets deben usarse? Bueno, si quiere escribir una aplicación que se vea así:

Necesitará, al menos, una imagen y una etiqueta de texto para acompañarla. Comience con la imagen:

// Create an image this._image = new Gtk.Image ({ file: "gnome-image.png" });

Puede descargar el archivo de imagen usado en este ejemplo aquí. Asegúrese de ponerlo en la misma carpeta que el código que está escribiendo.

// Create a label this._label = new Gtk.Label ({ label: "Welcome to GNOME, too!" });

Ese código añade la etiqueta debajo. Puede ver cómo se crean los widgets aquí; cada uno es una parte de GTK+, y se le pueden dar propiedades que personalizan cómo se comportan. En este caso, se establece la propiedad «file» de la imagen al nombre de archivo de la imagen que se desea, y la propiedad «label» de la etiqueta a la oración que se quiere bajo la imagen.

Sí, suena redundante que un objeto «Label» tenga una propiedad «label», pero no lo es. Otros widgets que contienen texto también tienen una propiedad «label», por lo que es consistente que un widget «Label» también tenga una.

Sin embargo, no se pueden simplemente añadir estos widgets a la ventana en orden, como los elementos HTML aparecen en el orden en el que los escribe. Eso es porque una «ApplicationWindow» sólo puede contener un widget.

¿Cómo se resuelve eso? Haciendo que ese widget sea un widget contenedor, que puede contener más de un widget y organizarlos dentro. Observe la rejilla.

// Create the Grid this._grid = new Gtk.Grid ();

Todavía no se le da ninguna propiedad. Estas vendrán después, cuando aprenda cómo usar los poderes de la rejilla. Primero, adjúntele a su rejilla la imagen y la etiqueta que hizo.

// Attach the image and label to the grid this._grid.attach (this._image, 0, 0, 1, 1); this._grid.attach (this._label, 0, 1, 1, 1);

Este código se ve terriblemente complicado, pero no lo es. Aquí está lo que esos números significan:

El primer número es en qué posición de izquierda a derecha se ponen las cosas, comenzando desde 0. Cualquier widget que use un 0 aquí va todo a la izquierda.

El segundo número es en qué posición de arriba a abajo se pone un widget dado, comenzando desde 0. La etiqueta va debajo de la imagen, por lo que se le da a la imagen un 0 y a la etiqueta un 1 aquí.

Los números tercero y cuarto son cuántas columnas y filas debe ocupar un widget. Se verá cómo funciona esto en un minuto.

// Add the grid to the window this._window.add (this._grid);

// Show the window and all child widgets this._window.show_all(); }

});

// Run the application let app = new WelcomeToTheGrid (); app.application.run (ARGV);

Ahora que ha creado la rejilla y le ha adjuntado todos los widgets, se añade a la ventana y se le dice que se muestre, como la última parte de la función «_buildUI». Como siempre, para finalizar se crea una instancia nueva de la clase de la aplicación y se le dice que se ejecute.

Guarde su aplicación como «welcome_to_the_grid.js». Después, para ejecutar su aplicación simplemente abra una terminal, vaya a la carpeta en la que está, y escriba

     $ gjs welcome_to_the_grid.js

¡Allí va! Pero espere. Eso no se ve bien. ¿Por qué la etiqueta está pegada a la imagen así? Eso no se ve tan bien, y la hace difícil de leer. ¿Qué puede hacer acerca de esto?

# Configurar la rejilla

Una cosa que puede hacer, es darle a la etiqueta una propiedad «margin_top» cuando la crea. Esto funciona de manera similar a establecer un margen para un elemento HTML usando estilos CSS en línea.

// Create a label this._label = new Gtk.Label ({ label: "Welcome to GNOME, too!", margin_top: 20 });

Por supuesto, si hace eso y después remplaza la etiqueta con otra cosa (o añade otro widget), entonces tendrá que repetir el «margin_top». De lo contrario, acabará con algo así:

Le podría dar una propiedad «margin_bottom» a la imagen, pero no funcionará cuando la etiqueta nueva esté en una columna separada. Entonces, mejor probar esto:

// Create the Grid this._grid = new Gtk.Grid ({ row_spacing: 20 });

Eso hace que siempre hayan 20 píxeles de espacio entre cada fila horizontal.

Sí, también puede establecer la propiedad «column_spacing» en una rejilla, o las propiedades «margin_left» y «margin_right» en cualquier widget. Pruébelas, si quiere.

# Añadir más widgets

Si quisiera añadir una segunda etiqueta, ¿cómo lo haría para que realmente se vea integrada? Una manera es centrar la imagen en la parte superior, para que esté encima de ambas etiquetas en lugar de sólo de la que está en la izquierda. Allí es donde los otros números en el método «attach» de la rejilla entran:

// Create a second label this._labelTwo = new Gtk.Label ({ label: "The cake is a pie." });

// Attach the image and labels to the grid this._grid.attach (this._image, 0, 0, 2, 1); this._grid.attach (this._label, 0, 1, 1, 1); this._grid.attach (this._labelTwo, 1, 1, 1, 1);

Después de haber creado la segunda etiqueta, se añade a la rejilla a la derecha de la primera. Recuerde, los primeros dos números cuentan columnas y filas de izquierda a derecha y de arriba a abajo, comenzando desde 0. Por lo que si la primera etiqueta está en la columna 0 y fila 1, se puede poner la segunda en la columna 1 y fila 1 para ponerla a la derecha de la primera.

Tenga en cuenta el número 2 en la declaración «attach» de la imagen. Eso es lo que hace el truco. Ese número indica cuántas columnas ocupa la imagen, ¿recuerda? Entonces, cuando se junta todo, se obtiene algo así:

Hay dos cosas de las que debe tomar nota, aquí.

Configurar la imagen para que ocupe dos columnas no la estrecha en sí horizontalmente. En vez de eso, estrecha la caja invisible que el widget «Image» ocupa para llenar ambas columnas, y luego pone la imagen en el centro de esa caja.

Incluso a pesar de que ha establecido las propiedades «row_spacing» de la rejilla y «border_with» de la ventana de la aplicación, todavía no ha establecido nada que ponga un borde entre las dos etiquetas. Estaban separadas anteriormente cuando la imagen estaba en una sola columna, pero ahora que ocupa ambas GNOME no ve una razón para mantenerlas separadas.

Existen por lo menos tres maneras de solucionar esto último. Primero, se puede establecer «margin_left» o «margin_right» en una de las etiquetas:

Segundo, se puede establecer la propiedad «column_homogenous» de la rejilla a «true».

// Create the Grid this._grid = new Gtk.Grid ({ column_homogeneous: true, row_spacing: 20 });

Eso hace que se vea algo así:

And third, we can set the Grid's column_spacing property, the same way we set its row_spacing.

// Create the Grid this._grid = new Gtk.Grid ({ column_spacing: 20, row_spacing: 20 });

That makes it look like this:

# Using stock images

GNOME has a lot of stock images on hand already, that we can use if we don't feel like creating our own or if we want a universally-recognized icon. Here's how we create a stock image, compared to how we create a normal one:

// Create an image this._image = new Gtk.Image ({ file: "gnome-image.png" });

// Create a second image using a stock icon this._icon = new Gtk.Image ({ stock: 'gtk-about' });

After that, we attach it to the Grid to the left of the first Label. (We aren't using the second one for this example.)

// Attach the images and label to the grid this._grid.attach (this._image, 0, 0, 2, 1); this._grid.attach (this._icon, 0, 1, 1, 1); this._grid.attach (this._label, 1, 1, 1, 1);

That gives us this, when we run it:

That's what the stock "About" icon looks like. You can see a list of all the stock items starting with gtk-about in GNOME's developer documentation. It was written for C programmers, but you don't need to know C to use it; just look at the part in quotation marks, like "gtk-about", and copy that part to use the icon next to it.

We put single quotes around 'gtk-about' here because, unlike text strings that have double quotes around them, that part will never need to be translated into another language. In fact, if it were translated it'd break the icon, because its name is still "gtk-about" no matter which language you speak.

# What's next?

Before we go on to the next tutorial, let's try something a little different:

// Create a button this._button = new Gtk.Button ({ label: "Welcome to GNOME, too!"});

// Attach the images and button to the grid this._grid.attach (this._image, 0, 0, 2, 1); this._grid.attach (this._icon, 0, 1, 1, 1); this._grid.attach (this._button, 1, 1, 1, 1);

That's right, we turned the Label into a Button just by changing the name! If you run the application and click on it, though, you'll find that it doesn't do anything. How do we make our Button do something? That's what we'll find out, in our next tutorial.

If you like, feel free to spend some time experimenting with Grids, Labels, and Images, including stock images.

One trick you can use to make more complex layouts is to nest Grids inside of each other. This lets you group together related widgets, and rearrange them easily. Take a look at the RadioButton code sample if you'd like to see how this is done.

# Código de ejemplo completo