miércoles, 22 de agosto de 2012

Listas complejas

Si lo que queremos es crear listas mas complejas conteniendo datos de diferentes tipos yo recomiendo crear un objeto y después crear una lista de este objeto.

// complila con valac  nombre.gs  --pkg gee-1.0

[indent=4]
uses Gee
//creamos la clase casa

class casa: Object
    Portal: int
    Piso:int
    Puerta:string
    Calle:string


casa0:casa
init
    var lista_de_casas = new list of casa
 

    //Instanciamos el objeto casa
    casa0= new casa()
    //Introducimos datos
    casa0.Portal=4
    casa0.Piso=3
    casa0.Puerta="A"
    casa0.Calle ="Calle Mayor"
    //Introducimos en la lista
    lista_de_casas.add(casa0)
   
    // Si queremos obtener un nuevo item en la lista deberemos reinstanciar
    // el objeto casa y lo podemos hacer con el mismo nombre
    casa0= new casa()
    casa0.Portal=6
    casa0.Piso=7
    casa0.Puerta="B"
    casa0.Calle ="Calle Menor"
    lista_de_casas.add(casa0)
   
    for var e in lista_de_casas
        print e.Calle+" "+e.Portal.to_string()+ "-"+ e.Piso.to_string()+ " "+e.Puerta+ " "
    // este for tiene un warning consigo fallo de la librería gee
   



En este tipo de listas podríamos introducir tipos de variables creados por nosotros desde otros objetos o usar otros que ya están creados como los de las librerías SDL. Por ejemplo : Rect y Surface. Es decir, podemos anidar objetos dentro de otros y todos meterlos en una lista. En el siguiente ejemplo Introduciremos un objeto dentro de otro objeto, es decir el objeto persona lo introduciremos dentro del objeto casa. Pero claro esta que los objetos necesitan instanciarse para ser usados y si el objeto casa quiere usar el objeto persona este debe de haber sido correctamente instanciado. Lo haré mediante el constructor de casa. Aún así lo podría haber hecho a través de init. ¿Para que sirve el constructor? Es el que recoge las variables de construccion del objeto cuando lo instanciamos con new. En este caso no tiene ninguna. init al igual que construct se ejecutan cuando instanciamos el objeto con new. Sin embargo se dispara antes que construct. Pero bueno, dejemos esto de la construccion de objetos para otro capítulo.

[indent=4]
uses Gee
class persona: Object
    Nombre:string
    Apellidos:string
    
class casa: Object
    Portal: int
    Piso:int
    Puerta:string
    Calle:string
    Persona:persona
    construct () // también se podría haber puesto init aquí.
        Persona= new persona()
casa0:casa
e:Collection
init
    var lista_de_casas = new list of casa
    //Instanciamos el objeto casa
    casa0= new casa()
    //Introducimos datos
    casa0.Portal=4
    casa0.Piso=3
    casa0.Puerta="A"
    casa0.Calle ="Calle Mayor"
    casa0.Persona.Nombre="Gorka"
    casa0.Persona.Apellidos="Santos Garmendia"
    
    //Introducimos en la lista
    lista_de_casas.add(casa0)
    
    // Si queremos obtener un nuevo item en la lista deberemos reinstanciar
    // el objeto casa y lo podemos hacer con el mismo nombre
    casa0= new casa()
    casa0.Portal=6
    casa0.Piso=7
    casa0.Puerta="B"
    casa0.Calle ="Calle Menor"
    casa0.Persona.Nombre="Gaizka"
    casa0.Persona.Apellidos="Sanchez Soler"
    lista_de_casas.add(casa0)
    
    for e in lista_de_casas
        print e.Persona.Nombre + " " +e.Persona.Apellidos
        print e.Calle+ " "+ e.Portal.to_string()+ "-"+ e.Piso.to_string()+ " "+ e.Puerta+ " \n"
        
    // este for tiene un warnin consigo fallo de la librería gee
    



Si lo necesitamos también podemos incluir listas dentro de los objetos. Imaginemos que dentro del objeto persona introducimos una lista de los nombres de los hijos, el resultado sería el siguiente. No olvideís que las listas dentro de las clases también tienen que ser inicializadas.


