General > Programación

[TALLER] Interfaces gráficas con GTK+ y C

(1/5) > >>

5.1:
ACLARACIONES
Antes de nada, me gustaría aclarar algunas cosas.
De entrada esto no pretende ser un curso, mis conocimientos no son los suficientemente avanzados para dar lecciones a nadie, por eso he decidido titularlo Taller, ya que lo único que pretendo aquí es compartir lo que he aprendido estos últimos meses, mis dudas y seguramente mis errores.
Soy un usuario autodidacta y me gusta la programación, pero no me considero un programador, no vivo de ello.
Desde mi punto de vista, hay dos formas de enfocar este taller, una sería pegaros una parrafada técnica, y la segunda desarrollar un programa desde el principio, que me parece una forma mucho más amena de aprender y con la cual obtendremos resultados inmediatos, así que me he decantado por esta segunda opción.
Voy a intentar explicarlo todo con el lenguaje menos técnico posible, aún así, si no sabes ni lo que es una variable quizá este taller no este enfocado para ti.
Aclarado estos punto empezamos.

INTRODUCCION
Lo que aquí haremos sera desarrollar un programa en C, con una GUI(Graphical user interface) basada en la biblioteca GTK (The GIMP Toolkit), estaría bien que echaras un vistazo a este enlace de Wikipedia para ayudar a entender que es GTK.
Simplificando, GTK es una biblioteca que contiene una serie de objetos (Widgets) que podemos usar para el desarrollo de nuestra GUI, un ejemplo de estos pueden ser Labels, Buttons, RadioButtons, CheckButtons, etc ...
Os dejo un enlace a la Galería de Widgets de GTK+3, de cara a que veáis todos los posibles objetos que podemos utilizar.
Básicamente se dividen en dos clases, una serian los contenedores, que como ya indica su nombre son objetos que contienen otros widgets, y la otra los Widgets con los que interactuamos en una GUI.
Por ejemplo, un Frame seria un contenedor que podría contener un botón, un label ... Echad un vistazo a la galería y lo tendréis más claro.
Si hay un interés por este taller y me quedan ganas, más adelante haremos otro con Bash + GtkDialog, algo muy útil también.
Bueno, ya he pegado la parrafada inicial, así que vamos a lo divertido :)

DESARROLLANDO UN PROGRAMA SENCILLO CON GTK + C
Para empezar este taller vamos a desarrollar un sencillo programa que me pidió USUARIONUEVO, se trata de una aplicación que nos calcule el tamaño de un diccionario, tiempo en procesarlo, y número de palabras en función de la cantidad de caracteres que queramos emplear y la longitud de la contraseña a descifrar.

A la hora de hablar del código, voy a estructurarlo en 4 partes :

  - Includes : Serían las declaraciones a otros ficheros necesarios en nuestro código.
  - Declaración de funciones : La parte donde declararemos cada una de las funciones que emplearemos.
  - Variables globales : Aquí declararemos las variables que usaremos desde las distintas funciones.
  - Las funciones : Las diferentes funciones que necesitaremos.

Bien, lo primero que necesitamos es un archivo en el cual escribiremos el código necesario y un editor de texto, en mi caso usare KWrite. Así pues, creamos un archivo de texto que renombraremos a dicciocalc.c y lo abrimos con el editor que elijamos.

Lo primero que tendremos que escribir, sera el include a las biblioteca GTK, por lo que la primera linea de nuestro código será :


--- Código: ---#include <gtk/gtk.h>
--- Fin del código ---
Con esto le estaremos diciendo al compilador que incluya el archivo gtk.h en la compilación de nuestra aplicación.

A continuación vamos a empezar con la función main, la cual suele ser el punto de entrada en un programa escrito en C

--- Código: ---int main(int argc, char *argv[])
{
}

--- Fin del código ---

Ahora empezamos a escribir el código de la función main. Cualquier programa que utilice GTK requiere de las siguiente linea de código inicial, la cual se encarga de inicializar la biblioteca GTK+

--- Código: ---int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
}

--- Fin del código ---

Una vez inicializado GTK podremos empezar a diseñar la interface, aunque de momento saltamos esto, y pasamos a las lineas en las que acaba el diseño de la interface y la mostramos en pantalla.

--- Código: ---int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);

// Codigo del diseño ....

gtk_widget_show_all (window);
gtk_main ();
}

--- Fin del código ---
Si os fijáis, estas dos últimas lineas que he añadido, lo que hacen es primero mostrar todos los widgets que hemos añadido y a continuación con la siguiente línea de código entra en un loop (bucle) esperando a las señales emitidas por los widgets para realizar la acción requerida.
Para aclarar esto os pongo un ejemplo, el programa se muestra en pantalla y entra en el loop (gtk_main), entonces nosotros apretamos un botón de la GUI, en ese momento se produce una señal (evento click) y se desarrolla la acción que hayamos definido al apretar ese botón.
Cuando conectemos señales a sus respectivas funciones lo veréis mucho más claro.

