jueves, 29 de abril de 2010

Notas Python: GObject en Python

GObject, la clase base

GObject, una clase que implementa todo lo básico, y que forma la base de todas las demás clases, tanto en GTK+ como en el resto de librerías de la plataforma GNOME.

El lenguaje C no es un lenguaje preparado para POO, pero con un esfuerzo mínimo, y gracias al trabajo de los desarrolladores de GTK+, se puede usar en este lenguaje. Esto se consigue mediante el sistema de objetos de GLib (GObject), que, mediante el uso de las características del lenguaje C, ofrece la posibilidad de usar POO.

Este sistema de objetos de GLib tiene algunas limitaciones propias del uso del lenguaje C (lenguaje no pensado para la POO), pero aun así, su funcionalidad es tal, que es más que probable que jamás se eche ninguna funcionalidad en falta. Dicha funcionalidad incluye:



  • herencia, característica imprescindible de cualquier lenguaje orientado a objetos que se precie de serlo; permite la creación de clases que heredan la funcionalidad de otras clases ya existentes. Esto permite crear clases con la funcionalidad básica y, basadas en dicha clase, crear otras que añadan una funcionalidad más específica.
  • polimorfismo, que permite tratar a un mismo objeto bajo distintas personalidades.
  • interfaces, que permite la definición de interfaces (clases abstractas) y su posterior implementación en clases.


Python es un lenguaje orientado a objetos por lo que a primera vista se puede pensar que las librerías gobject no son necesarias pero, hay algunas características propias de gobject que son muy útiles cuando se está trabajando en GNOME. A continuación voy a poner las dos que para mi son mas importantes:


  • Señales, este mecanísmo permite conectar nuestro programa con su entorno. Es muy útil cuando se usa para comunicarse entre diferentes partes un mismo proyecto.
  • Notificaciones cuando se cambian las propiedades de la clase (properties). Permite “conectar” funciones (callback) que se ejecutan cuando una propiedad cambia.


Sub clases gobject en Python.

Vamos a ver el proceso de creación de una subclase de GObject en Python.

Crear propiedades nuevas.

Lo primero que se hace es crear una clase “Car” que hereda de “gobject.GObject”. A continuación se crea el diccionario __gproperties__. En este caso, este diccionario solamente tiene una propiedad “fuel”.
En la funnción __init__ de nuestra clase, se inicializa el gobject con “gobject.GObject.__init__(self)”, usa para registrar los métodos y señales que hayamos creado.
Después se crean los métodos “do_get_property” y “do_set_property” para leer y escribir en las “properties” respectivamente.
Por último, se llama a la función gobject.type_register, con nustra clase como parámetro para registrar la clase como “official GType”, es necesario para que funcion correctamente.

import pygtk
pygtk.require('2.0')
import gobject

class Car(gobject.GObject):
    __gproperties__ = {
        'fuel' : (gobject.TYPE_FLOAT, 'fuel of the car',
                  'amount of fuel that remains in the tank',
                  0, 60, 50, gobject.PARAM_READWRITE)# typ, nick name,\
   description, minimum value, maximum value,default value, flags
        }

    def __init__(self):
        gobject.GObject.__init__(self)
        self.fuel = 50

    def do_get_property(self, property):
        if property.name == 'fuel':
            return self.fuel
        else:
            raise AttributeError, 'unknown property %s' % property.name

    def do_set_property(self, property, value):
        if property.name == 'fuel':
            self.fuel = value
        else:
            raise AttributeError, 'unknown property %s' % property.name

gobject.type_register(Car)
código procedente de http://www.pygtk.org/articles/subclassing-gobject/sub-classing-gobject-in-python.htm



Uso de las propiedades.
Para tener usar los métodos de lectura y escritura que hemos creado anteriormente (“do_get_property” y “do_set_property”), se escriben “get_property” y “set_propertie” respectivamente. Ver el código de ejemplo.

>>> from car1 import Car
>>> aCar = Car()
>>> print "The car has %f of fuel at the beginning" % aCar.get_property('fuel')
The car has 50.000000 of fuel at the beginning
>>> aCar.set_property('fuel', 20)
>>> print "Now the car has %f of fuel" % aCar.get_property('fuel')
Now the car has 20.000000 of fuel
código procedente de http://www.pygtk.org/articles/subclassing-gobject/sub-classing-gobject-in-python.htm

