29 de mar. de 2013

Aprendiendo Programacion en QML para Ubuntu Phone

El titulo basicamente lo dice todo. Concluciones Rapidas. 

1. Ubuntu pasara de usar Unity a Unity Next (QT) en algun momento en los proximos años. 

2. Programar en QML es muy sencillo. 

3. Hacer interfaces graficas con QML es relativamente mas facil que usar GTK y Python. 

4. Hacer aplicacione que funcionan en un Telefono, una Tablet y en el PC es un WIN WIN para cualquiera que este pensando en comenzar a programar. 

Basicamente lo que digo es que si hay todo un nuevo SDK porque no aprender de el y usarlo. 
No digo que olviden Python ni GTK, pero interesante aprender QML o Javascript y hacer programas para Ubuntu (Phone, Tablet y PC) o usar Javascript que es el nuevo lenguaje para Gnome. 

Aqui mis primero pasos usando el nuevo SDK de Ubuntu. 

Rapido y Facil 

1. Instalar el SDK (Si usan Raring es simple sudo apt-get install ubuntu-sdk) eso instalara QT5 y QTCreator que es lo que se usa para programar. 

Si usan versiones anteriores 

sudo add-apt-repository ppa:canonical-qt5-edgers/qt5-proper && sudo add-apt-repository ppa:ubuntu-sdk-team/ppa && sudo apt-get update && sudo apt-get install ubuntu-sdk notepad-qml 

2. Creando un programa para abrir una pagina web. (Bastante basico)
Me voy ahorrar el hola mundo porque basicamente un ejemplo mas complejo es un ejemplo util para hacer cosas mas interesantes y entendiendo el programa que voy a organizar se puede entender un simple hola mundo.

Programando.

1. Abrir Qt Creator es el nuevo IDE para las cosas de Ubuntu, es como Geany y otros que usabamos cuando estabamos tratando con Python.

2. Crear un Nuevo Proyecto



Para este caso le puse como nombre al proyecto eltiempo. Le damos finalizar y pasamos con el codigo.



EL CODIGO
Si conocen Javascript esto sera cosa de niños, realmente QML no es nada del otro mundo, tecnicamente es mas simple que Python, quizas por eso es mas rapido de usar.

Lo creado con QML lo podemos usar en dispositivos Android, PC, y Windows sin hacer esfuerzos raros ni cosas complejas.

Todo programa en QML se estructura de la siguiente forma.

imports

MainView

      Propiedades del MainView

      Page

          Contenido de la Aplicación
       
      Contenido por fuera de la aplicación

Repasemos que es esto.

Import, es lo mismo que importar modulos en Python, nada nuevo para nosotros.

MainView es el mismo Main() que usabamos en Python es la declaracion del programa.

Las propiedades se refieren a tamaño, color, si es maximizado o minimizado y todas esas cosas visuales.

Page hace referencia a la declaracion del codido del programa.

Y pues el contenido por fuera de la aplicación esto es nuevo porque no lo han visto tanto en Python pero cuando se use lo explicare en detalle.

He aquí el programa.

import QtQuick 2.0
import QtWebKit 3.0
import Ubuntu.Components 0.1


MainView {
    objectName: "mainView"
    applicationName: "eltiempo"
    id: root

    width: units.gu(60)
    height: units.gu(80)

    property real margins: units.gu(2)
    property real buttonWidth: units.gu(9)

    Page {
        title: i18n.tr("El Tiempo (Noticias)")
        WebView {
                id: webview
                url: "http://m.eltiempo.com"
                width: parent.width
                height: parent.height
                
    }
  }
}


Lo procedo a explicar con velocidad.

import QtQuick 2.0
import QtWebKit 3.0
import Ubuntu.Components 0.1

Se encarga de importar los tres ("modulos") que usaremos  QtQuick es la version de QT para QML.
QtWebkit es un modulo para usar un navegador en codigo QML o QT (Abrir paginas web y esas cosas)
Ubuntu Components se encarga de lo estético para que sea una aplicación con los parámetros de diseño de Unity Next

