Introducción a programación de aplicaciones de escritorio con Python y Qt: PyQt Luis Alberto Pérez Septiembre de 2011.

Slides:



Advertisements
Presentaciones similares
Interfaces de Usuario Prof. Wilmer Pereira UCAB/USB.
Advertisements

Introducción al Lenguaje. ¿ Qué es PHP ? O Hypertext Pre-processoes (PHP) es un lenguaje de "código abierto" interpretado, de alto nivel, embebido en.
LE, EI, Profesor Ramón Castro Liceaga UNIVERSIDAD LATINA (UNILA) LENGUAJES DE PROGRAMACIÓN PARA EL DESARROLLO DE INTERFACES.
Clase 09.  Garantizar la calidad de software  La prueba nunca termina, del IS translada se translada al usuario  Las casas de software invierte del.
Disseny de Base de Dades Un paseo por OpenERP Jordi Gálvez Santos 11/12/2008.
Introducción a programación de aplicaciones de escritorio con Python y Qt: PyQt Luis Alberto Pérez Septiembre de 2011.
1 /13 Repositorios online para Sironta Autor: Juan Aguilera Ramos Tutor: Jesús Gabaldón Estudios: Máster Universitario en Software Libre.
Ofelia Cervantes Redes Dinámicas 1. Ofelia Cervantes Redes dinámicas en Gephi REDES DINÁMICAS: se van construyendo y visualizando en tiempo real Pasos.
Museo Tecnológico. Bienvenidos al Museo Tecnológico BIENVENIDOS Información.
Flujos de datos Un flujo es un canal por donde fluyen los datos.
PROGRAMACIÓN ORIENTADA A OBJETOS SEGUNDA UNIDAD: “CLASES, OBJETOS Y MÉTODOS” IRVING YAIR SALAS CHÁVEZ ING. EN SISTEMAS COMPUTACIONALES - ITSLP.
MICROSOFT ACCESS. Definición de una Base de Datos: un programa que permite gestionar y organizar una serie de datos. Por ejemplo, para la gestión de los.
CURSO DE COMPUTACIÓN BÁSICO El objetivo de crear este curso es que el alumno adquiera los elementos básicos para conocer los usos de la computadora y trabajar.
SISTEMAS OPERATIVOS (II): WINDOWS
Tema 1 Fundamentos de Computación
WINDOWS Elvira Abajo Lera Octubre, 2008.
Nombre José Francisco Luna Jurado Matricula Asignatura
Herencia Multiple en Java
INGENIERÍA DE INFORMACIÓN Y APLICACIONES
Diseño de aplicaciones móviles
Clases y Objetos.
HERRAMIENTAS DE INFORMATICA
UNIVERSIDAD TECNICA DEL NORTE VIRTUALIZACION DE APLICACIONES
LOS DIFERENTES LENGUAJES DE PROGRAMACION PARA LA WEB
Programación en C - manejo de Archivos
Administrador de dispositivos
“POLIMORFISMO PARAMETRICO”
Programación Orientada a Eventos
PARCIAL 2.
Capítulo 12 Leer archivos XML con AJAX
gvSIG: Avanzando Juntos
INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS
INSTALACIÓN DE TU TIENDA ON LINE PRESTASHOP EN HOSTING
INTRODUCCIÓN AL PROGRAMA QUARKXPRESS
EL ESCRITORIO El Escritorio es la primera pantalla que nos aparece una vez se haya cargado el Sistema Operativo. La teclas rápidas o atajo para acceder.
CURSO DE HTML.
Interfaces Gráficas de Usuario
TÓPICOS AVANZADOS DE PROGRAMACIÓN
CREACIÓN DE EJERCICIOS EN HOT POTATOES
KUbuntu Carlos Torres Denis González 7 de septiembre de 2015.
Carpetas y archivos.
Principios básicos del entorno windows
ESCUELA SUPERIOR POLITÉCNICA DE CHIMBORAZO FACULTAD DE MECÁNICA INGENIERÍA DE MANTENIMIENTO VISUAL BASIC.
 PhoneGap es un framework de código libre para el desarrollo de aplicaciones móviles. Su principal característica: multiplataforma, es decir, con un.
