Curso de programación en C moderno

Anuncio
Portada
Sobre GTK
Curso de programación en C moderno
Bucle
principal
(II Edición)
Señales
Callbacks
Glade y
builder
Neira Ayuso, Pablo
Ejemplo
simple
Tema 14
Juego de la
vida
GTK
main
gui object
drawing area
Timer
Ejercicio
Índice
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
Falgueras García, Carlos
1 Sobre GTK
2 Bucle principal
3 Señales
4 Callbacks
5 Glade y builder
6 Ejemplo simple
7 Juego de la vida
main
gui object
drawing area
Timer
Ejercicio
Sobre GTK
Portada
• GTK (Gimp ToolKit) es una biblioteca libre y
multiplataforma para el desarrollo de interfaces gráficas de
usuario
Sobre GTK
Bucle
principal
• Está escrita en C, aunque tiene bindings a una infinidad de
Señales
lenguajes distintos (C++, C#, Python, Lua, Haskel, . . . )
• Se trata de una biblioteca muy popular, con mucha
Callbacks
Glade y
builder
comunidad alrededor y muchos años de madurez
• Las interfaces se construyen mediante la anidación de
Ejemplo
simple
diversos widget. Tiene una enorme variedad de widgets
(ejecutar “gtk3-widget-factory”)
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
• Dispone de una documentación detallada y de calidad
(https://developer.gnome.org/gtk3/stable/).
Además de numerosos tutoriales y ejemplos desarrollados
por su gran comunidad.
Bucle principal
• Toda la lógica de la interfaz se realiza dentro de un bucle
Portada
•
•
•
•
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
1
2
3
4
5
#i n c l u d e <g t k / g t k . h>
i n t main ( i n t a r g c , c h a r ∗∗ a r g v )
{
GtkWidget ∗ window ;
6
g t k _ i n i t (& a r g c , &a r g v ) ;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL) ;
g t k _ w i d g e t _ s h o w _ a l l ( window ) ;
gtk_main ( ) ;
7
8
9
10
11
12
13
infinito gtk_main();
Antes del bucle la interfaz no es funcional
Después del bucle no existe interfaz
No podemos modificar el interior del bucle
¿Cómo interacciono con la interfaz gráfica?
}
return 0;
Señales
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
• Una señal puede verse como un mensaje que nos envía
GTK cada vez que ocurre un evento
• Un evento puede ser cualquier acción del usuario: un click
en un botón, mover el ratón sobre una ventana, arrastar
algún objeto, . . . . También hay eventos internos de la
interfaz gráfica: se acaba de crear/destruir la ventana, se
va a redibujar algún objeto, . . .
• En GTK se implementan mediante callbacks
Callbacks
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
• Un callback es una función que pasamos a alguna librería,
para que ella se encargue de llamarla cuando convenga
• GTK guarda una lista de punteros a funciones por cada
posible evento
• Como usuarios de GTK, conectamos una o más funciones
de callback a una señal (pulsar un botón). Cuando ocurra
el evento oportuno, GTK se encargará de llamarlas a todas
Glade y builder
Portada
• Crear una interfaz compleja directamente en un lenguaje
de programación es complejo y poco versátil
Sobre GTK
• GTK puede crear e inicializar todos los objetos necesarios a
Bucle
principal
partir de un XML con la descripción de la interfaz
Señales
• Glade es un programa que nos ayuda a construir este XML
Callbacks
de manera gráfica
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
Ejemplo simple
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#i n c l u d e < s t d i o . h>
#i n c l u d e < s t d l i b . h>
#i n c l u d e <g t k / g t k . h>
#d e f i n e BUILDER_FILE " b u i l d e r . u i "
i n t main ( i n t a r g c , c h a r ∗∗ a r g v )
{
GtkBuilder ∗ builder ;
G t k W i d g e t ∗ window ;
GtkWidget ∗ b u t t o n 1 ;
GtkWidget ∗ b u t t o n 2 ;
g t k _ i n i t (& a r g c , &a r g v ) ;
/∗ b u i l d e r ∗/
b u i l d e r = gtk_builder_new ( ) ;
i f ( ! g t k _ b u i l d e r _ a d d _ f r o m _ f i l e ( b u i l d e r , BUILDER_FILE , NULL ) ) {
f p r i n t f ( s t d e r r , " Can ' t open f i l e \"% s \"\ n " , BUILDER_FILE ) ;
e x i t ( EXIT_FAILURE ) ;
}
/∗ o b j e c t s ∗/
window = GTK_WIDGET( g t k _ b u i l d e r _ g e t _ o b j e c t ( b u i l d e r , " window " ) ) ;
b u t t o n 1 = GTK_WIDGET( g t k _ b u i l d e r _ g e t _ o b j e c t ( b u i l d e r , " b u t t o n 1 " ) ) ;
b u t t o n 2 = GTK_WIDGET( g t k _ b u i l d e r _ g e t _ o b j e c t ( b u i l d e r , " b u t t o n 2 " ) ) ;
Ejemplo simple
Portada
Sobre GTK
27
28
29
/∗ s i g n a l s ∗/
g _ s i g n a l _ c o n n e c t ( window , " d e s t r o y " , G_CALLBACK( g t k _ m a i n _ q u i t ) ,
NULL ) ;
g _ s i g n a l _ c o n n e c t ( b u t t o n 1 , " c l i c k e d " , G_CALLBACK( b u t t o n _ c b ) , " H o l a "
);
g _ s i g n a l _ c o n n e c t ( b u t t o n 2 , " c l i c k e d " , G_CALLBACK( b u t t o n _ c b ) , " A d i o s
") ;
g t k _ b u i l d e r _ c o n n e c t _ s i g n a l s ( b u i l d e r , NULL ) ;
Bucle
principal
30
Señales
31
Callbacks
32
33
34
g t k _ w i d g e t _ s h o w _ a l l ( window ) ;
35
gtk_main ( ) ;
36
37
return 0;
38 }
39
40 s t a t i c v o i d b u t t o n _ c b ( G t k W i d g e t ∗ w i d g e t ,
41 {
42
p r i n t f ( "%s mundo ! \ n " , s t r ) ;
43 }
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
const
char ∗ s t r )
gcc -g $(pkg-config --cflags gtk+-3.0 --libs gtk+-3.0)main.c
Juego de la vida
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
Juego de la vida
main
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
1 i n t main ( i n t a r g c , c h a r ∗∗ a r g v )
2 {
3
s t r u c t w o r l d ∗w ;
4
s t r u c t g u i ∗g ;
5
6
g t k _ i n i t (& a r g c , &a r g v ) ;
7
8
w = w o r l d _ a l l o c (WORLD_X, WORLD_Y) ;
9
i f ( ! w) {
10
p e r r o r ( " Can ' t a l l o c a t e w o r l d " ) ;
11
e x i t ( EXIT_FAILURE ) ;
12
}
13
w o r l d _ i n i t (w) ;
14
15
g = g u i _ a l l o c ( " b u i l d e r . u i " , w , WINDOW_X, WINDOW_Y) ;
16
i f (! g) {
17
p e r r o r ( " Can ' t c r e a t e g u i " ) ;
18
e x i t ( EXIT_FAILURE ) ;
19
}
20
21
gtk_main ( ) ;
22
23
w o r l d _ f r e e (w) ;
24
gui_free (g) ;
25
26
return 0;
27 }
gui object
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
1 struct gui {
2
GtkBuilder ∗ builder ;
3
4
G t k W i d g e t ∗ window ;
5
GtkWidget ∗ btn_quit ;
6
GtkWidget ∗ btn_step ;
7
GtkWidget ∗ btn_pause ;
8
GtkGrid
∗ grid ;
9
GtkWidget ∗ drawing_area ;
10
11
struct {
12
double x ;
13
double y ;
14
} cell_size ;
15
16
bool run ;
17
18
s t r u c t world ∗ world ;
19 } ;
drawing area
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
/∗ d r a w i n g a r e a ∗/
g−>d r a w i n g _ a r e a = gtk_drawing_area_new ( ) ;
// Tamanyo d e l l a v e n t a n a de d i b u j a d o
g t k _ w i d g e t _ s e t _ s i z e _ r e q u e s t ( g−>d r a w i n g _ a r e a , ws_x , ws_y ) ;
// N e c e s a r i o p a r a c a p t u r a r l o s c l i c k d e l r a t o n
g t k _ w i d g e t _ s e t _ e v e n t s ( g−>d r a w i n g _ a r e a ,
g t k _ w i d g e t _ g e t _ e v e n t s ( g−>d r a w i n g _ a r e a ) | GDK_BUTTON_PRESS_MASK) ;
// Any ad imos e l n u e v o w i d g e t a l g r i d
g t k _ g r i d _ a t t a c h _ n e x t _ t o ( g−>g r i d , g−>d r a w i n g _ a r e a , g−>b t n _ q u i t ,
GTK_POS_BOTTOM, 1 , 1 ) ;
s t a t i c g b o o l e a n draw_cb ( G t k W i d g e t ∗ w i d g e t ,
g)
{
/∗ C l e a r s c r e e n ∗/
cairo_set_source_rgb ( cr , 0 , 0 , 0) ;
cairo_paint ( cr ) ;
cairo_t ∗ cr ,
struct
gui ∗
/∗ TODO
∗ D i b u j a e l mundo s a b i e n d o que e l c o d i g o de a b a j o d i b u j a un
rectangulo
∗ b l a n c o en l a s c o o r d e n a d a s ( 2 , 3 ) de 5 x4 p i x e l e s de tamanyo
∗/
cairo_set_source_rgb ( cr , 1 , 1 , 1) ;
c a i r o _ r e c t a n g l e ( cr , 2 , 3 , 5 , 4) ;
c a i r o _ f i l l ( cr ) ;
9
10
11
12
13
14
15
return
16 }
false ;
Timer
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
1 s t a t i c v o i d pause_cb ( G t k W i d g e t ∗ w i d g e t , s t r u c t g u i ∗ g )
2 {
3
i f ( ! g−>r u n )
4
g_timeout_add (VEL_MS, t i m e r _ c b , g ) ; // Co nec t am os l a
nuevo
5
g−>r u n = ! g−>r u n ;
6 }
1 s t a t i c gboolean timer_cb ( g p o i n t e r g u i )
2 {
3
s t r u c t g u i ∗g = ( s t r u c t g u i ∗) g u i ;
4
s t e p _ c b ( NULL , g ) ;
5
/∗ S i d e v u e l v e f a l s e , l a s e n y a l s e d e s c o n e c t a y e l
vuelve
6
∗ a llamar
7
∗/
8
r e t u r n g−>r u n ;
9 }
s e n y a l de
c a l l b a c k no s e
Ejercicio
Portada
Sobre GTK
Bucle
principal
Señales
Callbacks
Glade y
builder
Ejemplo
simple
Juego de la
vida
main
gui object
drawing area
Timer
Ejercicio
1
Estudia detenidamente el código proporcionado
2
Crea el fichero “builder.ui” con Glade. Presta atención
al identificador de cada widget
3
Completa el código de “gui.c”. Las zonas a completar
están marcadas con un TODO
Descargar