martes, 18 de agosto de 2015

Practica No.2 Interfaz Gráfica (GUI) en Python

Actualmente uno de los pilares del diseño de aplicaciones es el poder realizar interfaces graficas de usuario o GUI amigables con el usuario y eficientes, de tal manera que se pueda interactuar adecuadamente con la aplicación, esto en muchos de los lenguajes de programación más conocidos y sobre todo en los orientados a objetos no es un problema y podemos encontrar muchos ejemplos en la red.

En un lenguaje tan sencillo de utilizar como Python llega a surgir la duda de si es posible realizar de forma adecuada una GUI y la respuesta es sí, de hecho existen muchos módulos que permiten realizar interfaces graficas de manera sencilla y muchas de ellas son variantes de librerías utilizadas en el lenguaje de programación C/C++.

A continuación se mostraran ejemplos de dos de los módulos más importantes y que son compatibles con la versión 3.4 de Python. Hay que aclarar que el propósito de este post no es dar una guía completa de todo lo que podemos realizar con estas librerías, sino más bien ejemplificar las instrucciones básicas para poder realizar la interfaz gráfica.

Tkinter

Tkinter es un módulo que ya viene incluido al momento de instalar Python, utiliza el conocido toolkit Tk, siendo muy robusto y sencillo de aprender. Al venir por defecto en cualquier instalación de Python es el más utilizado de todos, y a la vez el que cuenta con una mayor documentación.

Este módulo fue conocido en sus inicios por tener widgets poco atractivos, cosa que cambio con la versión 8.5 que se empezó a distribuir con la versión 2.6 de Python, el cual ya incluye cosas tan interesantes como textos con antialiasing o Treeview.

TkInter se distribuye bajo la PSFL (Python Software Foundation License) una licencia compatible con la GPL creada para la distribución de software relacionado con el proyecto Python. La PSFL carece de la naturaleza viral de la GPL, por lo que permite crear trabajos derivados sin que estos se conviertan necesariamente en software libre.

A continuación se describe una pequeña aplicación que cuenta con algunos de los elementos básicos de Tkinter:



En la imagen anterior podemos observar un ejemplo de GUI básica, primero que nada hay que importar el paquete lo cual se hace con la siguiente instrucción:

from tkinter import *  

De esta manera podemos acceder a todos los elementos que necesitamos para nuestra aplicación, para la creación de la ventana principal necesitamos dos funciones:

 
root = Tk()
root.mainloop() 

La primera instrucción hace que la variable root herede todas las funciones de Tkinter y la segunda permite la inicialización de la ventana y que esta sea desplegada, todos los códigos que queramos agregar a la ventana deberán agregarse entre estas dos líneas de código.

Para agregar los distintos elementos a la pantalla se realiza con una inicialización normal, como puede apreciarse en el siguiente código se pasan como parámetros la ventana donde queremos que aparezca el elemento y el nombre con el que queremos que se despliegue.

 
label = Label(frame, text="Hola mundo")
c1 = Checkbutton(frame, text="Uno")

Así mismo podemos modificar la configuración por default de los distintos elementos gráficos, cada uno de ellos tiene sus propios atributos configurables, en el ejemplo siguiente modificamos el color de fondo y de la letra de una etiqueta.

 
label.config(bg="cyan")
label.config(fg="blue")

El último tema a tratar en este post es como hacer que los elementos de la interfaz gráfica se despliegue como queramos, para esto tenemos dos opciones usando la instrucción pack() delegando al lenguaje donde los ubique pero nos asegura que se desplieguen completamente o bien haciéndonos cargos nosotros mismos utilizando la instrucción grid(), en este caso la ventana es tratada como un conjunto de renglones y columnas y nosotros debemos indicar directamente en qué posición queremos agregar nuestros elemento gráficos. 

El código fuente del ejemplo anterior se puede descargar desde aquí.

PyQt

PyQt es probablemente una de las opciones menos populares para realizar interfaces gráficas en Python, sin embargo es muy sencillo de utilizar y brinda varias posibilidades, para instalarlo basta con ir a la página oficial y descargar la opción adecuada a nuestra plataforma, al ser un binding de Qt aplicaciones destinadas a funcionar bajo KDE (que fue complementa diseñado en Qt) son fáciles e interesantes de realizar con este módulo.

