Mostrando entradas con la etiqueta nota. Mostrar todas las entradas
Mostrando entradas con la etiqueta nota. Mostrar todas las entradas

lunes, 26 de julio de 2010

Nota: Añadiendo south a un projecto existente de django

Hace poco tiempo, miré por encima como funcionaba south, pero no lo había usado hasta ahora. Simplemente había traducido y resumido el tutorial oficial para hacer un mini tutorial, pero sin incluirlo en ningún proyecto.

Ahora se ha añadido al proyecto sobre el que estoy trabajando el módulo south y por lo tanto tenía que añadir las migraciones correspondientes a la base de datos de mi ordenador de desarrollo.

No he sido capaz de añadir south sin borrar los datos que había previamente en las tablas. Me imagino que se podrá, pero como no me ha salido a la primera y los datos que tenía, eran de prueba, simplemente me he cargado las tablas de la base de datos.

El orden que he seguido es el siguiente:

Borrar las tablas de la base de datos se las aplicaciones que vaya a gestionar South.

Eliminar las aplicaciones de INSTALLED_APPS.

Sincronizar la base de datos.

Añadimos de nuevo las aplicaciones a INSTALLED_APPS.

Creamos la primera migración de las aplicaciones que vaya a gestionar South.

python manage.py schemamigration app_name –-initial

Donde app_name es el nombre de la aplicación que gestiona South. Hay que repetir este proceso para cada aplicación que gestionemos con South.

Ahora aplicamos la migración.

python manage.py migrate app_name

A partir de este momento, cada vez que se realice un cambio en los modelos, es necesario crear una nueva migración con:

manage.py schemamigration app_name –-auto


Para aplicar los cambios realizados hay que volver a usar:


python manage.py migrate app_name

domingo, 27 de junio de 2010

Nota: Palabras Clave para los colores en CSS

Palabras clave para los colores en CSS.



X11 color names


http://en.wikipedia.org/wiki/Websafe

jueves, 24 de junio de 2010

Nota: Script en Django

Puede ser una buena idea, para un proyecto de django, tener scripts externos que realicen tareas concretas. Para generar estos scripts, vamos a usar la opción, que tiene django a partir de la versión 1.0, de crear subcomandos para "manage.py". Una vez creado el subcomando, para ejecutar el script, simplemente habrá que ejecutar el fichero "manage.py" pasándole como parámetro nuestro subcomando.

En la página de django, nos muestran como se crean los subcomandos.
Writing custom django-admin commands.


La metodología para crear los subcomandos es muy fácil, en el directorio de una app de django, hay que crear unos directorios y unos ficheros. El fichero que contiene el código del subcomando, tendrá el nombre del subcomando con la extensión "py". Veamos como quedaría el directorio de la app si el nombre del subcomando fuese "my_subcommand":

app/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            __init__.py
            my_subcommand.py
    tests.py
    views.py


Por los tanto los ficheros que hay que crear son:
  • management/__init__.py
  • management/commands/__init__.py
  • management/commands/my_subcommand.py

Es importante crear los ficheros __init__.py. Estos ficheros están en blanco, pero indican que los directorios son módulos de python.

En el fichero "management/commands/my_subcommand.py", es donde hay que escribir el código del subcomando.

Como ejemplo, voy a poner un subcomando de "manage.py" que muestre el texto "Hello world!".

Dentro del directorio de cualquier aplicación del proyecto, tiene que estar añadida la aplicación a INSTALLED_APPS, creamos los siguientes ficheros:

  • management/__init__.py
  • management/commands/__init__.py
  • management/commands/hello_world.py


Los ficheros __init__.py están vacíos, y en "management/commands/hello_world.py" copiamos el siguiente código.


from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = 'check unchecked votes'

    def handle(self, *args, **options):
        print "Hello world!"

Para ejecutar el script, hay que ir al directorio principal del proyecto y ejecutar en el terminal:
python manage.py hello_world


Este ejemplo es muy simple, y no usa los modelos de django, pero vale para ver como es la estructura de un subcomando. En el fichero que contiene el código del subcomando, se pueden importar los modelos como en cualquier otro fichero del proyecto.

from myproject.myapp.models import Model


Lo que nos permite generar scripts que interactúen con los modelos creados en nuestro proyecto y usar la metodología de django para trabajar con la base de datos.

Nota: Tutoriales oficiales de django

En la página web de django hay una gran variedad de tutoriales.

http://code.djangoproject.com/wiki/Tutorials

martes, 22 de junio de 2010

nota: lista vacía en python

Comprobación de lista vacía:
a = []
if not a:
    print "list is empty"

miércoles, 9 de junio de 2010

Usando path relativos para los templates de Django