Bien, ahora empecemos a el diseño en sí de la interface. Lo primero que tenemos que añadir es la ventana padre (la de nivel superior), resumiendo es la ventana que contendrá el resto de los widgets.
En cuanto la creemos y compilemos veréis el resultado y lo tendréis claro a que me refiero.

En GTK, los widgets a usar hay que declararlos antes de usarlos, como haríamos con una variable de cualquier tipo. Si nosotros declaramos un Widget (o una variable) dentro de una función, sólo será accesible desde la propia función, y si queremos acceder al Widget (o la variable) desde una función diferente nos dará un error de compilación.
La solución a esto es declarar el Widget o variable en la zona que comente al principio, la de variables globales.
En el caso de la ventana padre, sólo accederemos a ella desde la función main, por lo que la declararemos dentro de esa función. Podemos declararla en cualquier parte del código antes de usarla, pero por mantener un orden todas las declaraciones dentro de una función las haremos al principio de esta.
Por lo tanto, nuestro código quedaría así :


--- Código: ---#include <gtk/gtk.h>

int main(int argc, char *argv[])
{
// Esta es la línea que declara e inicializa el Widget llamado window
GtkWidget *window = NULL;

gtk_init(&argc, &argv);

// Codigo del diseño ....

gtk_widget_show_all (window);
gtk_main ();
}

--- Fin del código ---
Aclarar que el nombre del Widget declarado es window, simplemente por facilitar la comprensión del código, pero en realidad podemos llamarlo de cualquier manera, ya que no definimos el tipo de widget hasta que no lo creamos, recordad, de momento sólo estamos haciendo el paso previo a la creación, la declaración.

Una vez declarado, vamos a crear la ventana (window)


--- Código: ---#include <gtk/gtk.h>

int main(int argc, char *argv[])
{
// Esta es la línea que declara e inicializa el Widget llamado window
GtkWidget *window = NULL;

gtk_init(&argc, &argv);

// EN ESTE BLOQUE DIBUJAMOS LA VENTANA PRINCIPAL
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
//Conecto la señal de cerrar ventana a cerrar el programa
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
// Le digo que al iniciar la ventana esté centrada en la pantalla
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);  
// Defino el título de la ventana
gtk_window_set_title (GTK_WINDOW (window), "DICCIOCALC");
// Defino el borde de la ventana
gtk_container_set_border_width (GTK_CONTAINER (window), 6);
// Defino el tamaño inicial (y será el mínimo)
gtk_widget_set_size_request(window, 350, 350);


// Resto del código de diseño ...

gtk_widget_show_all (window);
gtk_main ();
}

--- Fin del código ---

Bien, ahora paso a comentar linea por linea lo que hemos añadido


--- Código: ---window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
--- Fin del código ---
Aquí estamos diciendo que el widget que habíamos declarado anteriormente es el Widget Window, y que esta sera la ventana de nivel superior.

--- Código: ---g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
--- Fin del código ---
Esta línea es muy importante, estamos conectando la señal que se produce al cerrar la ventana (destroy) con la función "gtk_main_quit", esta es una función ya definida en la librería GTK, y lo que hace es finalizar el entrono GTK, ya que si no la finalizáramos quedarían procesos colgados cuando cerramos el programa.
De momento no explico más en profundidad el tema señales, cuando creemos la del botón para lanzar el proceso de calculo, ya me detendré en la explicación. De momento que os quede claro que la señal destroy es imprescindible añadirla al código.
La podríamos enlazar a una función que creemos nosotros y en esa función añadir el gtk_main_quit() , pero de momento para no liar la cosa lo dejamos como está.


--- Código: ---gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
--- Fin del código ---
Esta línea no requiere mucha explicación, le estamos diciendo que a la hora de mostrar la ventana lo haga en medio de la pantalla.


--- Código: ---gtk_window_set_title (GTK_WINDOW (window), "DICCIOCALC");
--- Fin del código ---
Ahora definimos el título de la ventana, en este caso será el nombre que le queramos dar al programa, yo le he llamado DICCIOCALC, pero vamos, podéis poner el que queráis.


--- Código: ---gtk_container_set_border_width (GTK_CONTAINER (window), 6);
--- Fin del código ---
La ventanas tienen un borde, y este puede ser del tamaño que nosotros queramos, yo le he puesto un borde de grosor 6, pero vamos, eso al gusto, probad diferentes grosores y lo veréis.


--- Código: ---gtk_widget_set_size_request(window, 350, 350);
--- Fin del código ---
Aquí estamos definiendo el tamaño que tendrá la ventana, en principio si no añadimos esta línea, la ventana se ajusta al tamaño de los diferentes widgets que contenga.


Bueno,  hemos visto algunas de las posibilidades que tenemos a la hora de crear un widget Window, pero podemos definir muchas otras características de la ventana. Recomiendo ver la lista completa aqui.