A continiación se muestra como hacer que se cree una señal cuando se modifica una propiedad. En el primer ejemplo, la señal se genera cuando se modifica cualquier “property”.

import pygtk
pygtk.require('2.0')
import gobject

from car1 import Car

def myCallback(obj, property):
    if property.name == 'fuel':
        if obj.get_property('fuel') < 10:
            print 'we are running out of fuel!!'
            
def test():
    aCar = Car()
    aCar.connect('notify', myCallback)
    aCar.set_property('fuel', 5.0)

if __name__ == '__main__':
    test()

En cambio en el segundo ejemplo, sólo se genera la señal cuando se modifica la “property” fuel.

import pygtk
pygtk.require('2.0')
import gobject
from car1 import Car

def myCallback(obj, property):
    if obj.get_property('fuel') < 10: 
        print 'we are running out of fuel!!'

def test():
    aCar = Car()
    aCar.connect('notify::fuel', myCallback) 
    aCar.set_property('fuel', 5.0)

if __name__ == '__main__':
    test()
código procedente de http://www.pygtk.org/articles/subclassing-gobject/sub-classing-gobject-in-python.htm


Aviso


Si se usan nombres compuestos para las propiedades, cuado se definen en el diccionariop __gproperties__ se deben separar con el carácter '_' (background_color), pero en cambio, cuando se define y se usa el argumento de la clase, se debe hacer con el carácter '-' (self.background-color).


Creación de señales propias con gobject.


Al crear una clase heredada de gobject se pueden crear señales para que una vez que creamos objetos de esa clase, se puedan conectar a las señales que hemos creado.

A continuación voy a porner un ejemplo de la clase Car, creada antes, añadiendo una señal ('engine-started').

Es necesario crear un diccionario llamado __gsinals__, que contiene:
El nombre de la señal como clave y
los datos de configuración de la señal

Para emitir la señal, se usa el método emit. Los parámetros de dicho método, son el nombre de la señal y, en este caso, la propiedad que hemos creado (fuel).

El método do_engine_started, es opcional y se ejecuta cuando la señal se emite.

import pygtk
pygtk.require('2.0')
import gobject

class Car(gobject.GObject):
    __gproperties__ = {
        'fuel' : (gobject.TYPE_FLOAT, 'fuel of the car',
                  'amount of fuel that remains in the tank',
                  0, 60, 50, gobject.PARAM_READWRITE)
        }

    __gsignals__ = {
        'engine-started' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                            (gobject.TYPE_FLOAT,))
        }

    def __init__(self):
        gobject.GObject.__init__(self)
        self.fuel = 50

    def do_get_property(self, property):
        if property.name == 'fuel':
            return self.fuel
        else:
            raise AttributeError, 'unknown property %s' % property.name

    def do_set_property(self, property, value):
        if property.name == 'fuel':
            self.fuel = value
        else:
            raise AttributeError, 'unknown property %s' % property.name

    def do_engine_started(self, remaining_fuel):
        print '***** Beginning of class closure *****'
        print 'The engine is ready and we still have %f of fuel' % self.fuel
        print '***** End of class closure *****'

    def start(self):
        self.emit('engine-started', self.get_property('fuel'))
        
gobject.type_register(Car)
código procedente de http://www.pygtk.org/articles/subclassing-gobject/sub-classing-gobject-in-python.htm

Uso de las señales. Se muestra como podemos conectar un objeto de la clase que hemos creado a las señales que hemos definido:


import pygtk
pygtk.require('2.0')
import gobject

from car4 import Car

def myCallback(obj, remaining_fuel, data=None):
    print '***** Beginning of User callback *****'
    print 'The engine is starting and we still have %f of fuel' % remaining_fuel
    print '***** End of User callback *****'

def lastCallback(obj, remaining_fuel, data=None):
    print '***** Callback connected with connect_after *****'
    obj.set_property('fuel', remaining_fuel - 10)
    print 'Now we have %f of fuel' % obj.get_property('fuel')
    print '***** End of this callback *****'
    
def test():
    aCar = Car()
    aCar.connect('engine-started', myCallback)
    aCar.connect_after('engine-started', lastCallback)

    aCar.start()
    
if __name__ == '__main__':
    test()
código procedente de http://www.pygtk.org/articles/subclassing-gobject/sub-classing-gobject-in-python.htm



Documentación:

