3ENGINE

Programación y otros cachivaches

Etiqueta: Python

Página 3/6

Tecnologia

Cómo incrustar imágenes en una aplicación Qt en Python


En este post voy a explicar mediante una pequeña demo cómo incrustar imágenes dentro de una aplicación. El principal objetivo de esto es no tener que distribuir las imágenes junto con la aplicación. Pero antes, un poco de teoria:

El Sistema de Recursos de Qt

Se trata de un sistema independiente de la plataforma que permite almacenar archivos binarios en el ejecutable de la aplicación. Esto es útil si la aplicación necesita de un cierto conjunto de archivos (iconos, archivos de traducción, etc.) y no queremos correr el riesgo de perder los archivos.

Recursos Archivos Colección (.qrc)

Los recursos asociados con la aplicación se especifican en un archivo .qrc. Es un formato de archivo basado en XML que enumera los archivos y opcionalmente un nombre de recurso que la aplicación debe utilizar para acceder al recurso. Los archivos de recursos que figuran en el archivo .qrc son archivos que forman parte del árbol de código fuente de la aplicación. Las rutas especificadas son relativas al directorio que contiene el archivo .qrc.

Utilidad pyrcc4

pyrcc4 es equivalente a la utilidad rcc de Qt y se utiliza exactamente de la misma manera. Lee el archivo .qrc, y los archivos de recursos, y genera un módulo de Python que sólo necesita ser importado por la aplicación para que los recursos estén disponibles como si se tratara de los archivos originales.

Para mas información leer The Qt Resource System

Ejemplo

Paso 1: generar el fichero .qrc




    img/icon_ok.png
    img/icon_cancel.png


    img/image_qt.png


Por defecto, los recursos son accesibles en la aplicación bajo el mismo nombre de archivo. Opcionalmente el atributo alias permite cambiar el nombre. Al especificar un prefijo de ruta mediante la etiqueta qresource y el atributo prefix se han agrupado las imágenes en dos grupos. En este caso, las imagenes son accesibles con: :icons/ok.png , :icons/cancel.png y :img/image_qt.png respectivamente.

Paso 2: generar el módulo Python con los recursos

pyrcc4 -o images_rc.py images.qrc

Le indicamos a la herramienta que genere a partir de images.qrc un módulo Python images_rc.py con los recursos.

Paso 3: código fuente

# -*- coding: utf-8 -*-
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import images_rc
import sys


class MainWindow(QMainWindow):

    def accept(self):
        QMessageBox.information(self, 'Thanks!', 'Thanks for testing the demo', QMessageBox.AcceptRole)
        self.close()
        
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)
       
        # añadir imagen 
        title = QLabel() 
        pixmap = QPixmap(':images/title.png')
        title.setPixmap(pixmap)

        # añadir texto              
        info = QLabel('visit my blog at:3engine.net') 

        # crear botones 
        acceptButton = QPushButton('Accept', self)
        acceptButton.setIcon(QIcon(':icons/ok.png'))

        cancelButton = QPushButton('Cancel', self)
        cancelButton.setIcon(QIcon(':icons/cancel.png'))

        # añadir botones al diálogo
        buttonBox = QDialogButtonBox()
        buttonBox.addButton(acceptButton, QDialogButtonBox.AcceptRole)
        buttonBox.addButton(cancelButton, QDialogButtonBox.RejectRole)
        buttonBox.accepted.connect(lambda: self.accept())
        buttonBox.rejected.connect(lambda: self.close())

        # crear layout principal           
        vbox = QVBoxLayout()
        vbox.addWidget(title)
        vbox.addSpacing(10)
        vbox.addWidget(info)
        vbox.addSpacing(10)
        vbox.addStretch()
        vbox.addWidget(buttonBox)

        centralWidget = QWidget()
        centralWidget.setLayout(vbox)
        self.setCentralWidget(centralWidget)
        self.resize(100, 100)
        self.setWindowTitle('demo')       


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = MainWindow()
    main.show()    
    sys.exit(app.exec_())

En el código vemos el uso de los recursos incrustados en los widgets de tipo QPixmap y QIcon

El resultado es el siguiente

cap_qt

Enlace a la demo




Tecnologia

pyqt: cómo hacer que QLabel sea clicable.


En Qt el widget QLabel no es clicable. Para emular el click del ratón basta añadir una propiedad que use la clase Signal y sobreescribir el evento mouseRelease de QLabel de modo que emita un señal clicked.

