sábado, 15 de marzo de 2014

Python. Conexión de señales( PyGtk )




Seguimos con nuestro particular estudio de Python y nuestro pequeño programa.

Hasta ahora, hemos visto como hacer uso de Glade, y vemos como conectamos las respectivas señales.

   #Create object gtk.Window , from load window the glade
   self.window = self.glade.get_object('consultas')
   # Example connect manual signal.
   self.window.connect("destroy", self.destroy)

Si le echamos un vistazo al commit 78f6437,podemos observamos los cambios que teníamos anteriormente, git diff 753f400 78f6437 , observaremos como podemos determinar en Glade donde tiene que saltar.

En la imagen de tinnydb.ui puedes ver donde tienes que declarar que señal 
vamos a controlar.


En este caso, vamos a controlar el evento delete-event
En Gtk, este evento se dispara ANTES del destroy, y por ejemplo, podemos usarlo para preguntar si queremos salir de la aplicación o no.
Eso se consigue simplemente deteniendo la propagación de la señal al sistema de eventos de GTK, o por el contrario dejamos a Gtk que siga su curso, en este caso, sería el salto a la señal destroy.

¿ Pero no habíamos conectado manualmente el destroy ? Cierto. Podemos conectarlo combinándolo glade, además, las señales que conectamos se suman a las existen no se eliminan, aunque yo jamás lo he realizado, la teoría es simple: Para un mismo evento de Gtk, se puede disparar una o varias señales.
( Un poco de teoría de Gtk tampoco viene mal ;-) )

Bueno, seguimos. ¿ Como le decimos que use las señales definidas en Glade ?

# From Glade, signal delete_event the window consultas,  at class Handler.
  self.glade.connect_signals( Handler() )
Ya está, muy simple. Esto lo que hace es que decirme que clase va a tratar los eventos.

Creamos la clase que quiero que procese las señales;

class Handler():
    def delete_event(self, widget,data=None):
        print( "Call from Glade." )
        # TIP:if you return 0 , destroy, but if you return 1, stop , not kill program
        # TODO: Here create dialog ask if I want exit program
        return 0

Esto lo he realizado a propósito para que veáis lo que podemos hacer.
Podía hacer realizado;
  self.glade.connect_signals( self )
Ahora es nuestra propia clase principal, lo que tendrá un método llamado delete_event que gestiona esa señal.

También se puede conectar señales de esta manera;

 #Create our dictionay and connect it
dic = { "delete_event" : self.delete_event,
 "destroy" : gtk.main_quit }
self.window.signal_autoconnect(dic)

Hasta aquí un poquito de PyGtk , Glade y sus señales.




jueves, 13 de marzo de 2014

Un nuevo proyecto, TinnyDb.



Como me gusta aprender Python, siempre me ha gustado compartir con la gente lo que voy descubriendo y de paso mostrar mis avances desde el inicio, de esta manera, otro pueda ir cogiendo el hilo poco a poco.

En este paso voy a realizar un pequeño programa para hacer consultas a MySQL a través de PyGtk.
Para ello, las pantallas estarán realizadas con Glade.

De esta manera, podemos ver un poco de todo, Python , POO, Gtk , Glade, conexión con MySQL, como montar las vistas, etc..

En esta entrada, veremos como descargar el código desde GitHub.
Si no usas Git como control de versiones, es una buena oportunidad de empezar.

No voy a explicar como instalar Python , PyGtk o las librerías de MySQL, porque hay excelentes post que explican como hacerlo, es cuestión de buscar por la web.

No sé cuanto tiempo ni el grado de complejidad que va a requerirme llevar a cabo el proyecto, lo que sí sé seguro, es que nos vamos a divertir ;-)

Para empezar a trastear  e ir abriendo boca, tenemos un poco de código, es muy simple, un par de clases con muy poquitas lineas, puedes descargarlo desde github:

git clone https://github.com/rafathefull/tinnydb.git

Podemos observar en el fichero login.py, la pantalla que ilustra este post, y que está contenido en el fichero tinnydb.ui que lo puedes abrir con Glade.

Para ejecutarlo, simplemente : python main.py

De momento, os dejo el código que he realizado en un par de horas, funcionando con conexión a datos.

En el siguiente entrega, explicaremos un poco como la clase login se conecta a MySQL y el uso de Glade desde Python a través de PyGtk.