En el archivo settings.py, es necesario indicar donde se encuentran los templates con su path absoluto:
TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

Teniendo en cuenta que es código python, podemos hacer que esos paths se calculen a partir de paths relativos. Veamos como.


Es necesario incluir el siguiente código en el fichero settings.py
import os
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))

Una vez añadido este código al fichero, ya podemos indicar el template de forma relativa.

TEMPLATE_DIRS = (
os.path.join(PROJECT_PATH, 'templates')

)

viernes, 14 de mayo de 2010

Nota: git hosting

Git es un software de sistema de control de versiones distribuido. Los servicios de git hosting permiten, como su nombre indica, hospedar repositorios de git.

He encontrado dos servicios que tienen buena pinta:

github.com   Este parece bastante serio. Por ejemplo tiene el repositorio de Ruby on Rails. La única pega que he encontrado, es que la versión gratuita no tiene proyectos privados. Está orientado al software colaborativo.

codaset.com tiene unas características parecidas al anterior. Está pensado para software libre. Además, es gratuito y te permite controlar la privacidad de tu proyecto. Público, semipúblico o privado son las opciones de privacidad de los proyectos. A parte del repositorio propimente dicho, tiene un web presenta el estado del proyecto, un blog, una wiki, un sistema de tickes...

martes, 11 de mayo de 2010

Nota Django. Crear una página de comentarios

Este post es la continuación de otros post que he realizado sobre el framework Django. En este post voy a poner un pequeño ejemplo de como se haría una página de comentarios. Creo que es bastante ilustrativo porque toca temas importantes de django. Maneja la base de datos (SQLite3 en nuestro ejemplo) a través de los modelos de django, se usan plantillas (template) con el gestor de plantillas de django, se genera una página a partir de plantillas en las cual se escriben registros almacenados en la base de datos y se leen datos de un formulario que incluye esa misma página.

Lo primero que hay que hacer es crear el proyecto de django.

django-admin startproject commentweb


Creamos una app que va a tener el modelo que gestiona los comentarios que se almacenan en la base de datos.

python manage.py startapp comments


Añadimos el modelo dentro de commentweb/commments/models.py.


from django.db import models
# Create your models here.
class Comment(models.Model):
    title = models.CharField(max_length = 20)
    date = models.DateTimeField()
    text = models.TextField(blank = True)

El modelo consta de tres campos:

  • title: título del comentario.
  • date: fecha de la publicación.
  • text: contenido del comentario.


Ahora hay que modificar el archivo settings.py

Base de datos

DATABASE_ENGINE = 'sqlite3'           # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = 'comments.sqlite'             # Or path to database file if using sqlite3.
DATABASE_USER = ''             # Not used with sqlite3.
DATABASE_PASSWORD = ''         # Not used with sqlite3.
DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.

Zona horaria. Se puede consultar en http://en.wikipedia.org/wiki/List_of_tz_zones_by_name

TIME_ZONE = 'Europe/Madrid'

Añadimos el path donde se almacenan los templates.

TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    "/home/user/djangoprojects/commentweb/templates",
)


Aplicaciones disponibles. He borrado las que vienen por defecto y he añadido la que hemos creado.

INSTALLED_APPS = (
    'commentweb.comments',
)

A continuación sincronizamos la base de datos.

python manage.py syncdb


Nos inidica que hemos creado una nueva tabla

Nuestra página web va a tener dos direcciones, por lo tanto debemos editar el fichero commentweb/urls.py para añadirlas.


from django.conf.urls.defaults import *
from commentweb.comments.views import save
from commentweb.comments.views import comments

urlpatterns = patterns('',
    (r'^comments/$', comments),
    (r'^save/$', save)
)

Vamos a crear las páginas '/comments/' y '/save/'. La página '/comments/' mostrará los comentarios que hay almacenados en la base de datos. Además, tendrá un formulario que nos permita añadir nuevos comentarios. La página '/save/' almacena un comentario nuevo. Esta página se llama desde el formulario de la página anterior cuando se añade un nuevo comentario. Para gestionar estas páginas hay que crear las funciones comments y save en commentweb/comments/views.py. Pero antes, vamos a crear los templates que usan dichas funciones. En el directorio que hemos añadido anteriormente al archivo settings.py, vamos a crear el template comments.html. A continuación muestro su contenido:

< html>
    < head>
        < title>Comments< /title>
    < /head>
    < body>
        < form method="post" action="/save/">
            Title< input type="text" size="20" maxlength="20" name="title"> < br />
            < textarea name="text" rows="4" cols="40">< /textarea>< br/>
            < input type="submit" value="Comment!"/>
        < /form>
        {% for comment in comment_list %}
            < h2>{{comment.title}}< /h2>
            < p>Date: {{comment.date}}< /p>
            < p>{{comment.text}}< /p>
        {% endfor %}
    < /body>
