Continuaré la serie de posts que he venido haciendo con Vala y Gtk+, esta vez veremos varias cosas, entre las que destacan:
1- Configurar Geany para la compilación directa de codigo fuente de Vala y Gtk+
2- Aprender a agrupar en contenedores los widgets Gtk+
3- Reutilizar codigo fuente
4- Hacer un editor de textos muy muy simple
Entre otras... así que mejor comenzamos
En primer lugar, vamos a instalar Geany, por cierto, aprovecho este parentesis para avisarte que si no tienes las librerias Gtk+, GLib, y el compilador Valac instalados, ve al post llamado , ahi te explico cómo instalarlos desde tus repositorios para que no te descargues codigo fuente.
Creo que no es necesario hacer un tutorial para instalar Geany, así que mejor vamos a lo que nos importa, primero, tenemos el geany así:
Seleccionamos el menú Construir > Preferencias y tendremos una ventana igual a esta (debemos tener un archivo .vala abierto para que nos despliegue las opciones asi):
observa que he hecho cambios a lo que viene por defecto, cambiando unicamente la sección de la compilación, poniendo unicamente así
valac --pkg gtk+-2.0 "%f"
Y con eso el Geany pasará la opción Gtk para el compilador de vala, con el fin de evitar la terminal, asi que nos quedaremos con algo así:
Nota que es un programa Gtk+ y lo hemos compilado directamente.
Y una vez que lo ejecutamos, vamos a ver algo parecido a esto:
Y creo que con esto terminamos el curso intensivo de instalación y configuración de Geany para codigo fuente en Vala con Gtk+
Ahora si, vamos a lo que nos importa de acuerdo al codigo fuente de un ejemplo que puede ser visto en
El ejemplo es muy largo, asi que voy a ponerlo como codigo fuente, sin color y sin resaltos. Si lo quieres ver a color y resaltado, por favor copialo a tu Geany o Gedit y puedes verlo perfectamente.
[color=#000000]using Gtk;
public class TextFileViewer : Window {
private TextView text_view;
public TextFileViewer () {
this.title = "Text File Viewer";
this.position = WindowPosition.CENTER;
set_default_size (400, 300);
var toolbar = new Toolbar ();
var open_button = new ToolButton.from_stock (Stock.OPEN);
open_button.is_important = true;
toolbar.add (open_button);
open_button.clicked.connect (on_open_clicked);
this.text_view = new TextView ();
this.text_view.editable = false;
this.text_view.cursor_visible = false;
var scroll = new ScrolledWindow (null, null);
scroll.set_policy (PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
scroll.add (this.text_view);
var vbox = new VBox (false, 0);
vbox.pack_start (toolbar, false, true, 0);
vbox.pack_start (scroll, true, true, 0);
add (vbox);
}
private void on_open_clicked () {
var file_chooser = new FileChooserDialog ("Open File", this,
FileChooserAction.OPEN,
Stock.CANCEL, ResponseType.CANCEL,
Stock.OPEN, ResponseType.ACCEPT);
if (file_chooser.run () == ResponseType.ACCEPT) {
open_file (file_chooser.get_filename ());
}
file_chooser.destroy ();
}
private void open_file (string filename) {
try {
string text;
FileUtils.get_contents (filename, out text);
this.text_view.buffer.text = text;
} catch (Error e) {
stderr.printf ("Error: %sn", e.message);
}
}
public static int main (string[] args) {
Gtk.init (ref args);
var window = new TextFileViewer ();
window.destroy.connect (Gtk.main_quit);
window.show_all ();
Gtk.main ();
return 0;
}
}
Cuando lo compiles, tendrás algo como esto:
Ahora si, vamos a analizar algunos fragmentos de código para que nos queden claros algunos aspectos del programa.
public class TextFileViewer : Window {
// aqui hay codigo fuente...
}
Aquí se define como una clase (ese nombre reciben las funciones en Vala, haciendo enfasis en que es un tipo de referencia), creando una función llamada TextFileViewer, siendo asignada como una ventana, es decir, en vez de referirnos a la ventana como Window (), nos referiremos a ella como TextFileViewer.
private TextView text_view;
Aqui tambien hacemos una referencia a una función llamada TextView, que en la documentación de Gtk+ es definida como un visor de textos, si quieres ver más acerca de esa función, por favor, visita este enlace .
La función TextView es redireccionada para que sea llamada como text_view en el programa, es similar a usar un alias para mejorar la claridad de la lectura del codigo.
public TextFileViewer () {
this.title = "Text File Viewer";
this.position = WindowPosition.CENTER;
set_default_size (400, 300);
Creo que esta parte no requiere más explicaciones si es que has venido leyendo los posts anteriores, así que nada más te digo que aqui estamos definiendo la función TextFileViewer, que en realidad es una ventana Gtk+, con la posición del la ventana en el Centro de la pantalla (en el post anterior explico como usar diferentes posiciones por defecto), haciendo que la ventana tenga un tamaño por defecto de 400x300 px.
var toolbar = new Toolbar ();
var open_button = new ToolButton.from_stock (Stock.OPEN);
open_button.is_important = true;
toolbar.add (open_button);
open_button.clicked.connect (on_open_clicked);
Aqui, en la primera línea, estamos creando una barra de tareas, usada comunmente para agrupar botones Gtk+, iconos, etiquetas de texto, etc...
Mira esta liga para ver más detalles.
...
En la segunda línea que te pongo aquí, estamos creando un botón, pero esta vez creamos un botón de herramientas (ToolButton), desde el Stock ( mira aqui para más detalles del stock y los botones predefinidos para funciones). Esta vez unicamente se crea un botón para abrir. No te tienes que preocupar acerca del icono, del nombre o de cualquier otra cosa, el stock se encarga de definir eso.
En la linea donde se define si el botón es importante se define positivo, es decir que el botón es importante, para que se muestre el ícono del botón (la carpeta que aparece en muchos programas, y se muestre la cadena de texto "Abrir". Si seleccionamos "false" en esa configuración, se mostrará el botón con el icono, pero no se mostrará la cadena de texto "Abrir" (haz el experimento, no pasa nada ). Sustituye esa linea por esta otra:open_button.is_important = false;
Compila y ejecuta el programa, mira la diferencia y luego me dices.
En la siguiente linea, agregamos el botón abrir a la barra de herramientas, y en la siguiente conectamos al botón abrir con una función llamada "on_open_clicked", misma que viene a ser explicada a continuación.
this.text_view = new TextView ();
this.text_view.editable = false;
this.text_view.cursor_visible = false;
La explicacion de esto es más compleja, si quieres evitarte leer un buen rato, solamente te digo que el metodo this () puede ser usado para crear constructores, mira ejemplos de constructores aqui y puedes comprenderlo mejor.
Si no quieres quebrarte la cabeza con eso, solo te digo que creamos un visor de texto (TextView, porque fue redirigido como text_view en lineas anteriores), definiendo que el visor NO ES EDITABLE, y que el cursor no se ve en el visor.
var scroll = new ScrolledWindow (null, null);
scroll.set_policy (PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
scroll.add (this.text_view);
Aqui añadimos un ScrolledWindow, es decir, una barra de desplazamiento, en caso de que el texto sea más grande de lo que es el TextView, mira para más detalles del ScrolledWindow, por cierto, los dos null que hay ahí significan que NO HAY AJUSTE VERTICAL Y ORIZONTAL.
Por cierto, eso de set_policy (), significa que el ajuste del scroll bar va a ser automático, ahi en la pagina que te acabo de dar viene el metodo para que lo estudies más a fondo.
Por ultimo, el scrollbar empaqueta el text_view dentro de el (adelante habrá un diagrama de los widgets empaquetados, por si no comprendes bien eso)
var vbox = new VBox (false, 0);
vbox.pack_start (toolbar, false, true, 0);
vbox.pack_start (scroll, true, true, 0);
add (vbox);
Aqui creamos un contenedor vertical, el cual está declarado como inhomogéneo, con un espacio entre elementos de 0 px.
Mira para más detalles.
El VBox empaqueta la barra de tareas (toolbar), y enseguida empaqueta el scoll (ScrolledWindow).
En la ultima linea, la ventana agrega el VBox, para finalizar así la parte gráfica inicial del programa.
private void on_open_clicked () {
var file_chooser = new FileChooserDialog ("Open File", this,
FileChooserAction.OPEN,
Stock.CANCEL, ResponseType.CANCEL,
Stock.OPEN, ResponseType.ACCEPT);
if (file_chooser.run () == ResponseType.ACCEPT) {
open_file (file_chooser.get_filename ());
}
file_chooser.destroy ();
}
Aqui estamos definiendo la función on_open_clicked, definida como private, para que UNICAMENTE pueda ser usada dentro de las dos llaves que inician en la linea 3 y terminan en la linea 51.
En la función creamos un FileChooserDialog , el cual tiene la función de abrir, con dos botones del stock: uno para CANCELAR y otro para ACEPTAR.
hay un enunciado de condición: el if() que está ahi, el cual actua unicamente si la respuesta que le damos al FileChooser es ACEPTAR.
Si lo hacemos, se invoca a la función open_file (declarada después), y al terminar salimos del FileChooserDialog, con el nunciado destroy().
En caso de responder negativo (CANCELAR), pasamos directamente el destroy().
private void open_file (string filename) {
try {
string text;
FileUtils.get_contents (filename, out text);
this.text_view.buffer.text = text;
} catch (Error e) {
stderr.printf ("Error: %sn", e.message);
}
}
Aqui estamos definiendo la función open_file, la cual requiere un string como parámetro, llamado "filename".
Dentro de la función, se declara otro string llamado "text", el cual será usado para almacenar el contenido del archivo.
Se invoca a la función FileUtils.get_contents() para obtener el contenido del archivo. Se da como parámetro el string "filename" y como buffer de salida el string "text".
después, el texto del buffer de text_view es declarado igual al texto obtenido con la función get_contents().
En caso de error, se cacha el codigo de error y se desplegará en la terminal.
public static int main (string[] args) {
Gtk.init (ref args);
var window = new TextFileViewer ();
window.destroy.connect (Gtk.main_quit);
window.show_all ();
Gtk.main ();
return 0;
}
}
Aqui se inicia la ejecución del programa. Como muchos saben, el programa no inicia por otro lugar más que por la función main (), la cual estamos declarando.
Se inicia el Gtk.init (ref args);, necesario en TODO programa GTK+.
se crea una nueva ventana, la cual es definida como un nuevo "TextFileViewer"
se conecta el botón cerrar de la ventana con un main_quit. y por ultimo se ordena a la ventana mostrar todo lo que contenga.
Se pasa a la función Gtk.main()
y por ultimo se da el clasico return 0; para finalizar la ejecución del programa.
Ahora creo que ya me he cansado de escribir, asi que nada más te dejo el codigo del editor de textos más simple que existe, y en el proximo post te lo explico linea por linea:
[color=#000000]using Gtk;
public class TextFileViewer : Window {
private TextView text_view;
public TextFileViewer () {
this.title = "Text File Viewer";
this.position = WindowPosition.CENTER;
set_default_size (400, 300);
var toolbar = new Toolbar ();
var open_button = new ToolButton.from_stock (Stock.OPEN);
open_button.is_important = true;
toolbar.add (open_button);
open_button.clicked.connect (on_open_clicked);
var save_button = new ToolButton.from_stock (Stock.SAVE);
open_button.is_important = true;
toolbar.add (save_button);
save_button.clicked.connect (on_save_clicked);
this.text_view = new TextView ();
this.text_view.editable = true;
this.text_view.cursor_visible = true;
var scroll = new ScrolledWindow (null, null);
scroll.set_policy (PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
scroll.add (this.text_view);
var vbox = new VBox (false, 0);
vbox.pack_start (toolbar, false, true, 0);
vbox.pack_start (scroll, true, true, 0);
add (vbox);
}
private void on_open_clicked () {
var file_chooser = new FileChooserDialog ("Abrir archivo", this,
FileChooserAction.OPEN,
Stock.CANCEL, ResponseType.CANCEL,
Stock.OPEN, ResponseType.ACCEPT);
if (file_chooser.run () == ResponseType.ACCEPT) {
open_file (file_chooser.get_filename ());
}
file_chooser.destroy ();
}
private void on_save_clicked () {
var file_chooser = new FileChooserDialog ("Guardar archivo", this,
FileChooserAction.SAVE,
Stock.CANCEL, ResponseType.CANCEL,
Stock.OPEN, ResponseType.ACCEPT);
if (file_chooser.run () == ResponseType.ACCEPT) {
save_file (file_chooser.get_filename ());
}
file_chooser.destroy ();
}
private void open_file (string filename) {
try {
string text;
FileUtils.get_contents (filename, out text);
this.text_view.buffer.text = text;
} catch (Error e) {
stderr.printf ("Error: %sn", e.message);
}
}
private void save_file (string filename) {
try {
FileUtils.set_contents (filename, this.text_view.buffer.text);
} catch (Error e) {
stderr.printf ("Error: %sn", e.message);
}
}
public static int main (string[] args) {
Gtk.init (ref args);
var window = new TextFileViewer ();
window.destroy.connect (Gtk.main_quit);
window.show_all ();
Gtk.main ();
return 0;
}
}
Ahora si, me despido.
Por ultimo te quiero comentar que este post lo he hecho en tres dias (es en serio), asi que por favor tomate la molestia de valorar un poco el esfuerzo. Por supuesto no soy perfecto, asi que si tengo algun error por favor dimelo, yo te lo agradeceré.
Muchas Gracias!!!