Sie sind auf Seite 1von 29

Tema: III.

Programacion dirigida por eventos y ejecucion diferida


de codigo
Herramientas Avanzadas para el Desarrollo de Aplicaciones
Departamento de Lenguajes y Sistemas Inform
aticos
Universidad de Alicante

Curso 2012-2013 , Copyleft 2011-2013 .


Reproduccion permitida bajo los terminos de la licencia de
documentaci
on libre GNU.

1 / 29

Contenido
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

Preliminares
Programacion secuencial vs. dirigida por eventos I
Programacion secuencial vs. dirigida por eventos II
Esqueleto de una aplicaci
on dirigida por eventos I
Esqueleto de una aplicaci
on dirigida por eventos II
Diagrama de una aplicaci
on dirigida por eventos
Y todo esto en Vala...
Ejemplo de se
nal en Vala I
Ejemplo de se
nal en Vala IIa
Ejemplo de se
nal en Vala IIb
Ejemplo de se
nal en Vala IIc
Ejercicio en clase. Preparaci
on para la ejecucion diferida de codigo (I)
Ejercicio en clase. Preparaci
on para la ejecucion diferida de codigo (II)
Ejecucion diferida de c
odigo. Preliminares (I)
Ejecucion diferida de c
odigo. Preliminares (II). Ejercicio en clase
Ejecucion diferida de c
odigo. Preliminares (III)
El principio de HollyWood (I)
El principio de HollyWood (II)
Y todo esto en Vala...
Se
nales en Vala. Lo basico
Se
nales y funciones Lambda ()
Desconexion de se
nales en Vala (I)
Desconexion de se
nales en Vala (II)
Se
nales con enlace dinamico en Vala (I)
Se
nales con enlace dinamico en Vala (II)
2 / 29

Preliminares

En t
erminos de la estructura y la ejecuci
on de una aplicacion

representa lo opuesto a lo que hemos hecho hasta ahora:


programacion secuencial.
La manera en la que escribimos el c
odigo y la forma en la que se

ejecuta este esta determinada por los sucesos (eventos) que ocurren
como consecuencia de la interacci
on con el mundo exterior.
Podemos afirmar que representa un nuevo paradigma de

programacion, en el que todo gira alrededor de los eventos1 .

Cambios significativos en el estado de un programa.


3 / 29

Programacion secuencial vs. dirigida por eventos I


En la programaci
on secuencial le decimos al usuario lo que puede

hacer a continuacion, desde el principio al final del programa.


El tipo de c
odigo que escribimos es como este:
1
3
5
7

repetir
presentar menu () ;
opc = l e e r o p c i o n ( ) ;
...
s i ( opc == 1 ) e n t o n c e s a c c i o n 1 ( ) ;
s i ( opc == 2 ) e n t o n c e s a c c i o n 2 ( ) ;
...
hasta terminar

En la programaci
on dirigida por eventos indicamos:
Qu
e cosas -eventos- pueden ocurrir?
Lo que hay que hacer cuando ocurran
2
4
6
8

s o n e v e n t o s ( ev1 , ev2 , e v 3 . . . ) ;
...
c u a n d o o c u r r a ( ev1 , a c c i o n 1 ) ;
c u a n d o o c u r r a ( ev2 , a c c i o n 2 ) ;
...
repetir
...
hasta terminar
4 / 29

Programacion secuencial vs. dirigida por eventos II

A partir de este punto los eventos pueden ocurrir en cualquier

momento y marcan la ejecuci


on del programa.
Aunque no lo parezca plantean un problema serio: el flujo de la

ejecucion del programa escapa al programador.


El usuario (como fuente generadora de eventos) toma el control sobre

la aplicacion.
Esto implica tener que llevar cuidado con el dise
no de la aplicacion

teniendo en cuenta que el orden de ejecuci


on del codigo no lo marca
el programador y, ademas, puede ser distinto cada vez.

5 / 29

Esqueleto de una aplicacion dirigida por eventos I

Al principio de la misma llevamos a cabo una iniciaci


on de todo el

sistema de eventos.
Se definen todos los eventos que pueden ocurrir.
Se prepara el generador o generadores de estos eventos.
Se indica qu
e codigo se ejecutara en respuesta a un evento producido