Llegados a este punto ya podemos compilar nuestro programa y ver los primeros resultados.

Para compilarlo :


--- Código: ---gcc dicciocalc.c -o dicciocalc `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0`
--- Fin del código ---

Vamos a ejecutarlo

--- Código: ---./dicciocalc
--- Fin del código ---

Deberíamos ver algo como esto :


Vale, ya tenemos lo que sería el inicio de cualquier programa basado en GTK, es decir, la inclusión de la biblioteca GTK, la función main con la declaración y la creación de la ventana principal.
Ahora es necesario un pequeño descanso para plantearse que necesitamos en nuestra interface.
Existen diseñadores de interfaces de GTK, como por ejemplo Glade, pero a mi no me acaba de convencer, aunque puede ser útil para hacer un diseño de como queremos que quede la interface.
En este caso, al ser una GUI sencilla lo podemos hacer imaginando o sobre el papel.
De entrada nos tenemos que plantear que objectos vamos a necesitar, en el caso de el programa que estamos desarrollando sería lo siguiente.

Yo lo he dividido en tres secciones, y para cada sección emplearemos un contenedor frame

Sección Longitud de la contraseña, a la que añadiremos un spin button con números.
Sección de juego de caracteres, a la que añadiremos diferentes check buttons, uno para las Mayúsculas, otro para Minúsculas, otro para Caracteres Numéricos y finalmente uno para otros caracteres. A este último también le añadiremos otro spin button con números para indicar la cantidad de otros caracteres a emplear.
Sección de contraseñas por segundo, a le que añadiremos un Entry de cara a introducir la cantidad de contraseñas por segundo que es capaz de procesar tu ordenador.
Por último, fuera de estas secciones con frames, añadiremos un boton de cara a lanzar el proceso para los cálculos, y tres labels que nos mostrarán los resultados de los cálculos.

Iremos añadiendo sección a sección y compilando de cara a que vayáis viendo los avances que hacemos ...
De cara a no estar posteando el código fuente a cada momento, todas las líneas de código a partir de ahora y hasta nuevo aviso irán a continuación de la linea "gtk_widget_set_size_request(window, 350, 350);" que es la que empleamos para definir el tamaño de la ventana.

Realmente, antes de empezar con la primera sección, he de puntualizar un detalle. En realidad lo primero que hemos de añadir a la ventana, es un vertical box (vbox), que es un contenedor invisible, pero que hace que los widgets añadidos al vbox se vayan agregando de forma vertical.
Si en un momento dado necesitamos que en una misma línea se añadan dos widgets de forma horizontal, añadiríamos un horizontal box (hbox) y a este le añadiríamos los widgets que deseamos. Lo iréis viendo más claro a medida que lo hagamos.

Entonces lo primero será añadir un vbox a la ventana creada, para ello lo primero sería definir el widget, por lo que a continuación de la línea donde declaramos el widget window debemos añadir la declaración del vbox.
Nos quedaría así ...


--- Código: ---// Esta línea ya la pusimos antes
GtkWidget *window = NULL;
// A continuación añadimos
GtkWidget *vbox;

--- Fin del código ---

Bien, ya la tenemos declarada, ahora hay que crear y empaquetar el vbox


--- Código: ---// Esta línea ya la teníamos
gtk_widget_set_size_request(window, 350, 350);
//Ahora a continuación
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);

--- Fin del código ---

Explico las líneas que hemos añadido ...

--- Código: ---vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
--- Fin del código ---
Le estamos diciendo que el widget que hemos declarado con el nombre de vbox, es un "box" (caja) con orientación vertical, y el 0 indicaría que no deje ningún espacio adicional con los widgets que empaquetemos dentro de ese vbox.
Si queréis ver todas las características de un box, leed esto


--- Código: ---gtk_container_add (GTK_CONTAINER (window), vbox);
--- Fin del código ---
Bien, merece la pena explicar un poco esta linea. Hasta el momento teníamos una ventana que es un GTK_WINDOW, bien, esta ya de por si es un widget de tipo contenedor, es decir, que puede contener a otros widgets.
A la hora de añadir widgets a un contenedor, podemos hacerlo de dos formas diferentes, una sería con gtk_container_add y la otra con gtk_box_pack_start. La diferencia entre una y la otra es que la segunda tiene más opciones de "configuración", ya la explicaré un poco más adelante cuando la usemos, de momento me centro en la que usamos en esta línea de código, gtk_container_add.
La declaración de esta sería

--- Código: ---void gtk_container_add (GtkContainer *container, GtkWidget *widget);  // OJO, esto NO tenemos que añadirlo a nuestro código, simplemente es con carácter informativo que lo pongo aquí
--- Fin del código ---
Es decir, en el primer parámetro de indicamos a que tipo de container lo vamos a añadir, y con el segundo le indicamos el widget a añadir, en este caso estamos añadiendo a la ventana principal (recordad que la llamamos window) que es del tipo GTK_CONTAINER, un widget al que hemos llamado vbox.
Ahora el contenedor al que deberemos añadir los siguientes widgets sería este vbox, enseguida lo comprobareis.

