====== 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 =====