uses Gee

class persona: Object
    Nombre:string
    Apellidos:string
    Hijos:new list of string
    init
        Hijos= new list of string //inicializamos la lista de hijos así.
   
class casa: Object
    Portal: int
    Piso:int
    Puerta:string
    Calle:string
    Persona:persona
    init
        Persona= new persona()
casa0:casa
e:Collection
init
    var lista_de_casas = new list of casa
    //Instanciamos el objeto casa
    casa0= new casa
    //Introducimos datos
    casa0.Portal=4
    casa0.Piso=3
    casa0.Puerta="A"
    casa0.Calle ="Calle Mayor"
    casa0.Persona.Nombre="Gorka"
    casa0.Persona.Apellidos="Santos Garmendia"
    casa0.Persona.Hijos.add("Felipe") // introducimos los hijos dentro de la sublista
    casa0.Persona.Hijos.add("Rosa")
    casa0.Persona.Hijos.add("Marta")

   
    //Introducimos en la lista
    lista_de_casas.add(casa0)
   
    // Si queremos obtener un nuevo item en la lista deberemos reinstanciar
    // el objeto casa y lo podemos hacer con el mismo nombre
    casa0= new casa()
    casa0.Portal=6
    casa0.Piso=7
    casa0.Puerta="B"
    casa0.Calle ="Calle Menor"
    casa0.Persona.Nombre="Gaizka"
    casa0.Persona.Apellidos="Sanchez Soler"
    casa0.Persona.Hijos.add("Leire")
    casa0.Persona.Hijos.add("Agurtzane")
    lista_de_casas.add(casa0)
   
    for e in lista_de_casas
        print e.Persona.Nombre + " " +e.Persona.Apellidos
        for hijo in e.Persona.Hijos // imprimimos la lista de hijos
            print "Hijo:"+hijo
          
        print e.Calle+ " "+ e.Portal.to_string()+ "-"+ e.Piso.to_string()+ " "+ e.Puerta+ " \n"
      
    // este for tiene un warnin consigo fallo de la librería gee

domingo, 5 de agosto de 2012

Conversión de variables

De INT o DOUBLE  a   STRING
[indent=4]
a: int
init
    a=1
    print " numero: " + a.to_string() //imprimira la cadena 1

De  STRING a INT
[indent=4]
c : string
init
    c="123"
    print "%i", int.parse(c)

De  STRING a DOUBLE

[indent=4]
c : string
init
    c="123.3"
    print "%f", double.parse(c)

De DOUBLE a INT
numero : double
init 
    numero = 2584833
    print "%i", (int)numero
 

De DOUBLE a INT
numero : int
init 
    numero = 2584
    print "%f", (double)numero


miércoles, 25 de julio de 2012

Gtk_Timeout - Pon un timer en tu vida.


 En esta ejemplo hemos añadido al ejemplo de TextView una función que es llamada por el Timer de Gtk. Con ello hemos conseguido crear un texto animado. Cuando pulsamos el boton activamos el Timer.
 Timeout.add(50, mover) --> Llama a mover con velocidad de 50 ticks

  Atención puesto que "mover" tiene que ser una funcion de tipo booleano y retornar true para continuar en funcionamiento.

Nota: Booleano es de tipo lógico y sus valores posibles son true o false

Muy sencillo:


[indent=4]
uses
    Gtk
init

    Gtk.init (ref args)
    var test = new Miventana ()
    test.show_all ()
  
    Gtk.main ()
  
  