Añadiendo la primera sección (Longitud de la contraseña)
Bien, ahora que ya tenemos la ventana creada y su vertical box, vamos a añadir el primer frame, para ello lo primero es la declaración de dicho frame.

--- Código: ---// Estas 2 líneas ya las teniamos
GtkWidget *window = NULL;
GtkWidget *vbox;
// A continuación añadimos
GtkWidget *frame_longitud;

--- Fin del código ---
Como podéis ver hemos declarado un widget con el nombre frame_longitud. Lo he llamado así porque como después crearemos otros frames, para no liarnos le he agregado el nombre de la sección que estamos creando, en este caso como estamos haciendo la parte donde ingresaremos la longitud de la contraseña, pues eso, longitud.

Ya lo tenemos declarado, ahora toca crear el widget.

--- Código: ---// Esta línea ya la teníamos
gtk_container_add (GTK_CONTAINER (window), vbox);
//Ahora a continuación
frame_longitud = gtk_frame_new ("  LONGITUD DE LA CONTRASEÑA  ");
gtk_container_add(GTK_CONTAINER(vbox), frame_longitud);

--- Fin del código ---
Aquí veis que hemos creado un nuevo frame, llamado  frame_longitud, y con el título "LONGITUD DE LA CONTRASEÑA" , y a continuación lo hemos añadido al vbox con gtk_container_add
Fijaros bien, que ahora no lo hemos añadido a window, lo estamos añadiendo a vbox, el vertical box que creamos en la ventana superior (window).

Bien, ahora tocaría añadir un nuevo vertical box, pero esta vez al frame_longitud, como siempre para ello lo primero sería la declaración del widget.

--- Código: ---// Ahora no creo una linea nueva, lo añado a continuación de la declaración de vbox.
GtkWidget *window = NULL;
GtkWidget *vbox, *vbox_long;
GtkWidget *frame_longitud;

--- Fin del código ---
Bien, por mantener un mínimo orden, he declarado el widget vbox_long a continuación de vbox. Podemos añadir en una linea todos los que queramos, yo los separo por clases por mantener un orden, en este caso todos los vertical box en la misma línea.
Y como antes, los widgets que agreguemos en este frame, los añadiremos a este nuevo vertical box (vbox_long).

Una vez declarado, toca añadirlo.

--- Código: ---// Esta líneas ya las teníamos
frame_longitud = gtk_frame_new ("  LONGITUD DE LA CONTRASEÑA  ");
gtk_container_add(GTK_CONTAINER(vbox), frame_longitud);
// Ahora agregamos el vbox_long al frame_longitud
vbox_long = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame_longitud), vbox_long);

--- Fin del código ---
Es lo mismo que explique antes, hemos creado un box vertical, y lo hemos añadido a su contenedor inmediatamente superior, en este caso frame_longitud.

Ahora y como último paso en esta sección de la longitud de la contraseña, vamos a añadir un spin button, que contendrá números del 1 al 100 de cara a indicar el tamaño que tendrá la contraseña que queremos averiguar.
Una vez más el primer paso es la declaración, pero aquí la cosa cambia. En este caso, cuando pulsemos el botón para hacer los calculos necesario (tamaño del diccionario, número de palabras etc..), el control del programa pasará a otra función distinta a main, por lo que como os explique al principio si declaramos el spin button en la función main, al intentar acceder a ella desde la función calcular nos dará un error. Por tanto vamos a declarar este spin button en la zona de la que hablé al principio, la de las variables globales.

La cosa quedaría así :

--- Código: ---// El include a la libería ya lo teniamos ...
#include <gtk/gtk.h>

// Aquí irá una parte del código en la cual declararemos las funciones que aún tenemos que crear

// Y aquí pondríamos las declaraciónes globales
GtkWidget *spinner_long;

--- Fin del código ---
Es exactamente lo mismo que hemos estado haciendo hasta ahora para la declaración de los widgets, pero en una zona diferente del código. En este caso hemos declarado el widget con el nombre "spinner_long".
Una vez más insisto que el nombre que le pongamos a un widget cuando lo declaramos no define el tipo de widget que será, pero es conveniente poner un nombre acorde a lo que queremos crear de cara a una fácil comprensión del código.

Tal como funciona un spin button, para crearlo tenemos que pasarle una serie de parametros, y para ello necesitamos crear un nuevo objeto, un GtkAdjustment, el cual contendrá una serie de parámetros que ahora explicaré y que aplicaremos a nuestro spin button.

Igual que siempre, lo primero es declararlo, esta vez como no necesitamos acceder a el desde otras funciones lo haremos donde hemos hecho el resto de declaraciones en la función main.