Sin embargo no solo se puede utilizar en KDE, sino que es muy útil para todo tipo de aplicaciones multiplataforma, ya que desde la versión 4 utiliza widgets nativos para las distintas plataformas en vez de simplemente emular el aspecto de la plataforma sobre la cual se ejecuta.

Se distribuye con una licencia dual GPL/PyQt Commercial, es decir, que si vamos a publicar el código fuente y permitir a los usuarios modificar nuestra aplicación, podremos usar PyQt sin más preocupaciones. En caso contrario tendremos que pagar para obtener una licencia comercial.

A continuación se describe una pequeña aplicación que cuenta con algunos de los elementos básicos de PyQt:


Para utilizar adecuadamente esta librería necesitamos utilizar un enfoque orientado a objetos, antes que nada vamos a importar las librerías donde se encuentran los distintos elementos gráficos, para esto se utilizan las siguientes instrucciones, se pueden importar una gran cantidad de elementos gráficos mas, estos son solo un ejemplo:
 
from PyQt5 import QtGui,  QtCore
import sys
Para iniciar y definir los componentes de la interfaz gráfica utilizamos las siguientes sentencias:
 
app = QApplication
form = AppForm()
form.show()
app.exec_()
Con la primera definimos un atributo del tipo QApplication desde el cual ejecutaremos posteriormente nuestra aplicación, con la segunda instrucción definiremos un objeto del tipo de clase que tenemos que definir y sobre la cual agregaremos los elementos gráficos, la tercera instrucción despliega esos elementos y la cuarta instrucción permite la ejecución de la aplicación.

En esta ocasión utilizamos un objeto del tipo QBoxLayout para agregar los elementos y acomodarlos en la pantalla, también es posible utilizar el grid e indicar la posición de los elementos directamente, pero en este ejemplo no es considerado. Para agregar elementos a la ventana se realiza la siguiente parte de código:
 
page = QWidget()
self.button = QPushButton('Unir', page)
La primera instrucción crea el contenedor de todos los elementos de la interfaz gráfica de usuario, el cual se agregara a la ventana en sí misma, los elementos al momento de instanciarse deben indicar el nombre con el que aparecen y el elemento al que se agregaran, en este caso al contenedor, para agregar los distintos elementos a la ventana se agregan al QBoxLayout con la instrucción pack(), para que se acomoden de la mejor manera y finalmente el contenedor se agrega a la ventana.
vbox1 = QVBoxLayout()
vbox1.addWidget(self.label)
vbox1.addWidget(self.edit1)
vbox1.addWidget(self.button)
page.setLayout(vbox1)
Para cambiar los atributos de los componentes, hacemos referencia de la misma manera en que hacemos referencia a los atributos o métodos de una clase en leguaje orientado a objetos:
self.label.resize(self.label.sizeHint())
self.label.setPalette(palettef)
Lo mismo pasa con los eventos cuando al momento de presionar un botón queremos que ocurra cierta acción, los eventos deben definirse como métodos de la clase principal y agregarse a los botones de la siguiente manera:

def  Mostrar(self):
     QMessageBox.about(self, "Mensaje", "Text1 = %s, Text2 = %s" % (self.edit1.text(), self.edit2.text()))

self.button.clicked.connect(self.Mostrar)
El código fuente del ejemplo anterior se puede descargar desde aquí.

Otros módulos muy conocidos como wxPython,PyGTK no tienen todavía integración con Python 3.

miércoles, 12 de agosto de 2015

Practica No.1 Algoritmos de Ordenamiento

Ordenamiento de Burbuja
Este algoritmo de ordenamiento es de los más sencillos de implementar pero al mismo tiempo el que peor rendimiento tiene, consiste en ir comparando elemento por elemento del vector, de manera que se van intercambiando si están mal acomodados de modo que el valor más pequeño este en la primera posición, volver a comparar los elementos y así sucesivamente, hasta que todo el vector esta ordenado, el problema de este algoritmo es que al realizar las búsquedas siguientes, se vuelven a comparar los elementos ya ordenados, teniendo una complejidad:
$$\Omega(n^2)$$
A continuación se muestra la implementación de este algoritmo en Python:
def BubbleSort(vector):
    print("Algoritmo de Burbuja")
    tam=len(vector)
    for i in range(0,tam):
        for j in range (i+1,tam):
            if (vector[i] > vector[j]):
                temp = vector[i]
                vector[i] = vector[j]
                vector[j] = temp
    return vector

Ordenamiento de Selección