class QLabelClickable(QLabel):

    clicked = pyqtSignal()
    
    def __init__(self, *args):
        QLabel.__init__(self, *args)
   
    def mouseReleaseEvent(self, ev):
        self.clicked.emit()

Y este es el código para probarlo:

class MainWindow(QMainWindow):

    def label_clicked(self):
        print "click"
        
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)
        self.mylabel = QLabelClickable('click me!')
        self.mylabel.clicked.connect(self.label_clicked)
        self.setCentralWidget(self.mylabel)

app = QApplication(sys.argv)
main = MainWindow()
main.show()     
sys.exit(app.exec_())

En este otro ejemplo ahora QLabel incorpora una imagen y además hago uso del antiguo sistema para conectar eventos:

class MainWindow(QMainWindow):

    def label_clicked(self):
        print "click"
        
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)
        self.mylabel = QLabelClickable('')
        self.mylabel.setPixmap(QPixmap('myimage.png').scaled(10, 10, Qt.KeepAspectRatio))
        self.connect(self.mylabel, SIGNAL('clicked()'), self.label_clicked)
        self.setCentralWidget(self.mylabel)

app = QApplication(sys.argv)
main = MainWindow()
main.show()     
sys.exit(app.exec_())




Tecnologia

Decoradores Python con parámetros


Ya expliqué en una entrada anterior que es eso de los decordadores Python. Si todavia no lo has hecho te recomiendo que leas el artículo antes de seguir.

Decoradores con parámetros

Hace unos días tuve la necesidad de pasar parámetros a un decorador. Queria crear un decorador que retornara un valor por defecto si la función decorada retorna valor nulo. Entonces me di cuenta que mi anterior artículo no cubria esta aspecto.

Este es mi decorador:

def default_value(value):
    def _default_value(func):
        def box(*args, **kwargs):
            result = func(*args, **kwargs)
            if not result:
                return value
            return result
        return box
    return _default_value

Tenemos una funcion un tanto maleducada 😉 que sólo saluda a personas que se llamen David. La vamos a decorar para que retorne un saludo por defecto en caso que retorne nulo:

@default_value('hola desconocido')
def saluda(nombre):
    if nombre == 'david':
        return 'hola david'

Un test:

print saluda('david')
print saluda('antonio')

Y esta es la salida:

hola david
hola desconocido

Otra posible aplicación de los decoradores con parámetros, es si por ejemplo queremos devolver un valor por defecto sólo si la llamada a un función genera una excepción.

El código completo:

def default_try_value(value):
    def _default_try_value(func):
        def box(*args, **kwargs):
            try:
                result = func(*args, **kwargs)
            except:
                return value
            return result
        return box
    return _default_try_value
  
@default_try_value('error')
def divide_entre_2(numero):
    return numero / 2
    
print divide_entre_2(16)
print divide_entre_2('david')

Y esta es la salida:

8
error



Tecnologia

Utilizar markdown en modulos Pypi


Es posible que una vez subido un módulo Python a Python Package Index notes que la descripción del módulo (README) que aparece en la página PyPi no esté bien formateada.

Si formateaste la descripción del módulo con Markdown, caso bastante probable si tienes las fuentes en Github, tienes que saber que PyPi únicamente acepta reStructuredTxt como formato de descripción.

Las solución drástica es cambiar la descripción al formato aceptado por PyPi. O bien puedes traducir «on fly» de un formato a otro en setup.py.

Para hacer esto, primero instala pandoc. Se trata de una utilidad que es capaz de convertir ficheros de un lenguaje de marcado a otro.

$ sudo apt-get install pandoc

Después instala el módulo Python pyandoc:

$ sudo pip install pyandoc

Por último modifica setup.py:

long_description = ''

try:
    import subprocess
    import pandoc

    process = subprocess.Popen(
        ['which pandoc'],
        shell=True,
        stdout=subprocess.PIPE,
        universal_newlines=True
    )

    pandoc_path = process.communicate()[0]
    pandoc_path = pandoc_path.strip('\n')

    pandoc.core.PANDOC_PATH = pandoc_path

    doc = pandoc.Document()
    doc.markdown = open('README.md').read()

    long_description = doc.rst

except:
    pass
   
setup(
    long_description=long_description  
    # y tus parámetros de configuración....
)

Las líneas de la 6 a la 16 averigua la ruta donde se encuentra pandoc instalado mediante una llamada al sistema del comando which. Un try/catch es necesario para garantizar la instalación del módulo mediante python setup.py install en un sistema sin pandoc instalado.