--- Código: ---// Esto es lo que teniamos hasta ahora
GtkWidget *window = NULL;
GtkWidget *vbox, *vbox_long;
GtkWidget *frame_longitud;
// Ahora declaro en GtkAdjustment
GtkAdjustment *spinner_adj;

--- Fin del código ---
Tan sólo comentar que en este caso no lo declaramos como un GtkWidget, si no como GtkAdjustment..

Una vez declarados el spin button y el GtkAdjustment toca añadirlos al vbox_long (que es el vertical box que agreramos al frame_longitud).


--- Código: ---// Esto era lo último que habíamos añadido
vbox_long = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame_longitud), vbox_long);
// Ahora toca crear el spinner, aplicar los ajustes y mostrarlo
spinner_adj = (GtkAdjustment *) gtk_adjustment_new (8.0, 1.0, 100.0, 1.0, 1.0, 1.0);
spinner_long = gtk_spin_button_new (spinner_adj, 1.0, 0);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinner_long), TRUE);
gtk_box_pack_start (GTK_BOX(vbox_long), spinner_long, FALSE, FALSE, 0);

--- Fin del código ---

Paso a explicar cada línea de lo que acabamos de añadir

--- Código: ---spinner_adj = (GtkAdjustment *) gtk_adjustment_new (8.0, 1.0, 100.0, 1.0, 1.0, 1.0);
--- Fin del código ---
Acabamos de crear el objeto que declaramos antes, que llamamos spinner_adj, y le estamos diciendo que es un nuevo GtkAdjustment con las siguientes características :
     - Valor inicial : 8
     - Valor mínimo : 1
     - Valor máximo 100
     - Incremento mínimo en una pulsación: 1
     - Incremento máximo en una pulsación: 1
     - El último valor sinceramente no lo entiendo muy bien, pero ajustándolo a 1 funciona como queremos que funcione.
Aquí teneis al detalle la declaración de gtk_adjustment_new().


--- Código: ---spinner_long = gtk_spin_button_new (spinner_adj, 1.0, 0);
--- Fin del código ---
Ahora ya estamos creando el spin button, le pasamos el GtkAdjustment que hemos creado, el incremento u por último el número de decimales a mostrar, en este caso será 0 ya que no necesitamos valores con decimales.
Aquí tenéis al detalle la declaración de gtk_spin_button_new


--- Código: ---gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinner_long), TRUE);
--- Fin del código ---
Le estamos diciendo que el GTK_SPIN_BUTTON spinner_long (el que estamos añadiendo) sea solo numérico.


--- Código: ---gtk_box_pack_start (GTK_BOX(vbox_long), spinner_long, FALSE, FALSE, 0);
--- Fin del código ---
Aqí estamos usando la otra forma de añadir wigets que comenté anteriormente. Por un lado teníamos gtk_container_add que es la que habiamos usado hasta ahora, y por otro lado esta que acabamos de utilizar. Como ya dije antes esta forma tiene más control sobre como mostramos el widget en cuestión.
Podéis ver la declaración al detalle aquí
Bien, en este caso estamos diciendo que empaquete en el contenedor vbox_long, el widget spinner_long, que no se expanda, ni ocupe todo el espacio cuando cambiamos el tamaño de la ventana, y que no deje espacio (en píxeles) con su contenedor. La mejor forma de entender esto es ir cambiando los valores FALSE a TRUE e ir haciendo pruebas compilando y ejecutándolo.

Llegados a este punto ya tenemos la sección de la Longitud de la Contraseña creada totalmente, ahora podemos compilar y probar como tenemos el programa hasta ahora.

El código completo hasta ahora debería quedaros así.

--- Código: ---#include <gtk/gtk.h>

//Declaraciones globales
GtkWidget *spinner_long;

int main(int argc, char *argv[])
{
// Declaraciones
GtkWidget *window = NULL;
GtkWidget *vbox, *vbox_long;
GtkWidget *frame_longitud;
GtkAdjustment *spinner_adj;

gtk_init(&argc, &argv);

// EN ESTE BLOQUE DIBUJAMOS LA VENTANA PRINCIPAL
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
//Conecto la señal de cerrar ventana a cerrar el programa
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
// Le digo que al iniciar la ventana esté centrada en la pantalla
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);  
// Defino el título de la ventana
gtk_window_set_title (GTK_WINDOW (window), "DICCIOCALC");
// Defino el borde de la ventana
gtk_container_set_border_width (GTK_CONTAINER (window), 6);
// Defino el tamaño inicial (y será el mínimo)
gtk_widget_set_size_request(window, 350, 350);

//AÑADO UN VERTICALBOX PARA CONTENER LOS WIDGETS
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);