< /html>

Nota: he dejado un espacio entre los caracteres '<' y la etiquetas para una correcta visualización en el blog. Cuando se use este fichero hay que eliminar dichos espacios.

La plantilla anterior tiene dos partes fundamentales. La primera, es un formulario que permite añadir comentarios. De este formulario es importante el nombre del textarea (name="text"), el nombre de título (name="title") y que la acción que se ejecuta al pulsar el botón "Comment!" (action="/save/") nos lleva a la página '/save/'. La segunda, es una etiqueta de plantilla for que nos muestra todos los comentarios que están almacenados en la variable comment_list. A continuación se muestra el template para la página save.html


< html>

    < head> 

        < meta http-equiv="Refresh" content="2;url=../comments/"> 

    < /head>



    < body>

        < p>Su comentario ha sido guardado. 
Por favor esperar a ser redireccionado.< /p>

    < /body>

< /html>


Nota: he dejado un espacio entre los caracteres '<' y la etiquetas para una correcta visualización en el blog. Cuando se use este fichero hay que eliminar dichos espacios. Esta plantilla es muy simple. Nos muestra un mensaje diciendo que el comentario de ha guardado y pasado 2 segundos nos redirecciona otra vez a la página comments. El proceso en el que se guarda el comentario en la base de datos se realiza en la función que invoca este template desde la vista. A continuación, vamos a ver las funciones que generan las vistas.

from commentweb.comments.models import Comment

from django.shortcuts import render_to_response

import datetime



# Create your views here.

def comments(request):

    comment_list = Comment.objects.all()

    return render_to_response('comments.html', {'comment_list': comment_list})



def save(request):

    txt = request.POST["text"]

    title = request.POST["title"]

    comment = Comment()

    comment.text = txt

    comment.date = datetime.datetime.now()

    comment.title = title

    comment.save()

    return render_to_response('save.html', None)



La funcion comment obtiente una lista de todos los comentarios que hay en la base de datos. Esta función retorna la salida de la función render_to_response que tiene dos parametros de entrada. El primero es el template con el que se crea la página. El segundo, es un diccionario que contiene los valores de las variables que hay en las plantillas. La clave del diccionario es una cadena que corresponde al nombre de la variable que usa el template ({{comment_list}} en este caso) y valor del diccionario, es el valor que la variable va a tomar durante la ejecución.


Una vez realizado esto, nuestro ejemplo ya está terminado. Para poder comprobar su funcionamiento es necesario ejecutar el servidor de pruebas que trae django.

python manage.py runserver

la dirección de nuestra nueva página es:

http://127.0.0.1:8000/comments/

Una vez realizado todos los pasos anteriores, nuestra nueva página ya nos debería permitir introducir nuevos comentarios.

Nota ubuntu: Mostrar el path en Nautilus

Por defecto, en ubuntu 10.04, nautilus muestra el path en el que nos encontramos mediante botones. Si queremos obtener el path como un texto, por ejemplo para copiarlo, simplemente hay teclear:
 

'Ctrl + l'

lunes, 10 de mayo de 2010

Nota Django: Intro II. Hello world 2.

Este post es la continuación de Intro django I. Ahora lo que vamos a ver es como poder leer la dirección que se escribe en el navegador y usar esos datos.

Vamos a modificar el archivo urls.py y el archivo views.py para que cuando se escriba la dirección en el navegador, podamos leer los datos introducidos. Es necesario crear una nueva página, por lo que es necesario modificar el archivo urls.py y crear una nueva vista.

Vamos a crear la página http://127.0.0.1:8000/say/xxx. Donde 'xxx' es cualquier combinación de entre uno y veinte caracteres de logitud. Esta página mostrará el texto introducido ('xxx').

Añadimos la nueva vista.

vi views.py

Editamos el archivo para que quede de la siguiente manera.

# Create your views here.
from helloweb.textapp.models import Textmodel
from django.http import HttpResponse


def say_hello(request):
    text = Textmodel.objects.get(pk = 1)
    html = "%s" % text.content
    return HttpResponse(html)
 

def say(request, txt): 
    html = "%s" % txt 
    return HttpResponse(html) 

Ahora vamos a editar el fichero helloweb/urls.py para que se pueda interpretar la nueva dirección.

vi urls.py

Añadimos la nueva dirección a urlpatterns.

from django.conf.urls.defaults import * 
from helloweb.textapp.views import say_hello 
from helloweb.textapp.views import say 

# Uncomment the next two lines to enable the admin: 
# from django.contrib import admin 
# admin.autodiscover() 

