Fuente: MundoGeek
En esta entrada veremos algunos de los toolkits para creación de interfaces gráficas de usuario (GUIs) con Python más populares: TkInter, wxPython, PyGTK y PyQt.
TkInter
TkInter (de TK Interface) es un módulo que nos permite construir interfaces gráficas de usuario multiplataforma en Python utilizando el conocido toolkit Tk. Python incluye este módulo por defecto, lo que hace que sea un tookit muy popular. TkInter, además, es robusto, maduro y muy sencillo de aprender y de utilizar, contando con una amplia documentación.
Por otro lado hasta la versión 8.5 Tk era famoso por lo poco atractivo de sus widgets (cosa que se podía solucionar hasta cierto punto gracias a Tile). No es hasta esta versión que contamos con cosas tan básicas como textos con antialiasing en X11 o widgets como Treeview. En esta versión también se incluye Tile por defecto, por lo que contamos con un mejor aspecto general para todas las plataformas.
Sin embargo Python no se distribuye con Tk 8.5 hasta la versión 2.6, por lo que, para versiones de Python anteriores, es necesario recompilar TkInter para Tk 8.5 por nuestra cuenta, o bien usar Tile si no necesitamos ninguna de las nuevas características.
Es más, para poder usar la mayor parte de las nuevas características de Tk 8.5 es necesario instalar una librería que actúe como wrapper de Ttk (el nombre con el que han dado en llamar al conjunto de los nuevos widgets y temas de Tk), como puede ser pyttk.
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.
Por último, veamos una pequeña aplicación de ejemplo escrita con TkInter, sin uso de eventos y con solo unos pocos widgets, que nos servirá para comparar el aspecto de los distintos toolkits.
from Tkinter import * root = Tk() frame = Frame(root) frame.pack() label = Label(frame, text="Hola mundo") c1 = Checkbutton(frame, text="Uno") c2 = Checkbutton(frame, text="Dos") entry = Entry(frame) button = Button(frame, text="Aceptar") label.pack() c1.pack() c2.pack() entry.pack() button.pack() root.mainloop()
Pros: Popularidad, sencillez, documentación.
Contras: Herramientas, integración con el sistema operativo, lentitud.
Recomendado para: ¿Prototipos rápidos?
wxPython
wxPython es un wrapper open source para el toolkit anteriormente conocido como wxWindows: wxWidgets. wxPython es posiblemente el toolkit para desarrollo de interfaces gráficas en Python más popular, superando incluso a TKinter, que, como comentamos, se incluye por defecto con el intérprete de Python. wxPython cuenta con más y mejores widgets que TKinter, y ofrece un muy buen aspecto en todas las plataformas, utilizando MFC en Windows y GTK en Linux.
wxPython cuenta además con herramientas muy interesantes como wxGlade, una aplicación RAD para diseñar las interfaces gráficas de forma visual.
Sin embargo, la API adolece de una cierta falta de consistencia y un estilo muy alejado de Python y más cercano a C++, ya que, de hecho, uno de sus objetivos es no distanciarse demasiado del estilo de wxWidgets. Esto ha provocado que hayan aparecido distintos proyectos para abstraer al programador de los entresijos del toolkit, como Dabo o Wax, aunque estos han tenido un éxito muy comedido.
Tanto wxPython como wxWidgets se distribuyen bajo una licencia «wxWindows Licence», que consiste esencialmente en una LGPL con la excepción de que las obras derivadas en formato binario se pueden distribuir como el usuario crea conveniente.
Algunos ejemplos de aplicaciones conocidas creadas con wxPython son DrPython, wxGlade, Boa Constructor, Stani’s Python Editor y ABC.
Finalmente, a continuación podéis consultar el código de la aplicación de ejemplo:
import wx class Frame(wx.Frame): def __init__(self): wx.Frame.__init__(self, parent=None) panel = wx.Panel(self) text = wx.StaticText(panel, -1, "Hola mundo") c1 = wx.CheckBox(panel, -1, label="Uno") c2 = wx.CheckBox(panel, -1, label="Dos") t = wx.TextCtrl(panel) b1 = wx.Button(panel, -1, label="Aceptar") sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(text, 0, wx.ALL, 0) sizer.Add(c1, 0, wx.ALL, 0) sizer.Add(c2, 0, wx.ALL, 0) sizer.Add(t, 0, wx.ALL, 0) sizer.Add(b1, 0, wx.ALL, 0) panel.SetSizer(sizer) panel.Layout() app = wx.App(redirect=True) Frame().Show() app.MainLoop()
Pros: Popularidad, herramientas, multiplataforma.
Contras: API muy poco pythonica.
Recomendado para: Desarrollo multiplataforma.
PyGTK
Posiblemente PyGTK sea la segunda opción más utilizada para la creación de interfaces gráficas con Python, solo por detrás de wxPython, con la que compite de tú a tú. PyGTK, como podemos suponer por su nombre, es un binding de GTK, la biblioteca utilizada para desarrollar GNOME.
PyGTK cuenta con una API muy clara, limpia y elegante y es, además, muy sencillo de aprender, solo superado en ese aspecto por Tkinter. PyGTK también cuenta con grandes herramientas para construir la interfaz de forma gráfica, como Glade o Gazpacho.
Un punto negativo es que, hasta hace poco, era necesario instalar X11 para poder usar PyGTK en Mac OS, dado que GTK no había sido portado. Actualmente se puede utilizar el GTK+ OS X Framework que se encuentra todavía en versión beta.
PyGTK se distribuye bajo licencia LGPL.
Algunas aplicaciones escritas con PyGTK son Deluge, Exaile, Listen, Envy, WingIDE, DeVeDe o emesene.
Veamos el código de la aplicación de ejemplo en PyGTK:
import pygtk import gtk window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.connect("destroy", gtk.main_quit) box = gtk.VBox(False, 0) window.add(box) label = gtk.Label("Hola Mundo") c1 = gtk.CheckButton(label="Uno") c2 = gtk.CheckButton(label="Dos") entry = gtk.Entry() button = gtk.Button("Aceptar") box.add(label) box.add(c1) box.add(c2) box.add(entry) box.add(button) window.show_all() gtk.main()
Pros: Popularidad, sencillez, herramientas.
Contras: Ligeramente más complicado de instalar y distribuir en Mac OS.
Recomendado para: Cualquier tipo de aplicación. Especialmente interesante para Gnome.
PyQt
Es posible que PyQt, el binding de Qt para Python, sea la menos popular de las cuatro opciones, aunque es un toolkit sencillo de utilizar y con muchas posibilidades. Es especialmente interesante para el desarrollo en KDE, dado que Qt es la librería utilizada para crear este entorno.
No obstante el interés en Qt no se limita a KDE, sino que es una biblioteca multiplataforma que, además, desde la versión 4, utiliza widgets nativos para las distintas plataformas (anteriormente Qt emulaba el aspecto de la plataforma en la que corría).
Como aplicación de RAD se puede utilizar Qt Designer.
PyQt utiliza un modelo de licencias similar al de Qt, con una licencia dual GPL/PyQt Commercial. Si nuestro programa es compatible con la licencia GPL, es decir, 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.
Un par de ejemplos de aplicaciones que usan PyQt son Eric y QTorrent.
El código de la aplicación de ejemplo en PyQt tendría el siguiente aspecto:
import sys from PyQt4.QtCore import * from PyQt4.QtGui import * class Form(QWidget): def __init__(self): QWidget.__init__(self) layout = QVBoxLayout() layout.addWidget(QLabel("Hola mundo")) layout.addWidget(QCheckBox("Uno")) layout.addWidget(QCheckBox("Dos")) layout.addWidget(QLineEdit()) layout.addWidget(QPushButton("Aceptar")) self.setLayout(layout) app = QApplication(sys.argv) form = Form() form.show() app.exec_()
Pros: Sencillez, herramientas, multiplataforma.
Contras: Ligeramente más complicado de instalar y distribuir en Mac OS. Licencia.
Recomendado para: Cualquier tipo de aplicación. Especialmente interesante para KDE.
¿Alguien podría ayudarme con el proceso de instalación del wxpython o el pygtk?
Lo que pasa es que ya los descargué y los instale pero me marca error al compilar el programa porque al parecer no encuentra las librerias, me marca errores como «ImportError: No module named wx». Ya intente solucionarlo de varias formas y no logro encontrar la solución que me permita correr mis programas.
Estoy trabajando con el Wing IDE 101 versión 3.2.1. Ojala alguien pueda ayudarme.
Hola,te felicito por la documentacion, es muy util para quienes empezamos, hojala puedas ayudarme, pretendo hacer una agenda basica para practicar con PyQT4 y MySQL usando MySQLdb como driver para MySQL, pero ignoro como realizar la conexion de los LineEdit hacia los campos hecho en MySQL, envio mis dos scripts el primero es la interface grafica de la agenda (solo es el ingreso de datos, no consulta…..aun), esto hecho por el momento desde windows, espero en breve poderlo hacer desde linux,agradezco cualquier aporte.
from PyQt4 import QtCore, QtGui
class Ui_dlgAgenda(object):
def setupUi(self, dlgAgenda):
dlgAgenda.setObjectName(«dlgAgenda»)
dlgAgenda.setWindowModality(QtCore.Qt.NonModal)
dlgAgenda.setEnabled(True)
dlgAgenda.resize(562, 453)
dlgAgenda.setCursor(QtCore.Qt.ArrowCursor)
dlgAgenda.setFocusPolicy(QtCore.Qt.StrongFocus)
dlgAgenda.setAutoFillBackground(False)
self.label = QtGui.QLabel(dlgAgenda)
self.label.setGeometry(QtCore.QRect(21, 81, 109, 25))
self.label.setObjectName(«label»)
self.label_2 = QtGui.QLabel(dlgAgenda)
self.label_2.setGeometry(QtCore.QRect(21, 112, 109, 26))
self.label_2.setObjectName(«label_2»)
self.label_3 = QtGui.QLabel(dlgAgenda)
self.label_3.setGeometry(QtCore.QRect(21, 144, 109, 25))
self.label_3.setObjectName(«label_3»)
self.label_4 = QtGui.QLabel(dlgAgenda)
self.label_4.setGeometry(QtCore.QRect(21, 175, 109, 25))
self.label_4.setObjectName(«label_4»)
self.label_5 = QtGui.QLabel(dlgAgenda)
self.label_5.setGeometry(QtCore.QRect(21, 206, 109, 26))
self.label_5.setObjectName(«label_5»)
self.label_6 = QtGui.QLabel(dlgAgenda)
self.label_6.setGeometry(QtCore.QRect(21, 238, 109, 25))
self.label_6.setObjectName(«label_6»)
self.label_7 = QtGui.QLabel(dlgAgenda)
self.label_7.setGeometry(QtCore.QRect(21, 269, 109, 26))
self.label_7.setObjectName(«label_7»)
self.label_8 = QtGui.QLabel(dlgAgenda)
self.label_8.setGeometry(QtCore.QRect(21, 301, 109, 25))
self.label_8.setObjectName(«label_8»)
self.label_9 = QtGui.QLabel(dlgAgenda)
self.label_9.setGeometry(QtCore.QRect(21, 332, 109, 25))
self.label_9.setObjectName(«label_9»)
self.label_10 = QtGui.QLabel(dlgAgenda)
self.label_10.setGeometry(QtCore.QRect(21, 363, 109, 26))
self.label_10.setObjectName(«label_10»)
self.label_11 = QtGui.QLabel(dlgAgenda)
self.label_11.setGeometry(QtCore.QRect(21, 395, 109, 25))
self.label_11.setObjectName(«label_11»)
self.txtName1 = QtGui.QLineEdit(dlgAgenda)
self.txtName1.setGeometry(QtCore.QRect(159, 79, 113, 20))
self.txtName1.setObjectName(«txtName1»)
self.txtName2 = QtGui.QLineEdit(dlgAgenda)
self.txtName2.setGeometry(QtCore.QRect(299, 79, 113, 20))
self.txtName2.setObjectName(«txtName2»)
self.txtLast2 = QtGui.QLineEdit(dlgAgenda)
self.txtLast2.setGeometry(QtCore.QRect(300, 120, 113, 20))
self.txtLast2.setObjectName(«txtLast2»)
self.txtLast1 = QtGui.QLineEdit(dlgAgenda)
self.txtLast1.setGeometry(QtCore.QRect(160, 120, 113, 20))
self.txtLast1.setObjectName(«txtLast1»)
self.txtPhone1 = QtGui.QLineEdit(dlgAgenda)
self.txtPhone1.setGeometry(QtCore.QRect(160, 150, 251, 21))
self.txtPhone1.setObjectName(«txtPhone1»)
self.txtCell = QtGui.QLineEdit(dlgAgenda)
self.txtCell.setGeometry(QtCore.QRect(160, 180, 251, 21))
self.txtCell.setObjectName(«txtCell»)
self.txtEmail1 = QtGui.QLineEdit(dlgAgenda)
self.txtEmail1.setGeometry(QtCore.QRect(160, 210, 251, 21))
self.txtEmail1.setObjectName(«txtEmail1»)
self.txtAddress = QtGui.QLineEdit(dlgAgenda)
self.txtAddress.setGeometry(QtCore.QRect(160, 240, 251, 21))
self.txtAddress.setObjectName(«txtAddress»)
self.txtJob = QtGui.QLineEdit(dlgAgenda)
self.txtJob.setGeometry(QtCore.QRect(160, 270, 251, 21))
self.txtJob.setObjectName(«txtJob»)
self.txtArea = QtGui.QLineEdit(dlgAgenda)
self.txtArea.setGeometry(QtCore.QRect(160, 300, 251, 21))
self.txtArea.setObjectName(«txtArea»)
self.txtExtension = QtGui.QLineEdit(dlgAgenda)
self.txtExtension.setGeometry(QtCore.QRect(300, 340, 113, 20))
self.txtExtension.setObjectName(«txtExtension»)
self.txtPhone2 = QtGui.QLineEdit(dlgAgenda)
self.txtPhone2.setGeometry(QtCore.QRect(160, 340, 113, 20))
self.txtPhone2.setObjectName(«txtPhone2»)
self.txtFax = QtGui.QLineEdit(dlgAgenda)
self.txtFax.setGeometry(QtCore.QRect(160, 370, 251, 21))
self.txtFax.setObjectName(«txtFax»)
self.txtEmail2 = QtGui.QLineEdit(dlgAgenda)
self.txtEmail2.setGeometry(QtCore.QRect(160, 400, 251, 21))
self.txtEmail2.setObjectName(«txtEmail2»)
self.label_13 = QtGui.QLabel(dlgAgenda)
self.label_13.setGeometry(QtCore.QRect(180, 20, 191, 41))
self.label_13.setFrameShape(QtGui.QFrame.Box)
self.label_13.setTextFormat(QtCore.Qt.RichText)
self.label_13.setObjectName(«label_13»)
self.btnAceptar = QtGui.QPushButton(dlgAgenda)
self.btnAceptar.setGeometry(QtCore.QRect(431, 146, 109, 25))
self.btnAceptar.setObjectName(«btnAceptar»)
self.btnCancelar = QtGui.QPushButton(dlgAgenda)
self.btnCancelar.setGeometry(QtCore.QRect(431, 212, 109, 25))
self.btnCancelar.setObjectName(«btnCancelar»)
self.btnCerrar = QtGui.QPushButton(dlgAgenda)
self.btnCerrar.setGeometry(QtCore.QRect(431, 278, 109, 25))
self.btnCerrar.setObjectName(«btnCerrar»)
self.retranslateUi(dlgAgenda)
QtCore.QMetaObject.connectSlotsByName(dlgAgenda)
dlgAgenda.setTabOrder(self.txtName1, self.txtName2)
dlgAgenda.setTabOrder(self.txtName2, self.txtLast1)
dlgAgenda.setTabOrder(self.txtLast1, self.txtLast2)
dlgAgenda.setTabOrder(self.txtLast2, self.txtPhone1)
dlgAgenda.setTabOrder(self.txtPhone1, self.txtCell)
dlgAgenda.setTabOrder(self.txtCell, self.txtEmail1)
dlgAgenda.setTabOrder(self.txtEmail1, self.txtAddress)
dlgAgenda.setTabOrder(self.txtAddress, self.txtJob)
dlgAgenda.setTabOrder(self.txtJob, self.txtArea)
dlgAgenda.setTabOrder(self.txtArea, self.txtPhone2)
dlgAgenda.setTabOrder(self.txtPhone2, self.txtExtension)
dlgAgenda.setTabOrder(self.txtExtension, self.txtFax)
dlgAgenda.setTabOrder(self.txtFax, self.txtEmail2)
dlgAgenda.setTabOrder(self.txtEmail2, self.btnAceptar)
dlgAgenda.setTabOrder(self.btnAceptar, self.btnCancelar)
dlgAgenda.setTabOrder(self.btnCancelar, self.btnCerrar)
#
def retranslateUi(self, dlgAgenda):
dlgAgenda.setWindowTitle(QtGui.QApplication.translate(«dlgAgenda», «Agenda», None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Nombre(s):», None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Apellido(s):», None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Telefono:», None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Celular:», None, QtGui.QApplication.UnicodeUTF8))
self.label_5.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Email:», None, QtGui.QApplication.UnicodeUTF8))
self.label_6.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Direccion:», None, QtGui.QApplication.UnicodeUTF8))
self.label_7.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Empresa:», None, QtGui.QApplication.UnicodeUTF8))
self.label_8.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Departamento:», None, QtGui.QApplication.UnicodeUTF8))
self.label_9.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Telefono/Extension», None, QtGui.QApplication.UnicodeUTF8))
self.label_10.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Fax:», None, QtGui.QApplication.UnicodeUTF8))
self.label_11.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Email empresa:», None, QtGui.QApplication.UnicodeUTF8))
self.label_13.setText(QtGui.QApplication.translate(«dlgAgenda», «\n»
«\n»
«p, li { white-space: pre-wrap; }\n»
«\n»
«Agenda Personal», None, QtGui.QApplication.UnicodeUTF8))
self.btnAceptar.setText(QtGui.QApplication.translate(«dlgAgenda», «Aceptar», None, QtGui.QApplication.UnicodeUTF8))
self.btnCancelar.setText(QtGui.QApplication.translate(«dlgAgenda», «Cancelar», None, QtGui.QApplication.UnicodeUTF8))
self.btnCerrar.setText(QtGui.QApplication.translate(«dlgAgenda», «Cerrar», None, QtGui.QApplication.UnicodeUTF8))
if __name__ == «__main__»:
import sys
app = QtGui.QApplication(sys.argv)
dlgAgenda = QtGui.QDialog()
ui = Ui_dlgAgenda()
ui.setupUi(dlgAgenda)
dlgAgenda.show()
sys.exit(app.exec_())
mi conexion la estoy haciendo desde otro script con el cual quiero inicializar la conexion a la base de datos y proporcionar las fucniones del formulario hacia la base de datos
import sys
from PyQt4 import QtCore,QtGui
import MySQLdb
db=MySQLdb.connect(host=’localhost’,user=’root’,passwd=’passwd’,db=’test’)
cursor=db.cursor()
from pymarko.forms.agenda import Ui_dlgAgenda
class dlgAgenda(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.iu=Ui_dlgAgenda()
self.iu.setupUi(self)
# Aqui la coneccion de los txtLine Edit con funciones del dialogo
# Hacia la base de datos, la cual con UN SOLO ejemplo me vendria bien para
# Continuar trasteando con PyQT
if __name__==»__main__»:
app=QtGui.QApplication(sys.argv)
myapp=dlgAgenda()
myapp.show()
sys.exit(app.exec_())
Hojala puedan darme una idea para continuar con esto…..muchas gracias.
me falto agregar que la tabla se llama ‘agenda’ y esta dentro de la base de datos ‘test’
y la cree de la siguiente manera
import MySQLdb
db=MySQLdb.connect(host=’localhost’,user=’root’,passwd=’passwd’,db=’test’)
cursor=db.cursor()
sql=(‘create table agenda2(nombre1 varchar(30),nombre2 varchar(30),apellido1 varchar(30),apellido2 varchar(30),telefono1 int(15),celular int(15),email1 varchar(100),direccion varchar(100),empresa varchar(100),departamento varchar(60),telefono2 int(15),extension int(15),fax int(15),email2 varchar(100))’)
cursor.execute(sql)
Gracias!
Hola,
Muy interesante tu post. Muchas gracias por compartirlo.
Quisiera saber si conoces cuales de estos modulos de desarrollo para interfaz grafica en Python 3.x estan disponibles?
Es que googleando me he topado con que solo estan disponibles en su mayoria para 2.x, a excepcion de tkinter que si viene por default en las versiones 3.x
De antemano gracias por tu ayuda!! 🙂