//AÑADO UN FRAME PARA LA LONGTUD DE LA CONTRASEÑA
frame_longitud = gtk_frame_new ("  LONGITUD DE LA CONTRASEÑA  ");
gtk_container_add(GTK_CONTAINER(vbox), frame_longitud);
// Añado un vbox al frame
vbox_long = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame_longitud), vbox_long);
//Añado el spinner al vbox
spinner_adj = (GtkAdjustment *) gtk_adjustment_new (8.0, 1.0, 100.0, 1.0, 1.0, 1.0);
spinner_long = gtk_spin_button_new (spinner_adj, 1.0, 0);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinner_long), TRUE);
gtk_box_pack_start (GTK_BOX(vbox_long), spinner_long, FALSE, FALSE, 0);

// Resto del código de diseño ...

gtk_widget_show_all (window);
gtk_main ();
return 0;
}
--- Fin del código ---

Recordad, para compilar :

--- Código: ---gcc dicciocalc.c -o dicciocalc `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0`
--- Fin del código ---


Al ejecutarlo ...


Bien, ya tenemos la primera sección, vamos a por la segunda, "Juego de caracteres".
Tenemos que añadir un nuevo frame, así que como siempre, lo primero declararlo. Y como sólo accederemos a el desde el main, pues es en esa función que lo declaramos.


--- Código: ---// Declaraciones
GtkWidget *window = NULL;
GtkWidget *vbox, *vbox_long;
GtkWidget *frame_longitud, *frame_chars;
GtkAdjustment *spinner_adj;

--- Fin del código ---

Fijaros que lo he declarado a continuación del frame que ya teniamos, y lo he hecho con el nombre de frame_chars.

Ahora toca agregar el código para agregarlo.

--- Código: ---// Estas dos líneas es lo último que teniamos
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinner_long), TRUE);
gtk_box_pack_start (GTK_BOX(vbox_long), spinner_long, FALSE, FALSE, 0);
//Ahora añadimos lo siguiente
frame_chars = gtk_frame_new ("  JUEGO DE CARACTERES  ");
gtk_box_pack_start (GTK_BOX (vbox), frame_chars, FALSE, FALSE, 10);

--- Fin del código ---
Es lo mismo que ya habiamos hecho antes, la única diferencia es que si os fijáis a la hora de empaquetarlo dejamos una separación de 10 pixeles con el frame que ya teniamos creado.

Lo mismo que en el frame anterior, ahora toca crear un vertical box de cara a añadir a el los widgets necesarios de esta sección, por tanto lo primero ya sabeis que es, declarar ese vertical box, y una vez más, lo haremos en la función main.

--- Código: ---// Declaraciones
GtkWidget *window = NULL;
GtkWidget *vbox, *vbox_long, *vbox_chars;
GtkWidget *frame_longitud, *frame_chars;
GtkAdjustment *spinner_adj;

--- Fin del código ---
No hay mucho que comentar, hemos declarado dicho vertical box con el nombre de vbox_chars.

Como siempre el procedimiento es el mismo, declaramos, creamos y empaquetamos, por tanto :

--- Código: ---// Estas dos líneas es lo último que teniamos
frame_chars = gtk_frame_new ("  JUEGO DE CARACTERES  ");
gtk_box_pack_start (GTK_BOX (vbox), frame_chars, FALSE, FALSE, 10);
//Una vez mas primero lo creamos y luego lo añadimos.
vbox_chars = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame_chars), vbox_chars);

--- Fin del código ---

Si os dais cuenta siempre es lo mismo, habíamos declarado un frame, lo creamos y empaquetamos. Ahora hemos declarado un vertical box, lo creamos y lo agregamos a ese frame, y a partir de ahora los widgets que agreguemos lo haremos a este vbox_chars.

En esta sección será la que le digamos al programa que juegos de caracteres usar para que haga los calculos del diccionario que podriamos crear con ellos (los juegos de caracteres). Por lo tanto necesitamos :
   - Un check button que llamaremos opcion_alfa_mayusculas.
   - Un check button que llamaremos opcion_alfa_minusculas.
   - Un check button que llamaremos opcion_numeros.
   - Un check button que llamaremos opcion_otros.
   - Un spin button que llamaremos spinner_chars.

Empezamos con las declaraciones, pero en este caso necesitaremos acceder a estos widgets desde otra función diferente a main, por lo que tenemos que declararlos en la zona de variables globales (Al principio del código)...
Esto es lo que teníamos

--- Código: ---//Declaraciones globales
GtkWidget *spinner_long;

--- Fin del código ---
Nos quedará así

--- Código: ---//Declaraciones globales
GtkWidget *spinner_long, *spinner_chars;;
GtkWidget *opcion_alfa_mayusculas, *opcion_alfa_minusculas, *opcion_numeros, *opcion_otros;

--- Fin del código ---
A estas alturas no creo que sea necesario explicar lo que hemos hecho, ya debería estar claro como se declara un widget.

Una vez más, ahora toca crear y agregar los widgets creados...

--- Código: ---// Lo último que habiamos puesto era la creacion y empaquetado del vbox_chars en el frame
vbox_chars = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame_chars), vbox_chars);
// Ahora creamos y empaquetamos los widgets en ese vbox_chars

