Descargar la presentación
La descarga está en progreso. Por favor, espere
Publicada porPurificación Mendoza Hernández Modificado hace 8 años
1
Introducción a programación de aplicaciones de escritorio con Python y Qt: PyQt Luis Alberto Pérez luis.perez@neodoo.es Septiembre de 2011
2
Algunos frameworks y librerías para programación de GUIs ● Tkinter – capa sobre Tcl/Tk. En la librería estándar de python ● PyGtk – Bindings para GTK ● PyQT – Bindings para QT ● PySide – Bindings para QT, de Nokia ● wxPython – toolkit sobre wxWidgets ● PyjamasDesktop – Port para escritorio de Pyjamas, framework de desarrollo de aplicaciones web Para más información: http://wiki.python.org/moin/GuiProgramming
3
¿Qué es QT? ● Multiplataforma, incluye soporte para Windows, MacOS/X y Linux ● C++ ● Gran toolkit, con abstracciones para sockets, threads, cadenas unicode, acceso a bases de datos, SVG, etc, además de una amplia librería de “widgets”. ● Usado por: ● KDE (“K” Desktop Environment) ● Eric Python IDE ● Skype ●...
4
¿Qué es PyQt? ¿Por qué? ● Bindings para QT, desarrollados y mantenidos por Riverbank computing. ● Bindings sobre Qt usando SIP ● Licencia dual GPL / Comercial ● Versiones para Qt 4 y Qt 3 y anteriores ● Estado actual y versiones que usaremos
5
Instalación ● En linux: apt ● libqt4-dev ● qt4-designer ● python-qt4 ● pyqt4-dev-tools ● En windows: se ofrecen instaladores binarios ● http://www.riverbankcomputing.com/software/ pyqt/download
6
Componentes de PyQt ● QtCore: Contiene clases que no son del GUI, como el event loop, el mecanismo de signals y slots, threads, etc. ● QtGui: Clases del GUI ● QtHelp: Clases para crear y visualizar ayudas ● QtNetwork: Clases para crear clientes y servidores de red. ● QtOpenGL: Para renderizar gráficos 3D con OpenGL ● QtScript y QtScriptTools: Para poder usar el interprete de JavaScript de Qt. ● QtSql: Para integración con bases de datos ● QtSvg: Para visualizado de SVG ● QtTest: Módulo de apoyo para hacer unit testing de PyQt ● QtWebKit: Implementa un browser basado en el motor WebKit
7
Componentes de PyQt (II) ● QtXml y QtXmlPatterns: SAX, DOM, XQuery y Xpath ● QtDeclarative:Uso de QML en PyQt, sistema declarartivo de construcción de interfaces ● QtDesigner: permite extender el Qt Designer usando PyQt ● Qt: Modulo que importa todas las clases de todos los paquetes de pyqt ● Dbus.mainloop.qt: Soporte para Dbus (Solo para X11) ● uic: Soporte para archivos.ui generados por Qt Designer ● Pyqtconfig: Encapsula información acerca de la instalación de pyqt y facilita la construcción de scripts de build para bindings sobre PyQt.
8
Hello world! Hello.py import sys from PyQt4 import QtGui app = QtGui.QApplication(sys.argv) widget = QtGui.QWidget() widget.resize(250, 150) widget.setWindowTitle('Hello window') widget.show() sys.exit(app.exec_())
9
Algunas clases importantes ● El api de Qt es muy extensa, y parte de ella puede resultar redundante con la librería estandar de python, y menos “pythonic”, pero se integra muy bien (ej: las clases de networking se integran con el event loop del GUI) ● QObject ● QWidget ● QEvent, QEventLoop ● QString, QBitArray, QChar, Qdate,... ● QThread, QTimer
10
Widgets comunes ● QMainWindow ● QLabel, QComboBox, QcheckBox, QLineEdit QradioButton, Qdial, QpushButton, QtabWidget, QtableWidget, QprogressBar, Qsplitter... ● QDialog, QDialogButtonBox ● Ver widgets.py
11
Herramientas ● Qt Designer: Herramienta para crear interfaces gráficos visualmente
12
Herramientas (II) ● pyuic4: Equivalente a la utilidad uic de Qt para convertir GUIs creados con Qt Designer en código python ● pyrcc4: Equivalente a la utilidad rcc de Qt para embeber recursos (iconos, imágenes, ficheros de traducciuones) en un módulo python ● pylupdate4: Equivalente a la utilidadd lupdate de Qt. Extrae las posibles cadenas traducibles del código python y crea o acualiza ficheros.ts, que son usados por Qt Linguist para gestionar las traducciones.
13
Usando Qt designer ● Se compila mediante pyuic4 pyuic4 window.ui -o windowUi.py ● Se pueden cargar archivos.ui al vuelo usando el módulo uic ● Evitar modificar manualmente el.ui o el.py generado! ● Para usar el módulo generado por pyuic4, basta con importarlo, instanciar la clase generada, y pasarle a su método setupUi el widget o ventana principal de la aplicación. app = QApplication(sys.argv) window = QDialog() ui = Ui_ImageDialog() ui.setupUi(window) ● También puede heredarse de la clase generada, invocando a setupUi con self ● Es posible escribir plugins para Qt designer (ver doc oficial)
14
Ejercicio ● 02_Calculator: Usar QtDesigner para crear el interfaz de una calculadora simple (numeros enteros, operaciones básicas, resultado), y compilarla con al herramienta pyuic4 ● Más adelante usaremos esta pantalla para implementar la calculadora.
15
Qt Properties ● PyQt no soporta el acceso a propiedades de objetos qt como atributos normales, esto es debido al conflicto con los nombres de los métodos “getter” que qt usa. Por ej: label = QtLabel() label.text() # el getter label.setText(txt) #el setter ● Si que soporta el paso de propiedades en el constructor: act = QtGui.QAction("&Save", self, shortcut=QtGui.QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) ● También usando pyqtConfigure (de Qobject) act = QtGui.QAction("&Save", self) act.pyqtConfigure(shortcut=QtGui.QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save)
16
Layouts ● Posicionamiento absoluto label1 = QtGui.QLabel('Estoy posicionado absolutamente!', self) label1.move(15, 10) # desde esquina sup. Izda. ● Box Layout (QVBoxLayout y QHBoxLayout) ● Sirven para posicionar elementos horizontalmente o verticalmente boxlayout.py hlayout = QtGui.QHBoxLayout() hlayout.addWidget(okButton) hlayout.addWidget(cancelButton) mywindow.setLayout(hlayout)
17
Layouts (II) ● GridLayout (QgridLayout): Para posicionar elementos en cuadrícula. Gridlayout.py (ejercicio: corregir el ejemplo) grid = QtGui.QGridLayout() grid.addWidget(button, 0, 0) ● FormLayout (QformLayout): Para posicionar elementos en formularios Formlayout.py layout = QtGui.QFormLayout() layout.addRow(QtGui.QLabel("Field 1:"), QtGui.QLineEdit()) layout.addRow(QtGui.QLabel("Combo 2, long text:"), QtGui.QComboBox()) layout.addRow(QtGui.QLabel("Control 3:"), QtGui.QSpinBox())
18
Signals y Slots ● Las señales son emitidas por componentes (ej: cuando se pulsa un botón o cambia el estado de un checkbox) ● Los slots son funciones que se conectan a señales y que son invocadas cuando alguna de éstas es emitida ● Las señales no saben si hay alguien “escuchando” o conectado a ellas, con lo que el emisor está desacoplado completamente del código que maneja los eventos
19
Signals y Slots (II) ● Tres tipos de signals: ● Signals Qt: Estáticamente en C++ de Qt: QtCore.SIGNAL("toggled(bool)") ● Signals PyQt: El emitir señales implicitamente las define. Se referencian también con QtCore.SIGNAL. ● Short-circuit signals: Signals PyQt que no tienen lista de argumentos al referenciarlas ni parentesis (en realidad implicitamente todos sus parámetros son de tipo PyQt_PyObject. Solo pueden ser conectadas a “callables” python, no a slots Qt ● Dos tipos de slots: ● Slots Qt: Definidos estáticamente en clases C++ de Qt: QtCore.SLOT("done(int)") ● Slots PyQt: Cualquier “callable” python, funciones y métodos. Los slots qt, al ser métodos también pueden referenciarse sin usar QtCore.SLOT.
20
Conectando signals y slots ● New-style: ● qobject.signal.connect(pyObj.pyMethod) ● qobject.signal.connect(qobject.slot) ● Old-style: ● QtCore.QObject.connect(a, QtCore.SIGNAL("QtSig()"), pyObj.pyMethod) ● QtCore.QObject.connect(a, QtCore.SIGNAL("QtSig()"), b, QtCore.SLOT("QtSlot()")) ● QtCore.QObject.connect(a, QtCore.SIGNAL("PySig()"), b, QtCore.SLOT("QtSlot()")) ● QtCore.QObject.connect(a, QtCore.SIGNAL("PySig"), pyObj.pyMethod) a: objeto que emite la señalb: objeto que recibe la señal QtSig: Signal de QtPySig: Signal de PyQt QtSlot: Slot de Qt
21
Signals y Slots (II) signalsslots_newstyle.py self.btn = QtGui.QPushButton("Pulsame!") self.output = QtGui.QLabel(u"Esto se borrará al pulsar") self.btn.clicked.connect(self.output.clear) predef_signals.py self.connect(dial, SIGNAL("valueChanged(int)"), spinner.setValue) self.connect(spinner, SIGNAL("valueChanged(int)"), dial.setValue) self.setWindowTitle("Using default signals") signalsslots.py self.btn = QtGui.QPushButton("Pulsame!") self.output = QtGui.QLabel(u"Esto se borrará al pulsar") self.connect(self.btn, QtCore.SIGNAL('clicked()'), self.output, QtCore.SLOT('clear()')) predef_signals_newstyle.py dial.valueChanged.connect(spinner.setValue) spinner.valueChanged.connect(dial.setValue) self.setWindowTitle("Using default signals")
22
Signals y Slots (III) ● Cualquier clase que herede QObject puede definir señales y slots, no solo los widgets (Qwidget) ● Los widgets de Qt tienen predefinidas ciertas señales y ciertos slots, pero podemos definir tanto signals y slots Qt como pyQt. ● Para definir signals Qt podemos usar la factoría QtCore.pyqtSignal, y para definir slots Qt el decorador QtCore.pyqtSlot (Ver doc oficial) ● Cualquier señal puede tener conectados varios slots, y cualquier slot estar conectado a varias señales ● Una señal puede estar conectada a otra señal. La emisión de la primera señal causará automáticamente la emisión de la segunda ● Las señales puede ser síncronas (los slots se ejecutan sincronamente cuando se emite una señal) o asíncronas (los slots se encolan, y el código que sigue a la emisión de la señal continúa normalmente)
23
Signals y Slots: Autoconnect ● AutoConnect: Se pueden autoconectar slots nombrando al método como “on_ _ ” slots_autoconnect.py Class AutoConnectSlotsExample(QWidget): btn = QtGui.QPushButton("Pulsame!") btn.setObjectName("btn") # Importante, poner el nombre QtCore.QMetaObject.connectSlotsByName(self) # Se autoconectan hijos de este widget con slots de esta clase def on_btn_clicked(self): # código del slot
24
Signals y Slots (V) ● También se pueden conectar pasando slots a los constructores de widgets como keyword arguments: ● signalsslots_keywordargs.py self.output = QtGui.QLabel(u"Esto se borrará al pulsar") self.btn = QtGui.QPushButton("Pulsame!", clicked=self.output.clear) ● Existe un método sender() para obtener el objeto causante getting_signal_sender.py def buttonClicked(self): sender = self.sender() self.statusBar().showMessage(sender.text() + ' was pressed')
25
Emitiendo Signals (old-style) emitting_signals.py class TemperatureLabel(QLabel): def __init__(self, parent=None): super(TemperatureLabel, self).__init__(parent) self.temperature_changed(0) def temperature_changed(self, level): self.setText(u" {0} ".format(temps[level],colors[level])) … Label = TemperatureLabel() self.connect(self.dial, SIGNAL("temperatureChanged"), label.temperature_changed)... def emit_temperature_change(self, value): level = … self.dial.emit(SIGNAL(“temperatureChanged”), level)
26
Emitiendo Signals (new-style) emitting_signals_newstyle.py class TemperatureDial(QDial): temperatureChanged = pyqtSignal(int) … Label = TemperatureLabel() self.dial.temperatureChanged.connect(label.temperature_changed)... def emit_temperature_change(self, value): level = … self.dial.temperatureChanged.emit(level)
27
Ejercicios ● 01_signals: Implementar un botón que al pulsarlo provoque que un dial aumente su valor. ● a) Haciendo un slot que “escuche” el pulsado del botón y modifique directamente el dial ● b) Haciendo que el slot emita una señal propia pasandole el nuevo valor del dial, y conectando la nueva señal al slot Qt de establecer su valor de dial. ● c) Implementar los anteriores ejercicios definiendo y conectando señales del modo “new-style”
28
Eventos ● El sistema de eventos es un mecanismo de bajo nivel, más acoplado a los componentes que las señales y slots ● Útil en la personalización o creación de widgets ● PyQt aporta manejadores de eventos, como el manejador de eventos de teclado, de ratón, etc. ● Si un widget recibe un evento, pero éste no lo maneja, se propaga al widget o componente que lo contiene.
29
Eventos (II) overriding_evhandlers.py class OverrButton(QtGui.QPushButton): def __init__(self, txt, label2update): QtGui.QPushButton.__init__(self, txt) self.label2update = label2update def mousePressEvent(self, event): self.label2update.clear() ● Se pueden manejar eventos sobreescribiendo manejadores específicos de widgets (ej: keyPressEvent) ● O sobreescribiendo el manejador genérico event(), para implementar manejo de aquellos eventos que no tienen un manejador específico (ej: Qevent.ToolBarChange) ● Por último podemos utilizar filtros de eventos
30
Ejercicio ● 02_Calculator: Implementar una calculadora simple (numeros enteros, operaciones básicas, resultado, teclado funcional), haciendo uso de signals, slots, y manejadores de eventos. Usar QtDesigner para la vista.
31
Diálogos ● QDialog: clase base ● Pueden devolver valores ● Dialogos modales: invocando exec_() se espera a la finalización del uso del diálogo. Se puede usar setModal(true) y show(), que devuelve el control inmediatamente para diálogos no modales ● Tiene slots “accept()” y “reject()” ● Algunas clases de dialogos específicos: QMessageBox, QProgressDialog, QfileDialog, QerrorMessage, QWizard ● QdialogButtonBox para implementar botones típicos cancel/ok. Emite señales “accepted()” y “rejected()”.
32
Dialogos (II) modal_dialog.py def open_properties_dlg(self): dialog = PropertiesDlg(self.props, self) res = dialog.exec_() if res: self.update_props_label() class PropertiesDlg(QDialog): … buttonBox = QDialogButtonBox(QDialogButtonBox.Ok| QdialogButtonBox.Cancel)... self.connect(buttonBox, SIGNAL("accepted()"), self, SLOT("accept()")) self.connect(buttonBox, SIGNAL("rejected()"), self, SLOT("reject()"))...
33
Actions ● QAction: Encapsula una acción que puede ser usada en toolbars, menús, y a través de atajos de teclado, para evitar tener que repetir código. ● Emiten la señal “triggered()” exit = QtGui.QAction(QtGui.QIcon('icons/exit.svg'), 'Salir', self) exit.setShortcut('Ctrl+Q') exit.setStatusTip('Salir de la aplicación') self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()')) toolbar = self.addToolBar("Salir") toolbar.addAction(exit) menubar = self.menuBar() file = menubar.addMenu('&File') # hace que el menu file sea accesible con alt+f file.addAction(exit)
34
Timers ● La clase Qtimer permite lanzar señales únicas o repetitivas a intervalos prefijados digitalclock.py timer = QtCore.QTimer(self) # se crea el timer timer.timeout.connect(self.showTime) # conectar la señal timeout del timer con un slot timer.start(1000) # intervalo ● ¡Cuidado! ¡Se ejecuta en el mismo event loop! Esto significa que si el slot tarde en terminar, el interface no responderá hasta que acabe, se decir, es como cualquier otra señal producida por una acción del usuario.
35
Multithreading ● Problema: tareas de larga duración ● QApplication.processEvents(): Da el control al event loop para procesar eventos que tenga pendientes, interrumpiendo temporalmente la ejecución en curso. ● En lugar de threads, ejecutar las tareas de larga duración en procesos separados (subprocess de python o QProcess) ● Usar threads: thread y threading de python o Qthread – Se pueden pasar señales entre threads, el único requisito es que el receptor de la señal tenga un event loop
36
Ficheros de recursos ● PyQt soporta el sistema de recursos de Qt ● Necesario escribir (Qt Designer lo hace automáticamente) fichero xml.qrt ● Pyrcc4 genera módulo.py con los recursos embebidos. Simplemente con importar dicho módulo ya pueden usarse recursos (añadiendo “:” al nombre del recurso cuando se use). ● Ejemplo/Ejercicio: Añadir un icono a la calculadora del ejercicio 02, mediante un fichero de recursos
37
Internacionalización ● Mecanismo similar a GNU Gettext (ver http://translate.sourceforge.net/wiki/toolkit/ts2po?redirect=1) ● Usar QtCore.QCoreApplication.translate(), Qobject,tr() y Qobject.trUtf8() para traducir cadenas (cuidado con el contexto al usar tr()) Self.statusBar().showMessage(self.tr("Ready"), 5000) ● Cargar ficheros.qm (Qt messages) en el arranque de la aplicación, gracias a QTranslator ● Crear archivo.pro en el que se listan todos los.py y.ui con cadenas a traducir, junto con los.ts (translation source) que se usarán ● Usar herramienta pylupdate4 para que se genere el fichero.ts ● Traducir el fichero.ts gracias a Qt Linguist ● Regenerar el.qm a partir del.ts
38
Empaquetado y distribución ● Distutils ● Paquetes de fuentes portables (sdist) ● RPMs (bdist_rpm) ● Instaladores windows (bdist_rpm) ● Py2exe: http://www.py2exe.org/index.cgi/Py2exeAndPyQt http://www.py2exe.org/index.cgi/Py2exeAndPyQt ● easy_install
39
Tarea ● Extender la calculadora creada en el ejercicio 2: ● Convertirla en calculadora decimal ● Añadir funcionalidad de conversión de divisas con dos botones, uno para convertir el número actual a la divisa x, y el otro para convertirlo a la divisa y. ● Implementar diálogo de preferencias – Separador de miles – Selección de las dos divisas sobre las que la calculadora trabajará. Los botones de cambio han de reflejar estas preferencias. ● Obtención de divisas (elegir un método): – a) Seleccionando un fichero localmente desde el diálogo de preferencias. – b) Obteniendolo de internet, implementarlo como un thread con progreso en el arranque de la calculadora (ej: yahoo finance) ● Opcional: Empaquetar la aplicación (método/s.o. libre)
40
Referencias ● Sobre QT ● http://doc.qt.nokia.com/4.7/ - documentación oficial de Qt. http://doc.qt.nokia.com/4.7/ ● Sobre PyQt ● Doc oficial: – http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/index.htmlGuía de referencia http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/index.html ● Tutoriales: – http://lateral.netmanagers.com.ar/stories/BBS47.html http://lateral.netmanagers.com.ar/stories/BBS47.html – http://www.commandprompt.com/community/pyqt/ (qt 2.x y 3.x) http://www.commandprompt.com/community/pyqt/ – http://rctorr.wordpress.com/2011/02/09/iniciando-con-python-y-qt-pyqt4-%E2%80%93- ii/ (en castellano) http://rctorr.wordpress.com/2011/02/09/iniciando-con-python-y-qt-pyqt4-%E2%80%93- ii/ – http://zetcode.com/tutorials/pyqt4 http://zetcode.com/tutorials/pyqt4 – http://docs.huihoo.com/pyqt/pyqt4.html ● Libros: – Rapid GUI Programming with Python and Qt http://www.qtrac.eu/pyqtbook.html (exhaustivo, aunque demasiado verborreico)http://www.qtrac.eu/pyqtbook.html – Advanced PyQt4 tutorial http://zetcode.com/ebooks/advancedpyqt4/
Presentaciones similares
© 2025 SlidePlayer.es Inc.
All rights reserved.