domingo, 9 de marzo de 2014

Maneras de hacer en PyGTK( Python ) vs T-GTK ( Harbour )


El haber usado Glade para el diseño del GUI para mi programa de Maquinas-Herramientas, me ha va permitir aprender Python con PyGtk, muchos más rápido, porque las pantallas ya las tengo creadas.

De esta manera, todo el interface es reusable 100%.

Siempre he pensado que aprender un nuevo lenguaje haciendo simples funciones que muestran como hacer el factorial de un número es súper aburrido.

¿ A quién le resulta divertido "ver", de hecho no vas a ver un carajo, como funciona una función recursiva? ¿ De verdad te vas a sentir realizado viendo un puñado de números sin sentido ? ;-)

Por eso, voy a intentar portar mi programa a Python para aprender de él, y de paso, ver como evoluciona, y sentirme satisfecho de ver ventanas, botones, carga de datos en una vista, etc..

¿ A que suena mejor ? Como no, comparar un triste número en un interprete a ver una ventana que responde a tus acciones no tiene color ;-)

Esta es el código de la ventana de Login usando T-GTK


    SET RESOURCES pGlade FROM FILE "./gui/pol.ui"

    DEFINE WINDOW oWnd ID "inicio" RESOURCE pGlade

            DEFINE ENTRY VAR s_cUser      ID "entry_user"     RESOURCE pGlade
            DEFINE ENTRY VAR s_cPass      ID "entry_pass"     RESOURCE pGlade
            DEFINE ENTRY VAR s_cServer    ID "entry_server"   RESOURCE pGlade
            DEFINE SPIN  VAR s_nPort      ID "spin_port"      RESOURCE pGlade
            DEFINE ENTRY VAR s_cDBName    ID "entry_bd"       RESOURCE pGlade
            DEFINE LABEL oLabelInf        ID "information"    RESOURCE pGlade

            DEFINE BUTTON oBtn ID "btn_access" RESOURCE pGlade;
                          ACTION ( oBtn:Disable(),;
                                   IF( !empty( oServer := Connect_Db( oLabelInf )),( oWnd:End() ), ),;
                                   oBtn:Enable() )

            DEFINE BUTTON ID "btn_cancel" RESOURCE pGlade ACTION ( oWnd:End() )

    ACTIVATE WINDOW oWnd INITIATE


En PyGTK;

__author__ = 'rafa'

import pygtk
pygtk.require('2.0')
import gtk
import MySQLdb
import os

class Login:

    def __init__(self):

        """
        Ventana de acceso a la BD
        """

        self.conectado = False

        self.gladefile = "./gui/pol.ui"
        self.glade = gtk.Builder()
        self.glade.add_from_file(self.gladefile)

        #accediendo a los controles
        self.window = self.glade.get_object('inicio')
        self.window.connect("destroy", self.destroy)

        self.btn_access = self.glade.get_object('btn_access')

        # este salta a un method
        self.btn_access.connect("clicked", self.Conect_Db, None)

        self.btn_cancel = self.glade.get_object('btn_cancel')
        self.btn_cancel.connect("clicked", self.destroy )

        self.label = self.glade.get_object('information')

        self.entry_user   = self.glade.get_object('entry_user')
        self.entry_user.connect("key-press-event", self.on_key_press_event )

        self.entry_pass   = self.glade.get_object('entry_pass')
        self.entry_pass.connect("key-press-event", self.on_key_press_event )

        self.entry_server = self.glade.get_object('entry_server')
        self.entry_bd     = self.glade.get_object('entry_bd')
        self.spin_port    = self.glade.get_object('spin_port')

    def on_key_press_event(self, widget, event):
        keyname = gtk.gdk.keyval_name(event.keyval)

        if keyname == "Return" or keyname == "KP_Enter":
            widget.get_toplevel().child_focus(gtk.DIR_TAB_FORWARD)

    # Cuando destruimos la pantalla, si no estamos conectado, salimos de la aplicacion.
    def destroy(self, widget, data=None):
        if not self.conectado:
            gtk.main_quit()
            os.sys.exit (1)
        else:
            gtk.main_quit()

    def main(self):
        gtk.main()

        return 0