MainView {
    objectName: "mainView"
    applicationName: "eltiempo"
    id: root

    width: units.gu(60)
    height: units.gu(80)

    property real margins: units.gu(2)
    property real buttonWidth: units.gu(9)

Aqui definimos el MainView es decir como se ve la aplicación principal
El nombre del obejto es mainView pero podria haberlo llamado vistaprincipal o como quieran.
El nombre de la aplicacion es eltiempo porque basicamente estoy creando una aplicacion para ver las noticias de la pagina www.eltiempo.com (Periodico Digital en Colombia)

id: root basicamente define que esta es la raiz del programa.

Width y Height son tamaños están en unidades básicas para celulares smartphones pero pueden cambiarlas.

Lo demas son margenes y esas cosas, detalles visuales que realmente son una copia de los parámetros establecidos por Unity Next.

El programa en si es lo que sigue.
Page {
        title: i18n.tr("El Tiempo (Noticias)")
        WebView {
                id: webview
                url: "http://m.eltiempo.com"
                width: parent.width
                height: parent.height
                
    }
  }
}
 

title: Es basicamente el titlo del programa para mi caso particular lo llame El tiempo (Noticias) i18n.tr basicamente lo que dice es que estoy usando codigo internacional para el texto pueden quitar eso si quieren, no hay lio.

WebView es el modulo que voy a ejecutar para este caso particular.
id: es el nombre de identificación que tendrá este micro programa dentro del programa. Podria llamarlo desde cualquier otro lado del programa usando solo el texto webview.

url: es básicamente la pagina que usa el tiempo para dispositivos moviles.

Width y Height son el tamaño que debe tener la pagina para este caso le dice que usara el tamaño definido por la ventana principal así que usara 60 y 80 que fue lo que definí mas atrás.

Y eso es basicamente todo.

Control + R para correr el programa y aquí ya lo ven funcionando.


Bastante fácil, solo usamos Ubuntu Components para lo visual y eso se encargo del trabajo.

Ya esta básicamente lista la aplicación para usarla en un teléfono o desde el pc mismo.

Pero hay mas.
Como se imaginaran esto es una aplicación que solo abre una pagina hecha para moviles pero resulta que eltiempo.com tiene una API

En mi segundo tutorial usaremos la api dentro de esta aplicación recién creada para evitar ver publicidad y demás cosas que muestra la pagina oficial.

Ahora el reto es para ustedes lectores, que aplicación pueden crear, un horoscopo, un sudoku o un render de alguna pagina con contenido interesante. Recuerden que el primer paso es hacer algo sencillo despues podemos proceder con cosas mas complejas como adaptar las API's a nuestra aplicacion.

13 de feb. de 2012

Python + GObject + Gstreamer + GTK3 (Parte 3)

Ahora si estamos por llegar a la parte que estaban esperando y es el trabajo con GTK3 y Gstreamer.

Estos dos a veces parecen buenos amigos pero no siempre se comportan como queremos. Sin más rodeos vamos a trabajar.

Lo primero es que para esta parte bajen un programa en python que mostré hace algunas entradas en este blog, a partir de ese programa es que vamos a construir los elementos necesarios para reproducir nuestros archivos desde GTK3.


El programa que descargaron fue uno que estoy usando para mejorar el codigo de Aleatorio. Se ve como ven en la imagen. En ese punto el programa solo es capaz de correr el botón aleatorio.




Cuando abren el programa en algún editor encontraran unos espacios donde hay unos comentarios que dicen, código de gstreamer y cosas de ese estilo.

Como ya explique en la entrada anterior el código de Gstreamer simplemente lo voy a dejar aquí y explicare lo nuevo.

 #Codigo de Gstreamer
 self.playbin = gst.element_factory_make("playbin2", "player")
         bus = self.playbin.get_bus()
         bus.add_signal_watch()
         bus.connect("message", self.on_message)


 #Codigo de mensaje de Gstreamer
     def on_message(self, bus, message):
         t = message.type
         if t == gst.MESSAGE_EOS:
             self.playbin.set_state(gst.STATE_NULL)
         elif t == gst.MESSAGE_ERROR:
             self.playbin.set_state(gst.STATE_NULL)
             err, debug = message.parse_error()
             print "Error: %s" % err, debug