//Añadimos los checkbox alfabeticos
opcion_alfa_mayusculas = gtk_check_button_new_with_label("Mayúsculas (A-Z)");
gtk_box_pack_start (GTK_BOX (vbox_chars), opcion_alfa_mayusculas, FALSE, FALSE, 3);

opcion_alfa_minusculas = gtk_check_button_new_with_label("Minúsculas (a-z)");
gtk_box_pack_start (GTK_BOX (vbox_chars), opcion_alfa_minusculas, FALSE, FALSE, 3);

opcion_numeros = gtk_check_button_new_with_label("Numérico (0-9)");
gtk_box_pack_start (GTK_BOX (vbox_chars), opcion_numeros, FALSE, FALSE, 3);

--- Fin del código ---
Bien, de momento sólo añadimos 3 de los 4, ya que el de "opcion_otros" es un tanto especial, ahora lo veréis.
En los tres ya añadidos es lo mismo, lo hemos creado con el texto correspondiente a cada uno (o sea Mayúsculas A-Z, Minuscúlas a-z, etc ..) y hemos dejado un espacio de 3 pixeles entre ellos a la hora de empaquetarlos con gtk_box_pack_start.
Como mucho decir que os fijéis en que cuando empaquetamos siempre le decimos que lo haga a vbox_chars.

Ahora toca el ocion_otros, pero este tiene una característica especial, y es que al lado del check button , tenemos que añadir un spin button.
¿ Y cómo hacemos esto ? Muy sencillo, igual que hasta ahora para poner un widget debajo del siguiente habíamos creado un vertical box y añadido los widgets a este, ahora vamos a crear un horizontal box (le llamaremos hbox), añadiremos este hbox al vbox_chars, y después añadiremos el opcion_otros y el spin button a este hbox, de manera que en una misma línea horizontal nos aparezcan los dos widgets.

Por enésima vez, lo primero declarar el horizonal box, en este caso en la zona de declaraciones del main.

--- Código: ---// Declaraciones
GtkWidget *window = NULL;
GtkWidget *vbox, *vbox_long, *vbox_chars;
GtkWidget *frame_longitud, *frame_chars;
GtkAdjustment *spinner_adj;
// Agregamosla declaración del hbox
GtkWidget *hbox;

--- Fin del código ---

Y repetimos el proceso de siempre, creación y empaquetado.

--- Código: ---// Lo último que habiamos puesto era la creacion y empaquetado de la  opcion_numeros
opcion_numeros = gtk_check_button_new_with_label("Numérico (0-9)");
gtk_box_pack_start (GTK_BOX (vbox_chars), opcion_numeros, FALSE, FALSE, 3);

// Ahora le toca al hbox recién declarado
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add (GTK_CONTAINER (vbox_chars), hbox);

--- Fin del código ---
Fijaros que en vez de decirle que cree el box de forma vertical ( GTK_ORIENTATION_VERTICAL) lo hemos hecho pasándole el argumento para que lo haga de forma horizontal con GTK_ORIENTATION_HORIZONTAL, y lo hemos añadido al vbox_chars. Ahora tan solo queda añadir lo que nos queda de esta sección al hbox.

--- Código: ---// Lo último que habiamos puesto era la creacion y empaquetado del  hbox
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add (GTK_CONTAINER (vbox_chars), hbox);

// Ahora añadimos los widgets que nos faltan, ya sabéis, primero creamos y luego empaquetamos.
opcion_otros = gtk_check_button_new_with_label("Otros carácteres (Indicar número)");
gtk_box_pack_start (GTK_BOX (hbox), opcion_otros, FALSE, FALSE, 0);

spinner_adj = (GtkAdjustment *) gtk_adjustment_new (10.0, 1.0, 40.0, 1.0, 1.0, 1.0);
spinner_chars = gtk_spin_button_new (spinner_adj, 1.0, 0);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinner_chars), TRUE);
gtk_box_pack_start (GTK_BOX(hbox), spinner_chars, FALSE, FALSE, 5);

--- Fin del código ---
Hemos agregado el checkbutton con las dos primeras líneas. A continuación definimos los ajustes del spinner tal como hicimos antes con el spinner de la longitud de contraseña, le decimos que solo sea numérico y empaquetamos. Daros cuenta que estos dos últimos widgets los hemos agregado al hbox para que nos aparezcan de forma horizontal, dejando un espacio entre ellos de 5 pixeles.

Bueno, pues ya hemos acabado otra sección, os pongo el código completo hasta ahora.


--- Código: ---#include <gtk/gtk.h>

//Declaraciones globales
GtkWidget *spinner_long, *spinner_chars;;
GtkWidget *opcion_alfa_mayusculas, *opcion_alfa_minusculas, *opcion_numeros, *opcion_otros;