En parte , la ventaja de T-GTK, en este caso es de Harbour y su maravilloso Preprocesado , que nos permite crear comandos, "ocultando " el uso de clases, aunque por debajo, el trabajo realizado es similar a la librería de PyGtk.

Pero, he aquí donde la potencia de Glade:

        SET RESOURCES pGlade FROM FILE "./gui/pol.ui"
        DEFINE WINDOW oWnd ID "inicio" RESOURCE pGlade

en PyGtk;

        self.gladefile = "./gui/pol.ui"
        self.glade = gtk.Builder()
        self.glade.add_from_file(self.gladefile)

        #accediendo a los controles
        self.window = self.glade.get_object('inicio')
        self.window.connect("destroy", self.destroy)

En Harbour escribimos muchísimo menos para obtener lo mismo, gracias a su potente preprocesado.
Pero lo importante, es que convertir un programa en otro a través de Glade, es de una gran ayuda.

O por decirlo de otra manera, un diseñador puede hacer las pantallas, mientras el programador lo dota de funcionalidad.

Esta manera , la de separar GUI y funcionalidad, me encanta. ;-)


sábado, 8 de marzo de 2014

Ubuntu 10.04 y Git


Si usas Ubuntu 10.04 todavía, como yo, seguramente la última versión que vas a tener en el sistema de git será la  1.7.0.4.

Y eso es un problema si quieres usar PyCharm con git, pues simplemente no te dejará usar repositorios de git desde el entorno de programación

. Pues tan simple como esto:

sudo apt-get install python-software-properties
sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git

Ahora dispones en el sistema de la versión 1.9.0 ;-)
Seguimos jugando con Python....


viernes, 7 de marzo de 2014

Software Maquinas-Herramientas

Después de más de 2 años, sacrificando fin de semanas y tiempo libre, he podido pasar a una versión totalmente funcional.

El Sofware es capaz de cálcular :

  • Tornillos Sin Fin 
  • Corona
  • Metrico ISO
  • Fresas-Madres
  • Husillos
  • Engranajes Rectos y Helicoidales
  • Noyos

Las pantallas de cálculo son similares, por ejemplo, las del tornillo SINFIN y su CORONA;


A parte de calcular , también dispone de la realización de la orden de fabricación:

Y toda la gestión de albaranes con su correspondiente facturación;

La verdad, es que estoy muy satisfecho con el resultado final, a costado, pero al menos, objetivo cumplido. Video del estado de como estaba de avanzado del software y ver más o menos como funciona el programa en si, tanto en GNU/Linux como en Windows.





martes, 4 de marzo de 2014

Python, enamorado de la simplicidad.


Estaba yo trasteando con Python, y estaba traspasando unas clases de cálculos de mecánica y me he encontrado que he implementado esta linea de Python, la cual es asombrosamente simple y potente;

  def aproxima( self, aMatriz, nNumber):
      """
        Devuelve el valor que sea el más aproximado dentro del array a nNumber
      """
      return min( aMatriz, key=lambda x:abs( x - nNumber ) )

Tenía una rutina en Harbour , hace lo típico, recorre el array, me guardo el valor de la posición que cumple y después devuelvo el elemento de ese array según la posición, lo cual, después de 25 lineas más o menos de código fuente, obtenía el premio ;-)

Pero la linea en Python hace lo mismo, en UNA SOLA LINEA!
Me he quedado prendado. 

Aunque a veces su simplicidad y el 'paso de todo', como esto;

   class coche():
         pass
 
   coche = coche()

   coche.color = 'rojo'
   coche.puertas = 5


Pero esa simplicidad, a veces, te puede volver loco ;-)

Ah! Se me olvidaba, muy importante , TODO el código ordenado!!!

ODIO el tener que estar repasando códigos de otros y cada cual usa la indentación como le da la gana, y era reacio a su uso al principio, pero si usas código de otros, lo agradeces de todo corazón!!! ;-)

sábado, 22 de febrero de 2014

HARBOUR:Acelerando al viejo SET FILTER TO


Estaba yo con mis cosas, y repasando la lista de correo de harbour, leí que alguien ponía una función, llamada OrdWildSeek

Buscando más información sobre dicha función, me percaté enseguida, que haciendo un poco de malabares y con un indice CUSTOM, y sin apenas esfuerzos, podemos quitar nuestros SET FILTER, que por su utilidad estaban, pero que por su ineficacia no lo usaba prácticamente nadie.