-ejecucion diferida de c
odigo-.
Se espera a que se vayan produciendo los eventos.

6 / 29

Esqueleto de una aplicacion dirigida por eventos II

Una vez producidos son detectados por el dispatcher o planificador

de eventos, el cual se encarga de invocar el c


odigo que previamente
hemos dicho que deba ejecutarse.
Todo esto se realiza de forma ininterrumpida hasta que finaliza la

aplicacion.
A esta ejecuci
on ininterrumpida es a lo que se conoce como el bucle

de espera de eventos.
Las aplicaciones con un interfaz gr
afico de usuario siguen este

esquema de programaci
on que acabamos de comentar.
Podemos verlo de forma gr
afica en el siguiente diagrama:

7 / 29

Diagrama de una aplicacion dirigida por eventos

Generador de Eventos
* La cola de
eventos no es
estrictamente
necesaria.

Cola de Eventos
Dispatcher

Manejador1

Manejador2

Manejador3

Manejadorn

Figura: Diagrama de una aplicaci


on dirigida por eventos.

8 / 29

Y todo esto en Vala...

Los eventos en Vala se denominan se


nales.
Son equivalentes a los eventos en C# o a los listeners en Java.
Las se
nales son un mecanismo proporcionado por la clase GLib.Object.
Si queremos que una clase nuestra pueda emitir se
nales -emitir

eventos-, debe derivar directa o indirectamente de GLib.Object.


Una se
nal se define como un miembro de una clase y se parece a un

metodo sin cuerpo.


S
olo vemos su signatura y nombre precedidos por la palabra reservada

signal y el modificador de acceso.


A una se
nal le conectamos tantos metodos o funciones como

queramos que se ejecuten cuando se emita esa se


nal.

9 / 29

Ejemplo de senal en Vala I

2
4