python subclass
http://www.pygtk.org/articles/subclassing-gobject/sub-classing-gobject-in-python.htm
gobject reference manual:
http://library.gnome.org/devel/gobject/stable/
glib:
http://www.es.gnome.org/Documentacion/Desarrollo/SistemaDeObjetosDeGlib

lunes, 26 de abril de 2010

Da un Aspecto Profesional a tu Blogspot. Blogger in Draft

En la Página de Blogger in Draft se puede leer lo siguiente:
"Blogger en borrador es una versión especial de Blogger en la que puedes probar nuevas funciones antes de su lanzamiento público. Entra y echa un vistazo a nuestras novedades."
http://draft.blogger.com


Me ha gustado bastante la utilidad para crear las plantillas para el blog.
Para probar esta nueva utilidad entra en draft.blogger.com -> Diseño -> Diseñador de Plantillas.

A partir de una plantilla inicial, se puede ir modificando hasta conseguir buenos resultados y bastante personalizados. Permite elegir la imagen de fondo entre una gran variedad, o si lo deseamos subir una imagen propia. También se puede modificar muy facilmente el color del texto que aparece en nuestro blog. Todos los cambios que vamos haciendo se van mostrando en "tiempo real" sobre una imagen previa del blog que tenemos debajo de los menús del Diseñador de Plantillas y con un único click, podemos a pantalla completa una vista previa de nuestro diseño.



Video promocional de google sobre esta nueva utilidad para blogspot.

Nota Android: Crear un qr-code

"Un código QR (Quick Response Barcode) es un sistema para almacenar información en una matriz de puntos o un código de barras bidimensional." wikipedia.

Con la aparición de los nuevos teléfonos móviles, los smartphones, se está empezando a usar estos códigos de barras para almacenar urls y proporcionar un acceso rápido a paginas web, liberandonos de la necesidad de tener que escribir la dirección. En la actualidad, es bastante habitual encontrar en la web qrcodes de aplicaciones que enlazan directamente con su ubicación en el "Android Market".

Para poder utilizar qrcodes con un smartphone gestionado por android, es necesario tener instalado una aplicación que permita leer dichos códigos a través de la cámara de fotos e interpretarlos.

En "Android Market", se puede encontrar "shopsavvy", una aplicación que permite la lectura de qrcodes, a partir de la cámara de photos. Esta aplicación tiene otras utilidades, como la de puntos de venta, precios del producto..., pero si el qr-code corresponde a una ulr, esta aplicación directamente nos enlaza, o bien con el "Market" o bien con el navegador.

Para crear un qr-code de una dirección concreta, hay una web que nos genera automáticamente la imagen a partir de un texto introducido por el usuario.

http://www.qrcode.es/?page_id=18&language=es

A continuación, pongo la imagen de un qr-code que redirecciona a este blog.

viernes, 23 de abril de 2010

Nota Python: Intro PyGTK

"GTK+ o The GIMP Toolkit es un conjunto de bibliotecas multiplataforma para desarrollar interfaces gráficas de usuario (GUI), principalmente para los entornos gráficos GNOME, XFCE y ROX aunque también se puede usar en el escritorio de Windows, MacOS y otros. GNOME está basado en GTK+, lo que significa que los programas de GNOME usan GTK+." (wikipedia)
PyGTK es un binding de la biblioteca gráfica GTK para el lenguaje de programación Python.

Gtk está basado en contenedores, lo que implica que un widget no se dice donde se ubica, no es necasrio el uso de coordenadas, si no que se dice que en que contenedor está el widget. Agunos widgets (como una ventana, un botón...) son contenedores que sólo pueden almacenar un único widget (un botón solamente almacena la etiqueta). Si se necesitase poner más de un widget en un contenedor de este tipo (por ejemplo una ventana), se debería poner un contenedor que permitiese más de un widget (por ejemplo una caja).

Los widgets GtkHBox y GtkVBox son contenedores que admiten más de un widget. GtkHBox y GtkVBox son cajas invisibles que empaquetan widgets horizontal o verticamente respectivamente.

La siguiente imagen muestra una ventana que contiene una caja vertical, esta a su vez contiene dos botones.


Ejemplo en ubuntu 10.04:



Para crear la ventana anterior en pygtk hay que hacer lo siguiente:


#objects
window = gtk.Window(gtk.WINDOW_TOPLEVEL) 
caja = gtk.VBox(False, 0) 
hello_button = gtk.Button("Say hello") 
bye_button = gtk.Button("Say bye") 

