====== PyQt 4 ====== PyQt es un binding de Python para el framework de aplicaciones de Nokia Qt. \\ Para Python actualmente existen el PyQt 4 y el PyQt 3. \\ Los principales módulos son: * **QtCore**, el núcleo con las clases que no corresponden a GUIs (eventos, threads, ficheros, expresiones regulares...). * **QtGui** que contiene la mayoría de las clases para crear GUIs. * **QtHelp** que contiene clases para crear visores de "ayudas" para las aplicaciones. * **QtNetwork** que contiene clases para escribir UDP\TCP clientes y servidores. * Además de **QtOpenGL**, **QtScript** (intérprete de JavaScript), **QtSql**, **QtSvg**, **QtTest** (para unit tests), **QtWebKit** (para implementar un navegador web), **QtXml**, **QtXmlPatterns** (para modelos de datos Xml), **QtMultimedia**, **QtDesigner** (para utilizar el diseñador de Qt), **QAxContainer** (para implementar objetos COM y ActiveX)... Y también algunas utilidades como: * **pyuic4**, que convierte las GUIs creadas con el Qt Designer en código Python. * **pyrcc4** que agrega recursos en un fichero. * **pylupdate4** para trabajar con strings de lenguaje. \\ \\ La documentación para Qt4 se encuentra en [[http://doc.qt.nokia.com/4.0/]] y para PyQt4 en [[http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/classes.html]]. ===== Aplicaciones con PyQt4 ===== ==== Básico ==== === QApplicaction === Los objetos que representan aplicaciones basadas en Qt se crean a partir de la clase **QtGui.QApplication**, una vez tenemos uno de estos objetos podremos gestionar los eventos de la aplicación, su flujo de control, su configuración... \\ Para construir un objeto lo podemos hacer a partir de su constructor ''__init__ (self, list-of-str argv)'', este inicializará el sistema de ventanas Qt, la aplicación y tomará como argumentos los argumentos pasados a la aplicación. Si quisieramos construir una aplicación podríamos utilizar el constructor ''__init__ (self, list-of-str argv, bool GUIenabled)'' asignando ''GUIenabled'' a ''false''· \\ El método ''int QApplication.exec_ ()'' crea y entra en el bucle principal de la aplicación hasta que se llame a ''quit()'' o a ''exit()'', entonces devuelve el valor que se pasó a ''exit()'' o ''0'' si se llamó a ''quit()''. app = QtGui.QApplication(sys.argv) ... sys.exit(app.exec_()) === QWidget's === La clase **QWidget** es la clase base para todos los objetos que permiten formar un entorno gráfico. Recibe los eventos del mouse, del keyboard, del sistema, de pintado... Todo widget es rectangular y están ordenado (a la hora de dibujarse por pantalla) en un //z-order//, aunque está delimitado por el widget-padre que lo contiene, el único widget que no tendría padre sería una ventana; generalmente las ventanas tienen "un frame" y una barra de título (en Qt puedes encontrarte clases como **QMainWindow** o **QDialog** que son las más adecuadas para este tipo de widgets). \\ Cada constructor de un widget acepta uno o dos argumentos por defecto: - ''QWidget *parent = 0'', es el padre del widget creado. Si es 0 (por defecto), el widget será una venta, si no el widget creado será un hijo del indicado y estará delimitado por este. - ''Qt.WindowFlags f = 0'' asigna las flags de ventana. import sys from PyQt4 import QtGui app = QtGui.QApplication(sys.argv) widget = QtGui.QWidget() widget.resize(250, 150) widget.setWindowTitle('simple') btn = QtGui.QPushButton("Press", widget) widget.show() sys.exit(app.exec_()) Podemos también hacerlo OO: class MyWindow(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) quitbutton = QtGui.QPushButton('Close', self) self.setCentralWidget(quitbutton) qApp = QtGui.QApplication(sys.argv) w = MyWindow() w.show() sys.exit(qApp.exec_()) === Eventos (signal & slots) === Los **signals** se emiten por un objeto cuando algo cambia en él, se podría decir que son los eventos. Cuando un signal es emitido los slots que se conectan a él se ejecutan como si fuese una llamada a función, si hubiese varios conectados se ejecutarían en un orden arbitrario. \\ El formato (general) para realizar una conexión signal-slot es: QtCore.QObject.connect(objeto, QtCore.SIGNAL("método"), nombre_funcion) Por ejemplo: import sys from PyQt4 import QtCore from PyQt4 import QtGui def bclicked(): print "Button Clicked" qApp = QtGui.QApplication(sys.argv) button = QtGui.QPushButton("Click Me") QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), bclicked) button.show() sys.exit(qApp.exec_()) Aunque a partir de la versión 4 también existe la siguiente forma (a partir de una propiedad creada con el mismo nombre que el signal): button.clicked.connect(clicked) U otra forma, utilizando el decorador ''signal'': button = QtGui.QPushButton("Click Me") button.show() @button.clicked.connect def btnclicked(): print "Button Clicked" Para crear nuestros propios Signals: import sys from PyQt4 import QtCore from PyQt4 import QtGui class MyWindow (QtGui.QWidget): mySignal = QtCore.pyqtSignal() def __init__(self): QtGui.QMainWindow.__init__(self) self.button = QtGui.QPushButton("Click Me", self) self.button.clicked.connect(self.btnclicked) self.i = 0 def btnclicked(self): print "Button Clicked" self.i = self.i + 1 if (self.i > 2): self.mySignal.emit() def myTooMuch(): print 'Too Much' qApp = QtGui.QApplication(sys.argv) w = MyWindow() w.mySignal.connect(myTooMuch) w.show() sys.exit(qApp.exec_()) Para enviar parámetros tendremos que cambiar las siguientes líneas: mySignal = QtCore.pyqtSignal(int) ... self.mySignal.emit(self.i) ... def myTooMuch(v): print 'Too Much: ' + str(v) ==== Creación de GUIs ==== === Layouts === Los Layout ayudan a organizar la distribución de los constroles (widgets) en una ventana. Para utilizarlos en Qt simplemente has de agregarlos a la ventana y a este los widgets mediante el método ''addWidget'': class MyWindow (QtGui.QWidget): def __init__(self): QtGui.QMainWindow.__init__(self) self.layout1 = QtGui.QVBoxLayout(self) self.button1 = QtGui.QPushButton("Click Me") self.button2 = QtGui.QPushButton("Click Me") self.layout1.addWidget(self.button1) self.layout1.addWidget(self.button2) {{ fw:pyqt4:layout1.png |}} Existen varios métodos de layout: * **QVBoxLayout**: Donde los elementos se muestran en vertical. * **QHBoxLayout**: Donde los elementos se muestran en horizontal. * **QGridLayout**: Donde los elementos se colocan en una tabla (con 'x' e 'y'). self.grid = QtGui.QGridLayout() self.setLayout(self.grid) self.grid.addWidget(QtGui.QLabel("HOLA"), 0, 0) self.grid.addWidget(QtGui.QLabel("ADIOS"), 1, 1) self.grid.addWidget(QtGui.QLabel("ARREVOIRE"), 2, 2) self.grid.addWidget(QtGui.QLabel("Yey!"), 2, 0) === GUIs con el Qt4 Designer === El Qt4 Designer es una herramienta que puedes instalar y que te permite crear GUIs de forma rápida e intuitiva. Como Qt es un framework ideado para C\C++ el archivo resultado, con extensión .ui, tendrá que ser pasado a Python, para ello utilizaremos el comando ''pyuic4'': pyuic4 untitled.ui -o window.py Una vez tengamos el archivo .py lo colocaremos en la misma carpeta y haremos un import de la clase resultado, según el tipo que hayamos creado podremos tratarla de varias formas: from window import Ui_Form class MyWindow (QtGui.QWidget): def __init__(self): QtGui.QWidget.__init__(self) self.gui = Ui_Form() self.gui.setupUi(self) self.gui.pushButton.clicked.connect(self.btnClick) def btnClick (self): print "a" === Qt Style Sheets === Las Qt Style Seets son otra forma de personalizar la apariencia de los widgets y están basadas en las CSS ([[http://doc.qt.nokia.com/4.6/stylesheet-reference.html|referencia]]). self.setStyleSheet("QWidget { background-color: rgb(255, 255, 255); background-image: url(heart.png); border-top:5px solid rgb(255, 170, 255); }") Pueden ser definidas.. QComboBox { margin-right: 20px; } QComboBox::drop-down { subcontrol-origin: margin; } QComboBox::down-arrow { image: url(down_arrow.png); } QComboBox::down-arrow:pressed { position: relative; top: 1px; left: 1px; } === Clases básicas === * **QGui.QDesktopWidget**: Permite el acceso a información del escritorio (número de pantallas, resolución...). === Clases de Widgets === ===== Creación avanzada de aplicaciones ===== ==== Paint & QImages ==== === Pintar sobre QWidgets === Para poder pintar sobre un QWidget lo haremos sobreescribiendo el método ''paintEvent'' de este y mediante los métodos de un objeto **QPainter**, lo crearemos y luego, entre sus los métodos ''begin'' (al cual le tendremos que pasar el QWidget sobre el cual pintaremos) y ''end'' llevaremos a cabo los métodos de pintar: class MyWindow(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) def paintEvent(self, event): paint = QtGui.QPainter() paint.begin(self) paint.setPen(QtGui.QColor(168, 34, 3)) paint.setFont(QtGui.QFont('Verdana', 23)) paint.drawText(event.rect(), QtCore.Qt.AlignCenter, "Pintooo!") paint.drawRect(100, 100, 200, 200) paint.fillRect(150, 150, 199, 199, QtGui.QColor(255,0,0)) paint.drawImage(QtCore.QRect(0,0, 80, 80), QtGui.QImage("heart.png")) paint.end() El método **repaint()** de un QWidget hará que se vuelva a llamar al método ''paintEvent''. === La clase QImage === Podemos obtener imágenes escaladas a partir de su método ''scaled'': image = QImage("/path/to/image") thumbnail1 = image.scaled(10, 10) Podemos pintar sobre una QImage con el QPainter: def paintEvent(self, event): i = QtGui.QImage(event.rect().width(), event.rect().height(), QtGui.QImage.Format_ARGB32) ipaint = QtGui.QPainter() ipaint.begin(i) ipaint.drawImage(event.rect(), QtGui.QImage("heart.png")) ipaint.end() paint = QtGui.QPainter() paint.begin(self) paint.drawImage(event.rect(), i); paint.end() === Notas sobre imágenes === * Podemos mostrar imágenes a partir de QLabels asignando su propiedad ''PixMap'': self.lbl = QtGui.QLabel(self) qPixMap = QtGui.QPixmap.fromImage(QtGui.QImage("heart.png")) self.lbl.setPixmap(qPixMap) * Podemos, también, descargar una imágen y mostrarla: class MyWindow(QtGui.QWidget): def __init__(self): QtGui.QWidget.__init__(self) self.lbl = QtGui.QLabel(self) self.url = QtNetwork.QHttp() self.url.done.connect(self.showImage) self.url.setHost('sonfamosos.com') self.url.get('/wp-content/uploads/2009/12/hulk-hogan.jpg') def showImage(self): img = QtGui.QImage.fromData(self.url.readAll(), 'JPG') self.lbl.setPixmap(QtGui.QPixmap.fromImage(img)) self.lbl.resize(img.width(), img.height()) ===== Otros módulos en PyQt =====