void f1 ( int n) { . . . }
void f2 ( int n) { . . . }
p u b l i c c l a s s T e s t : GLib . O b j e c t {
p u b l i c s i g n a l v o i d s i g 1 ( i n t a ) ; // <=== SIGNAL

6
p u b l i c s t a t i c i n t main ( s t r i n g [ ]
T e s t t 1 = new T e s t ( ) ;

8
10

args ) {

t1 . s i g 1 . connect ( f1 ) ;
t1 . s i g 1 . connect ( f2 ) ;
...
// C o n e x i o n de l a s e n y a l
// con e l c o d i g o a e j e c u t a r
// Lo v e r e m o s en e l p r o x i m o
// tema .

12
14
16

t1 . s i g 1 (2) ;
18
20

// E m i s i o n de l a s e n y a l
// E q u i v a l e a l l a m a r a : f 1 ( 2 ) ; f 2 ( 2 )

return 0;
}

22

10 / 29

Ejemplo de senal en Vala IIa

2
4
6

c l a s s P l a y e r : GLib . O b j e c t {
p u b l i c P l a y e r . with name ( s t r i n g n ) {
name = n ;
t r i e s = 0;
new try . connect ( r e c o r d t r y ) ;
}

public s i g n a l void new try () ;


public int g e t t r i e s () { return t r i e s ; }
p u b l i c v o i d m a k e t r y ( ) { t r i e s ++; n e w t r y ( ) ; }
private void r e c o r d t r y () {
s t d o u t . p r i n t f ( " the player < %s > tried one more time \ n " ,
name ) ;
}
p u b l i c s t r i n g g e t n a m e ( ) { r e t u r n name ; }
// Datos
public int t r i e s ;
p r i v a t e s t r i n g name = " " ;

10
12
14
16
18
20

22

void p l a y e r t r y ( Player p) {
s t d o u t . p r i n t f ( " The player [ %s ] tried one more time \ n " ,
p . get name ( ) ) ;
}

24

11 / 29

Ejemplo de senal en Vala IIb

1
3

v o i d main ( ) {
const i n t max tries = 2;
v a r j u a n = new P l a y e r . w i t h n a m e ( " Juan " ) ;
v a r p e d r o = new P l a y e r . w i t h n a m e ( " Pedro " ) ;

5
juan . new try . connect ( p l a y e r t r y ) ;
pedro . new try . connect ( p l a y e r t r y ) ;

7
9

for ( int i = 0; i < max tries ;


juan . make try () ;
pedro . make try () ;
}

11
13

i ++) {

12 / 29

Ejemplo de senal en Vala IIc

the
The
the
The
the
The
the
The

player
player
player
player
player
player
player
player

<Juan> tried one more time


[Juan] tried one more time
<Pedro> tried one more time
[Pedro] tried one more time
<Juan> tried one more time
[Juan] tried one more time
<Pedro> tried one more time
[Pedro] tried one more time

13 / 29

Ejercicio en clase. Preparacion para la ejecucion diferida de


codigo (I)

La ejecuci
on diferida de c
odigo tiene sus orgenes en el concepto de
Callback

En Lenguaje C un Callback no es m
as que un puntero a una funcion.
Vamos a comenzar a preparar en clase un ejercicio que haremos en las

practicas relacionadas con la ejecuci


on diferida de codigo.

14 / 29

Ejercicio en clase. Preparacion para la ejecucion diferidad


de codigo (II)

En la biblioteca est
andar de C (#include <stdlib.h>) disponemos

de la funcion qsort - ordena un vector. El prototipo de la


misma es:
1

v o i d q s o r t ( v o i d base , s i z e t nmemb , s i z e t s i z e ,
i n t ( compar ) ( c o n s t v o i d , c o n s t v o i d ) ) ;

Identifica cada uno de sus par


ametros. Trata de entender que es

compar. Propon un posible valor para ese parametro.


Cuando tengas hecho todo este estudio trata de crear un programa

ejecutable mnimo que te sirva para comprobar c


omo funciona
qsort.

15 / 29

Ejecucion diferida de codigo. Preliminares (I)


La constituyen los llamados Callbacks en C, son elementos de bajo

nivel, ya los conocemos2 . . .


2

i n t i n t c m p ( c o n s t v o i d pe1 , c o n s t v o i d pe2 ) {
i n t e1 = ( ( c o n s t i n t ) pe1 ) ;
i n t e2 = ( ( c o n s t i n t ) pe2 ) ;

4
r e t u r n e1e2 ;
6

i n t main ( ) {
i n t v [ 4 ] = {4 ,0 , 1 ,7};

10
f o r ( i n t i = 0 ; i < 4 ; i ++)
p r i n t f ( " v[ %d]= %d \ n " , i , v [ i ] ) ;

12
14

qsort (v , 4 , s i z e o f ( i n t ) , int cmp ) ;


p r i n t f ( "\n" ) ;
\v/
\
Ejecucion
f o r ( i n t i = 0 ; i < 4 ; i ++)
p r i n t f ( " v[ %d]= %d \ n " , i , v [ i ] ) ;
return 0;

16
18
20

diferida

Punteros a funciones.
16 / 29

Ejecucion diferida de codigo. Preliminares (II). Ejercicio en


clase

Tambi
en sabemos que Vala nos permite hacerlo mejor que C:

signal + connect.
Pero tambi
en sabemos que es compatible con bibliotecas de C. . .
Echa un vistazo a la biblioteca de compatibilidad con Posix de C:

vala posix , busca en ella la referencia a la funci


on qsort .
Fijate en la declaraci
on del tipo compar fn t.
Ejercicio: Trabajando en grupos como en el ejercicio anterior,

reescribe ese ejemplo hecho en C ahora con Vala y usando la capa de


compatibilidad Posix. 15min.

17 / 29

Ejecucion diferida de codigo. Preliminares (III)


Otros lenguajes de programaci
on sin llegar a tener un soporte

sintactico para esto ofrecen alternativas de mas alto nivel.


Vamos a ver el caso de tres implementaciones distintas para el caso

de C++:
libsigc++
signal/slot
boost::signals

: Empleada por la biblioteca gtkmm .


: Empleada por la biblioteca Qt .
: Implementaci
on parecida a libsigc++ pero candidata a
convertirse en el soporte estandar de ejecucion de codigo
diferido en C++ por su pertenencia al proyecto boost .

En la documentaci
on de cada una de estas tres implementaciones de

ejecucion de codigo diferido tenemos ejemplos sencillos, vamos a ver


un ejemplo de cada uno de ellos. 10min. cada uno

18 / 29

El principio de HollyWood (I)

Es muy sencillo: No nos llame...ya le llamaremos.


Se emplea sobre todo cuando se trabaja con frameworks.
El flujo de trabajo se parece a esto:
1 En el caso de trabajar con un framework3 implementamos un interfaz
y en el caso mas sencillo escribimos el c
odigo a ejecutar mas adelante.
2 Nos registramos. . . es decir, indicamos de alg
un modo cual es el codigo
a ejecutar posteriormente.
3 Esperamos a que se llame -al c
odigo registrado previamente- cuando le
toque: No nos llame. . . ya le llamaremos.
El programador ya no dicta el flujo de control de la aplicaci
on, sino

que son los eventos producidos los que lo hacen.

Se estudian en la asignatura Programaci


on-3.
19 / 29

El principio de HollyWood (II)

Puedes consultar m
as informaci
on sobre el aqu .
Si quieres ampliar m
as tus conocimientos sobre el debes saber que a

este principio tambien se le conoce por otros nombres:


1
2

Inversi
on de control ( IoC ).
Inyecci
on de dependencias (

DI

).

Puedes ampliar m
as informaci
on sobre estas tecnicas de programacion

en asignaturas como Programaci


on-3.

20 / 29

Y todo esto en Vala...

Conocemos lo esencial ya del principo de este tema: se~


nales y

conexiones con las mismas:


p u b l i c c l a s s T e s t : GLib . O b j e c t {
2
public s i g n a l void s i g 1 ( int a) ;
p u b l i c v o i d m ( i n t a ) { s t d o u t . p r i n t f ( " %d \ n " , a ) ; }

4
6

p u b l i c s t a t i c i n t main ( s t r i n g [ ]
T e s t t 1 = new T e s t ( ) ;

args ) {

8
t 1 . s i g 1 . c o n n e c t ( t 1 .m) ;
10
t1 . s i g 1 (5) ;
12
return 0;
}

14
}

21 / 29

Senales en Vala. Lo basico (I)

Recuerda que para que una clase pueda emitir se


nales debe derivar

directa o indirectamente de la clase GLib.Object.


Una se
nal puede tener ninguno, uno o mas parametros.
La signatura de la funci
on que conectamos a una se
nal debe coincidir

con la de la propia se
nal...
...salvo que en Vala se permite: Importante!
1
2

que omitamos tantos parametros desde el final como queramos...


o que proporcionemos el originador de la se
nal como primer
parametro del callback.

22 / 29

Senales en Vala. Lo basico (II)


Por ejemplo, para la se
nal Foo.some event seran se
nales validas

todas estas:
1
3
5
7
9

p u b l i c c l a s s Foo : O b j e c t {
p u b l i c s i g n a l void some event ( i n t x , i n t y , double z ) ;
// . . .
}
. . . // l a s s i g u i e n t e s f u n c i o n e s pueden c o n e c t a r s e a s o m e e v e n t
void on some event ()
void on some event ( i n t x )
void on some event ( i n t x , i n t y )
void on some event ( i n t x , i n t y , double z )
v o i d o n s o m e e v e n t ( Foo s o u r c e , i n t x , i n t y , d o u b l e z )

Los nombres de los par


ametros son libres.
Especificar el origen de la se
nal (source) nos puede servir para

diferenciar si conectamos la misma funcion a la misma se


nal para
diferentes instancias del mismo tipo.

23 / 29

Senales y funciones Lambda ()


A una se
nal podemos conectarle una funci
on definida en lnea, una

funcion lambda (funci


on-).
Tambi
en se las llama funciones an
onimas ya que no tienen nombre.
El primer ejemplo que hemos visto en la p
agina 21 podra reescribirse

as usando funciones-:
2
4

p u b l i c c l a s s T e s t : GLib . O b j e c t {
public s i g n a l void s i g 1 ( int a) ;
p u b l i c s t a t i c i n t main ( s t r i n g [ ] a r g s ) {
T e s t t 1 = new T e s t ( ) ;
t 1 . s i g 1 . c o n n e c t ( ( t , a ) => { s t d o u t . p r i n t f ( " %d \ n " , a ) ; } ) ;
t1 . s i g 1 (5) ;

6
8

return 0;
}

10
}

Pregunta: Qu
e son t y a ? Que representa cada uno?

24 / 29

Desconexion de senales en Vala (I)

Es posible que a partir de un momento no nos interese que un

determinado callback se invoque cuando se emita la se


nal a la que
estaba conectado.
Para conseguirlo debemos desconectarlo de la se
nal. Es el proceso

inverso a la conexion.
Podemos hacerlo de varias maneras, el caso m
as sencillo es usar el

metodo disconnect, el cual usa esta notaci


on:
1

foo . some event . connect ( on some event ) ;


// C o n e x i o n . . .
f o o . s o m e e v e n t . d i s c o n n e c t ( o n s o m e e v e n t ) ; // D e s c o n e x i o n

Pero qu
e ocurre si lo que habamos conectado era una

funcion-?..recuerda que no tienen nombre. . .

25 / 29

Desconexion de senales en Vala (II)

El truco est
a en saber que el metodo connect devuelve un valor de

tipo entero largo sin signo: ulong.


Por tanto, cuando conectamos una funci
on- que pensemos

desconectar, debemos guardar el valor que devuelve la conexion, por


ejemplo:
2

u l o n g s i g i d = f o o . s o m e e v e n t . c o n n e c t ( ( ) => { / . . . / }) ;
foo . some event . disconnect ( s i g i d ) ;

26 / 29

Senales con enlace dinamico en Vala (I)


Una se
nal puede ser redefinida en una clase derivada. . . como un

metodo normal y corriente. . .


Para ello debe tener enlace din
amico, o lo que es lo mismo, ser

declara virtual.
Cuando una se
nal se declara virtual puede tener una

implementacion de un callback por defecto, ademas de que esta


implementacion puede ser redefinida en clases derivadas, as:
2
4

c l a s s Demo : O b j e c t {
public v i r t u a l s i g n a l void s i g () {
s t d o u t . p r i n t f ( " callback por defecto \ n " ) ;
}
}

6
8
10

c l a s s Sub : Demo {
public override void s i g () {
s t d o u t . p r i n t f ( " Reemplazo del callback por defecto \ n " ) ;
}
}

27 / 29

Senales con enlace dinamico en Vala (II)


A una se
nal con un callback por defecto se le pueden conectar mas

callbacks?..s.
IMPORTANTE : Se ejecutan antes que el callback por defecto.
Existe la posibilidad de conectar callbacks que se ejecutan despu
es

del callback por defecto, eso se hace con el metodo


connect after:
1
3
5

v o i d main ( ) {
v a r demo = new Demo ( ) ;
demo . s i g . c o n n e c t ( ( ) => s t d o u t . p r i n t f ( " antes \ n " ) ) ;
demo . s i g . c o n n e c t a f t e r ( ( ) => s t d o u t . p r i n t f ( " despues \ n " ) ) ;
demo . s i g ( ) ; // e m i t i m o s l a s e n y a l
}

7
9
11

//
//
//
//

Resultado :
antes
c a l l b a c k por d e f e c t o
despues

28 / 29

Ejercicio: La vivienda domotica


Trabajando en grupos vamos a escribir el c
odigo para una aplicacion que
simule -a modo de ejemplo- una vivienda dom
otica. Esta vivienda o casa
consta de:
Varias habitaciones, cada una de las cuales dispone de. . .
Persianas, pueden estar subidas o bajadas. Estamos interesados en
saber cuando se suben.
Puertas, pueden estar abiertas o cerradas. Estamos interesados en
saber cuando se abren.
Luces, pueden estar encendidas o apagadas. Estamos interesados en
saber cuando se encienden.
Crea las clases/interfaces que consideres necesarios y un sencillo

programa de prueba que cree una casa, con varias habitaciones y cada
una de ellas con varias puertas/ventanas/luces.
Comprueba que, efectivamente, cuando alguien abre una puerta,

enciende una luz o sube una persiana, el sistema domotico nos avisa
de ello.
29 / 29

Das könnte Ihnen auch gefallen