Este algoritmo consiste en encontrar el elemento de menor valor en la primera iteración y colocarlo en la primera posición, después encontrar el segundo menor y ponerlo en la segunda posición y así sucesivamente, hasta ordenar todo el vector, tiene la misma complejidad que el ordenamiento por burbuja, su implementación en Python se muestra a continuación:
def SelectionSort(vector):
    print("Algoritmo de Selección")
    tam=len(vector)
    for i in range(0,tam):
        minimo=i
        for j in range (i+1,tam):
            if (vector[minimo]>vector[j]):
                minimo=j
        temp = vector[i]
        vector[i] = vector[minimo]
        vector[minimo] = temp
    return vector

Ordenamiento de Inserción

Este algoritmo se basa en la idea de ir ordenado los elementos del vector de forma ordenada como se vayan recorriendo asumiendo que los elementos del lado izquierdo ya están ordenados adecuadamente, por lo que solo se necesita encontrar su posición en esos elementos, tiene la misma complejidad que los anteriores y su implementación se muestra a continuación:
def InsertionSort(vector):
    print("Algoritmo de Inserción")
    tam=len(vector)
    for i in range(1,tam):
        valor=vector[i]
        j=i-1
        while j>=0 and vector[j]>valor:
            vector[j+1] = vector[j]
            j=j-1
        vector[j+1]=valor
    return vector

Ordenamiento por Mezclas

Este algoritmo se basa en la técnica de divide y vencerás, el vector original se divide en dos, estas dos listas se ordenan de manera separada, volviéndose a dividir hasta que se obtiene vectores de un solo elemento, entonces consideramos que ya está ordenada. Cuando ambas listas están ordenada se juntan para formar el arreglo ordenado. Este Algoritmo tiene una complejidad de:
$$\Omega(n \log n)$$
Por lo cual ofrece un mejor rendimiento que los algoritmos anteriores. Este método requiere de dos funciones para su implementación una que divida el arreglo, la cual se muestra a continuación en Python:
def MergeSort(vector):
    tam=len(vector)
    if tam==1:
        return vector
    else:
        mitad = len(vector)//2
        mitizq = MergeSort(vector[:mitad])
        mitder = MergeSort(vector[mitad:])
        return Mezcla(mitizq,mitder)
Y una que permita unir los dos arreglos ordenados, esta función se muestra a continuación codificada en Python:
def Mezcla(mitizq,mitder):
    resultado = []
    i=0
    j=0
    tizq=len(mitizq)
    tder=len(mitder)
    while (i < tizq or j < tder):
        if(i >= tizq):
            resultado.append(mitder[j])
            j=j+1
        elif(j >= tder):
            resultado.append(mitizq[i])
            i=i+1
        elif(mitizq[i] < mitder[j]):
            resultado.append(mitizq[i])
            i=i+1
        else:
            resultado.append(mitder[j])
            j=j+1
    return resultado

Ordenamiento QuickSort 

Este es al algoritmo más eficiente de ordenamiento actualmente, y se basa en la recursividad, se escoge un elemento del vector que será considerado pivote y en base a este elemento, se crean dos listas una que contenga los elementos menores y otra que contenga los elementos mayores, este proceso se vuelve a repetir hasta que quedan arreglos de un solo momento, que es cuando ha quedado ordenado el arreglo.
El punto central de este algoritmo es encontrar un pivote adecuado ya que dependiendo de este, la complejidad del algoritmo puede variar desde ser $\Omega(n \log n)$ en el mejor de los casos, hasta $\Omega(n^2)$ en el peor de los casos, la implementación del algoritmo se muestra a continuación.
def QuickSort(vector,primero,ultimo):
    i = primero
    j = ultimo   
    pivote = (vector[i] + vector[j]) / 2
    while i < j:
        while vector[i] < pivote:
            i+=1
        while vector[j] > pivote:
            j-=1
        if i <= j:
            x = vector[j]
            vector[j] = vector[i]
            vector[i] = x
            i+=1
            j-=1
    if primero < j:
        vector = QuickSort(vector, primero, j)
    if ultimo > i:
        vector = QuickSort(vector, i, ultimo)
    return vector
El programa de prueba con la implementación de todos estos algoritmos se puede encontrar en el siguiente link
Los algoritmos de ordenamiento por mezclas y quicksort fueron realizados basándose en las implementaciones encontradas en los siguientes sitios:
Merge Sort
Quick Sort