class Miventana : Window
    texto1: Gtk.TextView = new TextView
  
    rojo: Gtk.TextTag
    blanco: Gtk.TextTag
    ti1: Gtk.TextIter;     ti2: Gtk.TextIter;    ti3: Gtk.TextIter;    ti4: Gtk.TextIter
  
    acolor : Gdk.Color
  
    boton1: Button= new Button.with_label ("Pulsa este botón")
    contador: int = 0
    frase:string ="La casa esta rota, pero ya la estamos arreglando. La casa esta rota, pero ya la estamos arreglando."
    vbox : VBox = new VBox (true, 5)
      
    init
        Gdk.Color.parse("#1F2AF1", out acolor)
        rojo=texto1.buffer.create_tag("rojo", "foreground-gdk", acolor);
        blanco=texto1.buffer.create_tag("blanco", "foreground", "White");
      
        texto1.editable = false
        texto1.cursor_visible = false
        title = "Ventana de prueba"
        default_height = 360
        default_width = 560
        window_position = WindowPosition.CENTER
        boton1.clicked.connect (pulsado)
      
        destroy.connect(Gtk.main_quit)
        vbox.add (boton1)
        vbox.add(texto1)
        add (vbox)
        texto1.set_size_request(100, 200)
        boton1.set_size_request(100,10)
        texto1.buffer.text = frase
        texto1.buffer.get_iter_at_mark (out ti1, texto1.buffer.get_insert ())
        texto1.buffer.get_iter_at_mark (out ti2, texto1.buffer.get_insert ())
        texto1.buffer.get_iter_at_mark (out ti3, texto1.buffer.get_insert ())
        texto1.buffer.get_iter_at_mark (out ti4, texto1.buffer.get_insert ())
  
        Timeout.add(50, mover)
      
    def pulsado (btn : Button)
        contador=0
      
    def mover():bool
        contador+=1
      
        ti1.set_offset(0)
        ti2.set_offset(contador)
        ti3.set_offset(contador+5)
        ti4.set_offset(longitud(frase))
      
        texto1.buffer.remove_all_tags (ti1,ti4)
        texto1.buffer.apply_tag (blanco,ti1,ti2)
        texto1.buffer.apply_tag (rojo,ti2,ti3)
        texto1.buffer.apply_tag (blanco,ti3,ti4)
        return true



Gtk + Textview y variables de clase

En este ejemplo también vamos a ver como podemos inicializar ciertas variables de una clase y las podrémos usar por toda la clase. Ejemplo: texto1, rojo, blanco,contador. Estas variables las declararemos antes del init de la clase.

Como vemos mucho del texto no es sintaxis propia de vala sino la de GTK+. Por lo tanto para alguien experimentado en Python Gtk (pygtk) o quien haya programado en este interface antes en uno u otro idioma la dinámica es parecida.

Este ejemplo es un pequeño programa en el cual cuando pulsamos el botón el texto se va descubriendo hacia la derecha.   Lo conseguimos usando un contador de posición y creando "tags" que son estilos de texto:(subrayado, negrita,fuente, color...)
e insertando esos estilos en ciertos "Iters" que son por así decirlo punteros para el texto del buffer.


[indent=4]
uses
    Gtk
init

    Gtk.init (ref args)
    var test = new TestWindow ()
    test.show_all ()
    Gtk.main ();
   
   
class TestWindow : Window
    texto1: Gtk.TextView = new TextView
   
    rojo: Gtk.TextTag
    blanco: Gtk.TextTag
    ti1: Gtk.TextIter
    ti2: Gtk.TextIter
    ti3: Gtk.TextIter
    ti4: Gtk.TextIter
       
    acolor : Gdk.Color
    cont:int=0
    boton1: Button= new Button.with_label ("Pulsa este botón")
    contador: int = 0
    palabras: new array of string
    frase:string ="La casa esta rota, pero ya la estamos arreglando"
    vbox : VBox = new VBox (true, 5)
       
    init
        Gdk.Color.parse("#1F2AF1", out acolor)
        rojo=texto1.buffer.create_tag("rojo", "foreground-gdk", acolor);
        blanco=texto1.buffer.create_tag("blanco", "foreground", "White");
       
        texto1.editable = false
        texto1.cursor_visible = false
        palabras= frase.split(" ")
        title = "Ventana de prueba"
        default_height = 360
        default_width = 560
        window_position = WindowPosition.CENTER
        boton1.clicked.connect (pulsado)
       
        destroy.connect(Gtk.main_quit)
        vbox.add (boton1)
        vbox.add(texto1)
        add (vbox)
        texto1.set_size_request(100, 200)
        texto1.buffer.text = frase
        texto1.buffer.get_iter_at_mark (out ti1, texto1.buffer.get_insert ())
        texto1.buffer.get_iter_at_mark (out ti2, texto1.buffer.get_insert ())
        texto1.buffer.get_iter_at_mark (out ti3, texto1.buffer.get_insert ())
        texto1.buffer.get_iter_at_mark (out ti4, texto1.buffer.get_insert ())
       
    def pulsado (btn : Button)
               
        contador++
        ti1.set_offset(0)
        ti2.set_offset(contador)
        ti3.set_offset(contador+5)
        ti4.set_offset(longitud(frase))
       
        texto1.buffer.remove_all_tags (ti1,ti4)
        texto1.buffer.apply_tag (blanco,ti1,ti2)
        texto1.buffer.apply_tag (rojo,ti2,ti3)
        texto1.buffer.apply_tag (blanco,ti3,ti4)