Listo eso es todo lo que ya vimos en la entrada anterior y no hay necesidad de explicar. Si tienen dudas comentan en la entrada anterior y puedo explicar en detalle.

Ahora vamos a ver algo nuevo y es recuperar la lista, hasta el momento solo sabemos que podemos meter listas dentro de el GtkTreeview para que se vea como en la imagen mas arriba, pero que pasa si necesitamos esa lista para reproducirla.

Gstreamer, Python y GTK3 se llevan bien pero no tan bien para que el proceso sea automatico, es por ello que es necesario recuperar el estado de la lista para poder pasarla a Gstreamer.

Para ello vamos a crear una nueva definición que la podemos crear debajo de la funcion Aleatoria en el código.
     def lista(self):
         listaa = []
         for allfiles in self.liststore2:
             for media_files in allfiles:
                 listaa.append(media_files)
         return listaa 
  
Como ven lista es una función propia (self) cuyo único objetivo es buscar que hay en el TreeView y meterlo dentro de una variable que se llama listaa, al final esta funcion se retorna y ya cualquier función externa puede usarla.

Como ya se imaginan la siguiente función que usara esta información sera Play.

      #Reproducir
      def play(self, wid):
          print "Reproducir"
          le = self.lista()
          for a in le:
              self.playbin.set_property("uri", a)
              self.playbin.set_state(gst.STATE_PLAYING)
      
      #Detener
      def detener(self, widget):
          print "Detener"
          self.playbin.set_state(gst.STATE_NULL)

Como ven la información que retorno self.lista la guardamos dentro de la variable "le" y ahí quedo toda la musica que estaba dentro del TreeView de GTK3, lo siguiente es simplemente decirle a Gstreamer que reproduzca todo el contenido de "le".

Detener es parecido pero simplemente lo único que hace es detener cualquier acción del contenedor de Gstreamer.

Si le dan reproducir notaran que el programa comienza a reproducir cualquier canción que le pongan a reproducir. Pero ojo que no hemos terminado, hasta este punto del tutorial el programa solo es capaz de reproducir el primer elemento de la lista y el ultimo elemento de la misma, esto se debe a que no hemos hecho los ciclos de GObject ni de Python que les conté en la primera entrada.

Espero disfruten sus primeros pasos con Python + GObject + Gstreamer + GTK3 pueden seguir revisando cosas y seguramente van a descubrir como se hace para reproducir todos los archivos.

Pronto la ultima parte de estas entradas cortas con el código final de GObject y Python necesario para reproducir toda la lista musical.


11 de feb. de 2012

Python + GObject + Gstreamer + GTK3 (Parte 2)

Para poder trabajar con 4 lenguajes distintos es fundamental comenzar a entender el funcionamiento del que se encargara del trabajo pesado que en nuestro caso es Gstreamer, como ya les comente este depende de un ligero balance con GObject que se encarga de realizar el bucle sobre el que vive y corre Gstreamer.

Algunos podrán pensar en usar Pygst pero como no ha sido 100% portado a la nueva tecnología es mejor usar elementos conocidos que no cambian tanto en el tiempo al evolucionar las versiones del código.

Lo primero es entender el funcionamiento de Gstreamer. Para no complicarnos los módulos para reproducir contenido de Gstreamer son bastante amplios pero como esto es una primer aproximación realmente solo nos vamos a enfocar en Playbin que se encarga de reproducir cualquier cosa que le demos de comer.

Para quien desea leer un poco mas de la arquitectura y ejemplos pensados para pygtk y gtk2 es bueno ver esta pagina.

Volviendo al tema de playbin.
El código funciona de la siguiente forma.

Primero se crea un un elemento de Gstreamer que para efectos mas prácticos le podemos decir contenedor.