#add widgets
caja.pack_start(hello_button, True, True, 0) 
caja.pack_start(bye_button, True, True, 0) 
window.add(self.caja) 

#show widgets
hello_button.show() 
bye_button.show() 
caja.show() 
window.show()

Cuando se ejecuta un program en gtk se debe ejecutar el bucle main. Este bucle main se encarga de recoger los eventos y las señales. Para que se ejecute este bucle en PyGTK, hay que ejecutar la función:

gtk.main()

Para salir de dicho bucle hay que ejecutar la función:

gtk.main_quit()

Para recoger los eventos o las señales es necesario “conectar” los widgets. A continuación se muestra como se “conectan” los botones a las funciones “callback” para la señal "clicked":

hello_button.connect("clicked", callback1) 
bye_button.connect("clicked", callback2) 

A continuación se muestra un pequeño ejemplo basado en la ventana con dos botones que se ha mostrado anteriormente. Aparte de las señales de los botones, también se ha “conectado” la ventana principal para que al cerrarse la ventana se termine el programa("delete_event", "destroy")

#!/usr/bin/python 

import pygtk 
import gtk 

class HelloWorld(): 

    def delete_event(self, widget, event): 
        return False    

    def destroy(self, widget): 
        gtk.main_quit() 

    def __init__(self): 
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) 
        self.caja = gtk.VBox(False, 0) 
        self.hello_button = gtk.Button("Say hello") 
        self.bye_button = gtk.Button("Say bye") 
        
        self.caja.pack_start(self.hello_button, True, True, 0) 
        self.caja.pack_start(self.bye_button, True, True, 0) 
        self.window.add(self.caja) 

        self.window.connect("delete_event", self.delete_event) 
        self.window.connect("destroy", self.destroy) 
        self.hello_button.connect("clicked", self.b_click, 1) 
        self.bye_button.connect("clicked", self.b_click, 2) 

        self.hello_button.show() 
        self.bye_button.show() 
        self.caja.show() 
        self.window.show() 

    def b_click(self, widget, data): 
        if data == 1: 
            print "Hello World!" 
        else: 
            print "Bye" 

    def main(self): 
        gtk.main() 


if __name__ == "__main__": 
    hello = HelloWorld() 
    hello.main() 

jueves, 22 de abril de 2010

Nota Python: Salto de línea en Strings

Barra invertida (\) al final de cada línea permite hacer una salto de línea durante la edición del código sin que afecte a la cadena resultante:

print "hello \
       world!"
>> "hello world!"
Una pareja de triples comillas también permite hacer un salto de línea cuando se está editando el código pero dicho salto aparecerá en la cadena si se hace un print con ella.

print """hello
world!"""
>> "hello 
world!"

Si sólamete queremos introducir un salto de línea en una cadena, se debe usar'\n'.
print "hello \nworld!"
>> "hello 
world!"

miércoles, 21 de abril de 2010

Configuración de vim para python

Si se tiene "vi" como punto de partida e instalas vim, ya cambia bastante el aspecto de los programas en python. Por lo tanto, lo primero que he hecho ha sido instalar vim.

Instalación en Ubuntu:
sudo apt-get install vim

Aun así, hay algunas cosas que todavía se pueden ajustar mas, como puede ser el "autoindent" (auto sangrado) y asignar los 4 espacios al tabulador.

Para añadir estas características al editor, hay que modificar un fichero de configuración. Se puede añadir a dos fichero diferentes en función de para que usuarios queremos que estén disponibles estos ajustes.

Si se desea que estos cambios sean generales en el programa, se debe modificar el siguiente fichero:

/usr/share/vim/vimrc

En cambio, si sólo se quiere que estas modificaciones estén disponibles para un usuario, se debe modificar el siguiente archivo:

~/.vimrc

A continuación pongo los ajustes que tengo en mi .vimrc:

syntax on

set tabstop=4
set shiftwidth=4
set expandtab
set softtabstop=4
"set background=dark "comentado
set autoindent

SQLite en Python.

Una herramienta muy útil para trabajar con SQLite  es la extensión de firefox "sqlitemanager".

Hay una gran cantidad de bases de datos, tanto de pago como gratuitas. También existen una gran variedad de módulos distintos para trabajar con esas bases de datos en Python, lo que implica que hay una gran cantidad de APIs que aprender.

Se ha desarrollado una propuesta de API estándar para el manejo de bases de datos en Python para que el código sea prácticamente igual para todas las bases de datos. Esta API es Python Database API (DB-API)