int main(int argc, char *argv[])
{
// Declaraciones del main
GtkWidget *window = NULL;
GtkWidget *vbox, *vbox_long, *vbox_chars;
GtkWidget *frame_longitud, *frame_chars;
GtkAdjustment *spinner_adj;
GtkWidget *hbox;

gtk_init(&argc, &argv);

// EN ESTE BLOQUE DIBUJAMOS LA VENTANA PRINCIPAL
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
//Conecto la señal de cerrar ventana a cerrar el programa
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
// Le digo que al iniciar la ventana esté centrada en la pantalla
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);  
// Defino el título de la ventana
gtk_window_set_title (GTK_WINDOW (window), "DICCIOCALC");
// Defino el borde de la ventana
gtk_container_set_border_width (GTK_CONTAINER (window), 6);
// Defino el tamaño inicial (y será el mínimo)
gtk_widget_set_size_request(window, 350, 350);

//AÑADO UN VERTICALBOX PARA CONTENER LOS WIDGETS
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);


//AÑADO UN FRAME PARA LA LONGTUD DE LA CONTRASEÑA
frame_longitud = gtk_frame_new ("  LONGITUD DE LA CONTRASEÑA  ");
gtk_container_add(GTK_CONTAINER(vbox), frame_longitud);
// Añado un vbox al frame
vbox_long = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame_longitud), vbox_long);
//Añado el spinner al vbox
spinner_adj = (GtkAdjustment *) gtk_adjustment_new (8.0, 1.0, 100.0, 1.0, 1.0, 1.0);
spinner_long = gtk_spin_button_new (spinner_adj, 1.0, 0);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinner_long), TRUE);
gtk_box_pack_start (GTK_BOX(vbox_long), spinner_long, FALSE, FALSE, 0);


//AÑADO UN FRAME PARA LOS JUEGOS DE CARACTERES
frame_chars = gtk_frame_new ("  JUEGO DE CARACTERES  ");
//gtk_container_add(GTK_CONTAINER(vbox), frame_chars);
gtk_box_pack_start (GTK_BOX (vbox), frame_chars, FALSE, FALSE, 10);
// Añado un vbox al frame
vbox_chars = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame_chars), vbox_chars);
//Añadimos los checkbox alfabeticos
opcion_alfa_mayusculas = gtk_check_button_new_with_label("Mayúsculas (A-Z)");
gtk_box_pack_start (GTK_BOX (vbox_chars), opcion_alfa_mayusculas, FALSE, FALSE, 3);

opcion_alfa_minusculas = gtk_check_button_new_with_label("Minúsculas (a-z)");
gtk_box_pack_start (GTK_BOX (vbox_chars), opcion_alfa_minusculas, FALSE, FALSE, 3);

opcion_numeros = gtk_check_button_new_with_label("Numérico (0-9)");
gtk_box_pack_start (GTK_BOX (vbox_chars), opcion_numeros, FALSE, FALSE, 3);

//Añado un hbox
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add (GTK_CONTAINER (vbox_chars), hbox);

// Añado el opcion_otros y el spinner_chars al hbox
opcion_otros = gtk_check_button_new_with_label("Otros carácteres (Indicar número)");
gtk_box_pack_start (GTK_BOX (hbox), opcion_otros, FALSE, FALSE, 0);

spinner_adj = (GtkAdjustment *) gtk_adjustment_new (10.0, 1.0, 40.0, 1.0, 1.0, 1.0);
spinner_chars = gtk_spin_button_new (spinner_adj, 1.0, 0);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinner_chars), TRUE);
gtk_box_pack_start (GTK_BOX(hbox), spinner_chars, FALSE, FALSE, 5);


// Resto del código de diseño ...


gtk_widget_show_all (window);
gtk_main ();
return 0;
}

--- Fin del código ---

Si compilamos tendremos esto :





En construcción, to be continued ...

5.1:
Ya que no puedo moderar esta sección del foro, reservo este post ....

jostey:
Me sumo a estos consejos, que a pesar de que estoy estudiando C en este curso, aun no vimos nada con interfaz gráfica. Ánimo!  ;D

sanson:
Ponemos  chincheta y proponemos al jefe que moderes la zona , cosa lógica por otro lado

Eso si , ni un permiso que te vigiló jejjjeje


Editó

A coño que ya esta vk , pensaba que era nueva sección jejejejeje

5.1:

--- Cita de: sanson en 28-07-2015, 22:50 (Martes) ---Ponemos  chincheta y proponemos al jefe que moderes la zona , cosa lógica por otro lado

Eso si , ni un permiso que te vigiló jejjjeje


Editó

A coño que ya esta vk , pensaba que era nueva sección jejejejeje

--- Fin de la cita ---

Sí sí, que con el movimiento que hay en esta sección se necesitan 2 o 3 moderadores  ;D

Nada, si necesito que se borre/edite/mueva  algo del post, ya se lo diré a vk, pero vamos, no creo que este muy concurrido este hilo ...

Navegación

[0] Índice de Mensajes

[#] Página Siguiente

Ir a la versión completa