self.playbin = gst.element_factory_make("playbin2","player")

Después es necesario crear un elemento llamado bus que se encarga de escuchar cambios en el interior del contenedor.

bus = self.playbin.get_bus()

Como pueden ver usa get que es obtener en español. Lo que obtiene es información de lo que pasa dentro del contenedor que se llama playbin y creamos con las instrucción anterior.

Al bus es necesario agregarle un observador de señales ya que como sabemos al contenedor le llegaran y le saldrá información.

bus.add_signal_watch()


Este sistema entonces emite señales de lo que entra y sale del contenedor en todo momento pero tiene que almacenar esa información en alguna parte por lo que la siguiente linea se encarga de hacer el proceso de almacenamiento mas simple, al crear una función llamada self.mensajes donde guardaremos esa información importante.

bus.connect("messages", self.mensajes)


Vamos entonces a crear una función que es obligatoria como las anteriores para el funcionamiento de gstreamer. Y es el almacenador de los mensajes.

def self.mensajes(self, bus, messages):
     t = message.type
     if t == gst.MESSAGE_EOS:
           self.playbin.set_state(gst.STATE_NULL)

Esta primera parte de la definición en la función self.mensajes lo que hace es guardar en una variable t todos los mensajes que vengan del bus. Específicamente todos los mensajes que se producen cuando termina de reproducir algún contenido, el bus lee esos mensajes con una forma MESSAGE_EOS. Y lo siguiente que el sistema hace es decirle a Gstreamer que si no encuentra contenido pause (detenga) la reproducción, esto se hace con el comando set_state(gst.STATE_NULL).

     elif t == gst.MESSAGE_ERROR:
           self.playbin.set_state(gst.STATE_NULL)
           err, debug = message.parse_error()
           print "Error: %s" % err, debug

La segunda parte de la definición self.mensajes se encarga de decirle que hacer a gstreamer si lo que se intenta meter dentro del contener tiene errores o no se puede reproducir, en este caso primero pausa la reproducción y después crea un texto en consola donde se muestra la razón por lo que no se puede reproducir el contenido.

Con esto hemos terminado la segunda parte y ya sabemos como crear un playbin y que debe tener como obligatorio en Gstreamer para su correcto funcionamiento, en la próxima entrada comenzare a mostrar con ejemplos en GTK3 como trabajar con Gstreamer.

8 de feb. de 2012

Python + GObject + Gstreamer + GTK3 (Parte 1)

Esta entrada esta pensada para poder dar una primera respuesta a las personas que han preguntado acerca de la parte final del tutorial de Python y GTK3.

Como algunos quizás saben Gstreamer es muy amigo de GObject porque están pensados para funcionar como hermanos.
GObject es entonces una parte fundamental para Gstreamer ya que se encarga de crear un ciclo o bucle en el que gst habita y hace su trabajo.

Todo esto suena muy bonito pero tiene su grado alto de complejidad y es que como sabemos GTK3 también es un ciclo, entonces hay que saber quien vive dentro de quien y porque razón.

De primer mano podríamos pensar que el ciclo mas grande seria GObject y que GTK3 y Gstreamer deberían habitar dentro de este. Esta seria una solución ideal de no ser por el hecho de que estamos trabajando en Python que crea Threads que son para no confundirlos unos mini ciclos.

Al tener tantos ciclos puede pasar que no se sabe quien vive dentro de quien para que funcionen de forma adecuada todo.

Es por eso que hay que pensar muy bien incluso como invocar los modulos.

La respuesta la verdad no es tan compleja, el ciclo mayor debe ser GTK3 y dentro debe estar lo demás, se deben abrir y cerrar esos ciclos de la siguiente forma:

Abrir
GTK3
GObject
Gstreamer

Cerrar
Gstreamer
GObject
GTK3

Para verlo con un poco más de codigo seria algo asi:

from gi.repository import Gtk, GObject
import gst

loop = GObject.MainLoop()