Cada vez que he tenido que usar un LIKE en SQL, pasa por mi memoria el SET FILTER ;-)

¿ Y cual es la idea ? El idea es usar un sub-indice a partir del índice activo.
¿ Y como funciona ?

Pues a grandes rasgos y para que todo el mundo lo entienda;

  • SET FILTER TO , recurre TODO la DBF en busca de coincidencias.
    Ah!! y lo bonito que es ver que en el filtro hay solo 2 coincidencias separadas entre si por 200MB, el salto de un registro a otro es de "reír por no llorar" ;-)
  • OrWildSeek, recurre el FICHERO NTX ACTIVO, y nos va diciendo que registro cumple con el patrón que pasamos, y ahí es donde entramos nosotros con nuestro indices CUSTOMS


Ahora lo que más nos gusta, el código fuente.

Imagina que tenemos una tabla de clientes, y tenemos varios indices, y el 4, la expresión es nombre+apellidos.

Ahora, queremos obtener el nombre de SARAH. Pero no solo los que comienzan con SARAH, eso lo podemos solucionar rápidamente con un SCOPE, si no,  que forme parte de él, como;

  • ANGIE SARAH LOWE
  • SARAH CARMONA
  • JULIA SARAH SMITH
Eso se consigue , pasando el patrón "*"+Cadena+"?"

cNombre := "SARAH"

fast_filter( "*"+ alltrim( cNombre ) + "?", 4, 22, 28 )
Browse()


Ahora, ya estaría el filtro activado basado en subindices.

/* 
 Sustituto de SET FILTER
 cExpr  
    Expresion a buscar que forme parte del indice, podemos 
    poner *Texto? , para buscar palabra que forme parte

 nOrder
    Sobre que indice activo vamos a recorrer la lista.
    Por defecto es el indice activo.

 nRow, nCol 
     Posicion fila,columna para mostrar progreso. Se ejecuta en 
     un hilo aparte

 Return: Indice anterior

*/
function fast_filter( cExpr, nOrder, nRow, nCol )
      local PantaAnt := savescreen(0,0,MaxRow(),MaxCol())
      Local p := hb_threadStart( @Pajaritos(), nRow, nCol )
      Local nIndice := OrdNumber()

      DEFAULT nOrder TO OrdNumber()

      set order to nOrder
      INDEX ON &(IndexKey()) TAG _TEMP_ TO tHarbourt ;
               CUSTOM ADDITIVE MEMORY
       
      set order to nOrder
      go top

      DO WHILE OrdWildSeek( cExpr, .T. )
         OrdKeyAdd( "_TEMP_" )
      ENDDO
      OrdSetFocus( "_TEMP_" )
       
      hb_threadTerminateAll()
      restscreen(0 ,0 ,MaxRow(), MaxCol(), PantaAnt)

return nIndice

PROCEDURE Pajaritos( nRow, nCol )
        Local pajarito := "|",n := 0
        
        DEFAULT nRow := MaxRow(), nCol := 1

        DO WHILE .T.

           do case
              case n = 1 
                   pajarito = "|" 
              case n = 2 
                   pajarito = "/" 
              case n = 3  
                   pajarito = "-" 
              case n = 4 
                   pajarito = "\" 
              Otherwise 
                   n := 0
           end case

           DispOutAt( nRow, nCol, "Generando Consulta....[ " +  pajarito +" ]" ) //, "GR+/N" )
           ThreadSleep( 500 )
           n++
       ENDDO
RETURN


Creo que la función es muy simple y no necesita más explicación, el código habla por si mismo.
Lo único es que se crea un hilo para mostrar que se está haciendo alguna cosa.

Lo ideal sería que la función OrdWildSeek tuviese un codeblock para hacer llamada e ir mostrando un progreso, pero al no tenerlo, lo he ejecutado en un hilo aparte.

He de decir que me sorprende la velocidad, eso si, siempre teniendo en cuenta la cantidad de información a recorrer, avisados estáis.

Espero que os guste ;-)

Android y Git. Disponer del hash automáticamente.

Una de las cosas a las que estoy acostumbrado, es tener siempre en mi código, el hash/tag/versión del control de versiones que estoy usan...