http://www.python.org/dev/peps/pep-0249/

Hay un módulo que se ajusta a la DB-API 2.0 para SQLite. Dicho módulo es:
slqlite3

Para realizar la conexión con la base de datos se hace con la función "connect" esta función tiene unos parámetros de entrada que no están estandarizados. Para el módulo sqlite3 el parámetro de entrada es la ruta donde se encuentra almacenado el archivo que contiene los datos. También se puede poner la cadena ":memory:" lo que implicará que se usará la memoria RAM para la base de datos, por lo tanto no se almacenarán datos al terminar la ejecución del programa.

import sqlite
bdd = sqlite3.connect("./db.sqlite")

Para poder realizar operaciones, se han de realizar sobre un cursor.

cur=bdd.cursor()

Si en nuestra base de datos está desactivado la opción de autocommit, será necesario hacer un commit:

bdd.commit()


Ejemplo:


#!/usr/bin/python
import sqlite3

#connect to the data base
bdd = sqlite3.connect("./db.sqlite")

#cursor
cur=bdd.cursor()

#create a table
cur.execute("""CREATE  TABLE "main"."data" 
             ("id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL , 
             "name" VARCHAR)""")

#insert a value
name="Nombre"
sql_script="INSERT INTO data ( name ) VALUES (\'%s\')" % name
cur.execute(sql_script)
bdd.commit()


#close the data base 
bdd.close()


Nota: Si se va a ejecutar este ejemplo por segunda vez, no debe existir el fichero "db.sqlite" en el mismo directorio, ya que va a intentar crear otra vez la tabla "data" y dará error.


Post relacionados:
http://pablogplanet.blogspot.com/2010/04/base-de-datos-sqlite-y-gestor-sqlite.html

Bibloigrafía:

Base de datos sqlite y gestor "sqlite manager".

SQLite es un sistema de gestión de bases de datos relacional que está contenida en una relativamente pequeña biblioteca en C.

El motor de SQLite no es un proceso independiente con el que el programa principal se comunica, si no que pasa a ser parte del programa principal que lo gestiona.

El conjunto de la base de datos (definiciones, tablas, índices, y los propios datos), es guardada en un único  fichero estándar en la máquina host. Este diseño simple se logra bloqueando todo el fichero de base de datos al principio de cada transacción.


Sqlite manager es una extensión para firefox que permite manegar bases de datos sqlite. Esta extensión permite, crear nuevas tablas, visualizar el contenido de tablas existentes, modificar dicho contenido, o bien añadir nuevos registros a la base de datos.

Extensión:
https://addons.mozilla.org/es-ES/firefox/addon/5817


Algunos pantallazos de sqlitemanager.


Ejemplo de base de datos en sqlitemanager:

Interfaz para la creación de una nueva tabla:



Registros de una tabla existente:



Nota Python: Tamaño de una cadena

Para obtener el tamaño de una cadena se utiliza la función len()

str='cadena'
len(str)

Nota Python: How to i++

En Python no se usa i++ para incrementar una variable como en c/c++.
En Python usamos:

i += 1

Logos y botones para twitter

Gran cantidad de logos y botones para twitter:

Cajas de Código en blogspot

Vamos a "diseño->Edicion de html". Lo primero que hay que hacer es hacer un backup de la plantilla por si se comete algún error. Para descargar la plantilla pinchamos en "Descargar plantilla completa".

A continuación buscamos ]]></b:skin>
Antes del texto anterior copiamos:


pre
{
background:#efefef;
border:1px solid #A6B0BF;
font-size:120%;
line-height:100%;
overflow:auto;
padding:10px;
color:#000000 }
pre:hover {
border:1px solid #efefef;
}

code {
font-size:120%;
text-align:left;
margin:0;padding:0;
color: #000000;}
.clear { clear:both;
overflow:hidden;
}



Para introducir código en el blog a la hora de editar, debemos copiar el código entre las etiquetas(pero sin los espacios):
"< pre>< code>codigo< /code>< /pre>"
Si queremos que estas etiquetas estén disponibles cada vez que empezamos un post, se deben copiar en:
"Configuración->Formato->Plantilla de entrada"


Nota: Cuando se va a publicar la entrada, te puede dar un error. Si es así, pinchas la opción " Dejar de mostrar los errores HTML del cuerpo de esta entrada"