#Cerrando los ciclos
if __name__ == "__main__":
        main()
    loop.quit()   
    Gtk.main()


En la próxima entrada mostrare una primera aplicación que usa este tipo de ciclos en un primer ejemplo simple de Gstreamer.

6 de feb. de 2012

Crear Elementos Aleatorios en GtkTreeview

Si han revisado el blog y están haciendo el Tutorial de Python y GTK3 se habrán dado cuenta que en GTK3 no existe order(index) para el Treeview. Esto permitía reordenar una lista, pero en GTK3 no existe y por lo tanto elimina la opción de crear una lista aleatoria con facilidad.

Más información.

Es por ello que para GTK3 hay que implementar un método distinto para poder solucionar este pequeño problema que deja el paso de GTK2 a GTK3.

El usuario Gustavo Angel me ha pedido amablemente buscar una solución y me he puesto a pensar de una forma relativamente eficiente de realizar esto sin comprometer demasiado el código tratando de que el nuevo código sea compatible para GTK2 y GTK3


Código ANTIGUO únicamente valido para GTK2
     #Si se activa Aleatorio
         if var == 0:
             n = 0
             for musicfiles in self.medialist:
                 n += 1
             index = range(0, n)
             shuffle(index)
     #Reorganiza la lista de musica llamada medialist
             if len(index) > 1:
                 self.medialist.reorder(index)

Código NUEVO valido para GTK2 y GKT3
    #Nuevo sistema de aleatorio
    def aleatorio(self, widget, data=None):
        lista = []
        for allfiles in self.liststore1:
            for media_files in allfiles:
                lista.append(media_files)
        random.shuffle(lista)
        self.liststore1.clear()
        for f in lista:
            self.liststore1.append([f])

Este código nuevo no esta aplicado al programa del tutorial es solo un ejemplo que he creado para un programa sencillo que importa archivos de audio, crea una lista Treeview y después se encarga de volver la lista aleatoria.

Dejo el link de descarga del programa para que lo miren y lo prueben y si alguien tiene una mejor idea de como crear el Aleatorio nos deje el comentario.



Pronto actualizare el tutorial en PDF con el nuevo código aleatorio para gtk2 y gtk3

Actualización 12 de Febrero 2012: Al parecer este método solo es útil cuando se tiene una sola columna en el Gtk.liststore por lo que aunque es una forma valida de realizar el proceso es incompleta cuando se tienen mas columnas, seguiré buscando una solución mas completa para solucionar este problema.

Actualización 13 de Febrero 2012: Después de dedicar casi todo mi domingo a romperme la cabeza para solucionar este pequeño dolor de cabeza que son los Treeviews he encontrado una nueva solución mas general de la que comento en esta entrada. Esta nueva solución esta lejos de ser perfecta y para mi es mas bien un Hack que soluciona el problema pero hace que el código se vea algo maluco.

Dejo sin embargo la información en miras de si alguien encuentra una solución mas completa y bonita la pueda colocar en los comentarios y así actualizare esta entrada.

Este nuevo código asume que son dos listas o dos columnas con las que trabajamos por lo tanto asume también que ya no se trabaja con un solo gtk.liststore pero con dos para el caso de dos columnas. Si fueran 3 columnas entonces tocaría agregar una lista3 y un self.liststore3.

    def aleatorio(self, widget, data=None):
        lista1 = []
        lista2 = []
        for files in self.liststore1:
            for a in files:
                lista1.append(a)
        for uri in self.liststore2:
            for b in uri:
                lista2.append(b)
        listas = zip(lista1,lista2)
        random.shuffle(listas)
        u = [x[0] for x in listas]
        v = [x[1] for x in listas]
        self.liststore1.clear()
        self.liststore2.clear()
        for f in u:
            self.liststore1.append([f])   
        for f in v:
            self.liststore2.append([f])

Si encuentro una nueva solución que evite el uso continuo de tantos for y el zip, actualizare esta entrada. Por ahora se me ocurren opciones pero solo podre revisar hasta el sábado que tenga suficiente tiempo.