lunes, 23 de julio de 2012

Archivos

Para abrir archivos tenemos una serie de métodos como estos: http://references.valadoc.org/#!api=glib-2.0/GLib.FileStream . En este caso
hemos creado una variable f que será el archivo en modo lectura. Los datos se meterán en "a" a través del método f.gets(a) y nosotros los pasamos a una cadena creada con StringBuilder (Constructor de cadenas) en la variable bu y lo metemos una lista de Gee(atención al compilar usar --pkg gee-1.0 ).

Para aprender el funcionamiento de Stringbuilder. Por ejemplo para crear una cadena a partir de variables tipo caracter. http://references.valadoc.org/#!api=glib-2.0/GLib.StringBuilder


[indent=4] uses Gee init var f = FileStream.open("/home/gontzal/for","r") var a = new array of char[1000] var bu = new StringBuilder () var lista =new list of string while f.gets(a)!= null for s in a do bu.append_c(s) lista.add (bu.str) bu.erase() for h in lista stdout.printf(h)

Importar librerias propias

Cuando nuestro código es muy grande o cuando creamos unas pequeñas librerías para crear un código más limpio llevamos estas funciones o clases a otro fichero. Lo aplicaremos al ejemplo de las cadenas unicode que se ha expuesto en  el capítulo 4.

En el archivo "cadenas.gs" escribiremos las siguientes funciones:
 
[indent=4]

def toma_cadena (a:string,i :int,f:int=-1):string
    b: string
   
    var bu = new StringBuilder ();
    if f==-1
        bu.append_unichar(a.get_char(a.index_of_nth_char(i)))
        b=bu.str
    else
        for var p =i to f
            bu.append_unichar(a.get_char(a.index_of_nth_char(p)))
        b=bu.str
   
    return b


def longitud (a:string):int
    return a.char_count()
 
En el archivo "principal.gs" escribiremos el siguiente código:

[indent=4] a: string init a="áéíóú" stdout.printf ("%i",longitud (a) ) print ("\n") stdout.printf( "%s\n",toma_cadena(a,0,1))


Y para compilar haremos lo siguiente en Geany:
valac -o "%e" cadenas.gs "%f" 
o lo que es lo mismo:
valac -o principal cadenas.gs principal.gs


Esto creará un archivo ejecutable que se llamará principal y usará como fuentes ambos archivos. Por lo tanto no dará error al compilar puesto que las funciones que le faltan en el archivo principal.gs las encontrará en cadenas.gs


domingo, 22 de julio de 2012

Cadenas

Si deseamos trabajar con cadenas, nuestro acometido será muy similar al de python. Por ejemplo, si queremos unir dos cadenas simplemente usaremos el símbolo "+". Si lo que deseamos es obtener una subcadena usaremos los corchetes []. En el interior de los corchetes la sintaxis es la siguiente [inicio:fin]. Por lo tanto si queremos crear una subcadena con los dos primeros caracteres haremos lo siguiente [0:2]

[indent=4]
a: string
b: string 
c: string
init
    a="hola."
    b=",mundo"
    a= a[0:4]     //transformaremos a en hola sin punto
    c= a+b
    print c


Ojo!! Si lo que deseamos es sacar un solo caracter con formato tipo "char" usaremos esto : cadena[posición]. Lo cual no podremos imprimir con un simple print puesto que solo sirve para cadenas.
Ahora bien tendrémos que especificar que es un Char de este modo "%c",a[0]

Ejemplo:

[indent=4]
a: string
init
    a="hola"
    print a[0:1]    //Sacamos la "h" en forma string
    print "%c",a[0] //especificamos que "h" será un char

    print a[0:a.length] //Escribe todo hasta la longitud total
    print a[0:a.index_of("o",0)+1]  // imprime hasta la o
    print print a.replace("h","m") // escribe "mola" en vez de "hola"


Pero como en Python también tenemos la opción de separar una cadena dados ciertos separadores o unirla.

Ejemplo:

[indent=4]
a: string
f : new array of string
init
    a="hola que tal estas"
    f=a.split(" ")
    for i in f
        print i  // se imprimirá cada palabra por separado
   
 
//Después se pueden unir usando joinv, las uniremos con ":"

    m= m.joinv(":",f)
    print m



Glib aporta una serie de métodos para tratar las cadenas como UTF8. Ejemplo:

[indent=4]
a: string
f : new array of string
init
    a="á"
    print a

    print a.length // El valor es 2 puesto que cuenta los valores crudos.
    print a.char_count() // Este método se usa para Unicode. el resultado es 1.


Mayormente usaremos char_count para así poder usar unicode sin problemas.
Python sigue siendo bastante más sencillo para usar unicode. En este ejemplo tomaré una cadena unicode y la imprimiré de unicode en unicode.
Estas son las nuevas funciones que he usado: 
a.get_char(int) Toma un unichar de la cadena en la posición cruda int
a.index_of_nth_char(int) Indexa la posición Unicode de int, no usa la cruda.
a.char_count() Cuenta los caracteres unicode de la cadena.
He empleado también StringBuilder http://references.valadoc.org/#!api=glib-2.0/GLib.StringBuilder que nos puede servir para conformar cadenas a través de variables de tipo caracter o unicode-caracter





a: string
i: int

def toma_cadena (a:string,i :int ):string
    b: string
    var bu = new StringBuilder ();
    bu.append_unichar(a.get_char(a.index_of_nth_char(i)))
    b=bu.str
    return b
def longitud (a:string):int
    return a.char_count()

init
    a="1h2á3o4ó5ú"
    print "%i",longitud (a) 
   
    for i =0 to (longitud(a))
        stdout.printf( "%s\n",toma_cadena(a,i))
    


¿Que quiero decir con posición cruda y unicode?

Tenemos que entender que el unicode es una forma de notar todos los caracteres que están fuera de ASCII. Es decir los caracteres con acentos, dieresis, etc.
Estos caracteres toman formas crudas como \x3 por ejemplo. Por lo tanto ocuparán diferente espacio; "a" ocupa un espacio pero "á" ocupa dos. Puesto que la notación unicode para la acentuada ocupa dos espacios. Tenemos que tener en cuenta que dentro de UTF-8,16 o 32 (unicode) hay caracteres rusos, chinos etc. Y Ascii solo tiene 256. Es por eso que para el español se necesita el unicode puesto que los ingeleses no incluyeron los acentos dentro de ascii.   Ahora bien cuando hablo de posición o longitud cruda de "á" hablo de 2 y cuando hablo de longitud unicode de "á" diré 1. Lógicamente yo siempre usaré unicode por la cuenta que me trae. Eso quiere decir que muchas de las ventajas de usar corchetes desaparecen puesto que usan las cadenas crudas y no unicode.
Por lo tanto para similar los corchetes [] yo crearía las siguientes funciones para facilitar mi código. Aunque se podría mejorar para incluir las funciones de resta -1 para coger todo menos el último carácter, etc. Pero aquí no me voy a liar.

[indent=4]
a: string
i: int

def toma_cadena (a:string,i :int,f:int=-1):string
    b: string
    
    var bu = new StringBuilder ();
    if f==-1
        bu.append_unichar(a.get_char(a.index_of_nth_char(i)))
        b=bu.str
    else
        if f>0
            var p=i
            while p<f
                bu.append_unichar(a.get_char(a.index_of_nth_char(p)))
                p++
            b=bu.str
        else
            b=""
    return b

def longitud (a:string):int
    return a.char_count()


init
    a="áéíóú"
    stdout.printf ("%i\n",longitud (a))
    stdout.printf( "%s\n",toma_cadena(a,2,4))