urlpatterns = patterns('', 
    # (r'^admin/', include(admin.site.urls)), 
    (r'^hello/$', say_hello), 
    (r'^say/([a-z]{1,20})/$', say) 
) 

La expresión [a-z]{1,20} hace referencia a cualquier cadena de caracteres entre la a y la z (sólo minúsculas) con una longitud de entre 1 y 20 caracteres. Para más información sobre las expresiones regulares (o regexes). Enlace: http://docs.python.org/library/re.html#re-syntax

Una vez modificados los archivos, ejecutamos el servidor de pruebas que trae django.

python manage.py runserver


Ponemos la siguiente dirección en el navegador para comprobar que todo funciona.

http://127.0.0.1:8000/say/hello

El navegador nos debe mostrar el texto 'hello' en el contenido de la página. Podemos cambiar el texto 'hello' en la barra de direcciones por cualquier otro texto de entre uno y veinte caracteres en minúsculas, y esa nueva cadena es la que aparecerá en el contenido de la página.



Plantillas de Django

En el ejemplo anterior, el html se generó directamente con python. Esto no es muy conveniente y que el diseño de la página está empotrada en su programación. Lo adecuado es hacerlo de forma separada. Django tiene un sistema de plantillas (templates) que permite separar la parte de programción en django y la parte de diseño web.

A continuación vamos a modificar la función say, para que en vez de escrbir directamente el html, se extaraiga de una plantilla y los datos que queramos introducir en la página, los proporcione django.

Lo primero que hay que hacer es crear una plantilla. La voy a guardar como helloweb/templates/say_template.html

vi template.html

Añadir el siguiente código html al archivo:

 < html >
    < head >
        < title >Say page!!!< /title >
    < /head >
    < body >

        < h1 >Say page.< /h1 >
        < p >you say: {{ text }}.< /p >
    < /body >
< /html >

He dejado espacio entre las etiquetas html para que se vea correctamente en el blog pero en nuestro ejemplo no hay que dejar espacios entre los caracteres '<', '>' y las etiquetas.

El texto {{ text }} es una variable, y por lo tanto, este texto se reemplazará por un valor durante la ejecución.

A la hora de usar un template en django dentro de un proyecto, es necesario añadir el path donde se encuentra el template al fichero helloweb/settings.py. Las rutas hay que ponerlas de forma absoluta, es decir, partiendo de '/'. A continuación pongo lo que hay que variar en el archivo settings.py para añadir un directorio de templates.

TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    '/home/user/djangoprojects/helloweb/templates',
)

Nota: Es importante poner la coma al final de la cadena, ya que es una tupla.

Una vez hecho esto ya se han añadido los templates que estén en ese directorio al proyecto.


A continuación hay que modificar la función say del archivo helloweb/textapp/views.py para leer el template y añadir a dicho template las variables deseadas.


vi views.py

Modificamos la función say e importamos los módulos necesarios. Pongo el fichero views.py entero con las modificaciones necesarias para el uso del template.

# Create your views here.
from helloweb.textapp.models import Textmodel
from django.http import HttpResponse
from django.template.loader import get_template
from django import template

def say_hello(request):
    text = Textmodel.objects.get(pk = 1)
    html = "%s" % text.content
    return HttpResponse(html)

def say(request, txt):
    t = get_template('say_template.html')
    c = template.Context({'text': txt})
    html = t.render(c)
    return HttpResponse(html)

En la funcion say, hemos creado el template 't' a partir de la plantilla 'say_template.html'. Este fichero tiene que estar en el directorio que hemos añadido a settings.py. Después, se ha creado el contexto 'c' que contine el diccionario con la variable 'text', a la cual le daremos el valor de la variable 'txt' durante la ejecución.

Al poner la dirección http://127.0.0.1:8000/say/hello en el navegador, nos mostrará el contenido de la plantilla pero con el valor actual de la variable {{text}}, es decrir 'hello'.

jueves, 6 de mayo de 2010

Nota Django: Screencast. Crear una Wiki en 20 min

Screencast de django.
En este ejemplo, Siddhi nos muestra como crear una wiki con django en 20 minutos.
http://showmedo.com/videotutorials/video?name=1100000&fromSeriesID=110

sábado, 1 de mayo de 2010

Nota Android: Hard Reset y Android OS Monitor

Para realizar un reset hw y dejar el teléfono como viene de fábrica, hay dos maneras:

  • Marcando en el teléfono: *2767*3855#
  • LLamar + menú + colgar




Android Os Monitor.

Es una aplicación gratuita que se encuentra en el market que nos permite ver que tareas se están ejecutando en nuestro terminal, que conexiones hay abiertas, el estado de la batería...

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

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

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