Configurando mi espacio de trabajo
LINUX.
INTRODUCCIÓN A JAVA.
ARQUITECTURA DE APLICACIONES WEB.
Conceptos básicos de.NET Explorar el entorno de desarrollo Crear un proyecto Visual Basic.NET Use Visual Studio.NET Acceso a datos Depurar e implantar.
Implementación de aplicaciones
EXPLORADOR DE WINDOWS 7. Explorador de Windows El Explorador es una herramienta indispensable en un Sistema Operativo ya que con ella podemos organizar.
Samanta Janet Correa Proa 1ª A T/M BGC.  Son enlaces o rutas de acceso a otro archivo, pagina Web o una dirección de correo electrónico, es una herramienta.
¿Qué es un hipervínculo? . Un hipervínculo es un enlace, normalmente entre dos páginas web de un mismo sitio, pero un enlace también puede apuntar a.
Introducción al Visual Basic  Un programa en sentido informático está constituido en un sentido general por variables que contienen los datos con los.
Procesamiento de señales Introducción a Matlab 2014
HERRAMIENTAS DE MICROSOFT WORD LOS HIPERVINCULOS Los hipervínculos son enlaces o rutas de acceso a otro archivo, pagina Web o una dirección de correo.
LOS HIPERVINCULOS Las características, funciones, tipos y ejemplos de los hipervínculos.
Tema: Componentes lógicos de un ordenador. Mediante el sistema de numeración binario, es decir, usando los dígitos 0 y 1. Lo único que transmite,
Servidor de Reportes basado en Tecnología Java y XML
Curso de Excel #Intermedio Guillermo Díaz Sanhueza Mail: Web: Team Work Versión:
Lenguajes del lado del cliente
ESTRUCTURA DE SISTEMAS OPERATIVOS Carbajal Rojas karla.
CC 1002: Introducción a la Programación Clase 20
DESARROLLO DE APLICACIONES WEB INSTRUCTOR: HEMERSON VILLACORTA MANIHUARI.
MICROSOFT ACCESS. Definición de una Base de Datos: un programa que permite gestionar y organizar una serie de datos. Por ejemplo, para la gestión de los.
Gestión de Recursos compartidos.. Aspectos fundamentales del usó compartido Existen dos maneras de compartir archivos y carpetas: desde el equipo y desde.
ESTRUCTURA DE LOS SISTEMAS OPERATIVOS
ESTRUCTURA DE LOS SISTEMAS OPERATIVOS. Estos sistemas no tienen una estructura definida, sino que son escritos como una colección de procedimientos donde.
INTERNET: Por medio de este icono podrá conectarse a Internet y podrá acceder a la red de redes. 4-PAPELERA DE RECICLAJE: En este icono.
Navegadores y buscadores. ¿Qué es un Navegador? Un navegador o navegador web, o browser, es un software que permite el acceso a Internet, interpretando.
Transcripción de la presentación:

Introducción a programación de aplicaciones de escritorio con Python y Qt: PyQt Luis Alberto Pérez Septiembre de 2011

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:

¿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 ●...

¿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

Instalación ● En linux: apt ● libqt4-dev ● qt4-designer ● python-qt4 ● pyqt4-dev-tools ● En windows: se ofrecen instaladores binarios ● pyqt/download

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

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.

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_())

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

Widgets comunes ● QMainWindow ● QLabel, QComboBox, QcheckBox, QLineEdit QradioButton, Qdial, QpushButton, QtabWidget, QtableWidget, QprogressBar, Qsplitter... ● QDialog, QDialogButtonBox ● Ver widgets.py

Herramientas ● Qt Designer: Herramienta para crear interfaces gráficos visualmente

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.

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)

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.

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)

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)

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())

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

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.

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

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")

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)

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

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')

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)

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)

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”

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.

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

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.

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()”.

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()"))...

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)

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.

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

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

Internacionalización ● Mecanismo similar a GNU Gettext (ver ● 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

Empaquetado y distribución ● Distutils ● Paquetes de fuentes portables (sdist) ● RPMs (bdist_rpm) ● Instaladores windows (bdist_rpm) ● Py2exe: ● easy_install

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)

Referencias ● Sobre QT ● - documentación oficial de Qt. ● Sobre PyQt ● Doc oficial: – de referencia ● Tutoriales: – – (qt 2.x y 3.x) – ii/ (en castellano) ii/ – – ● Libros: – Rapid GUI Programming with Python and Qt (exhaustivo, aunque demasiado verborreico) – Advanced PyQt4 tutorial