Google+ Seguidores

miércoles, 22 de abril de 2015

Generar un PDF a partir de un sencillo formulario en PyQt

    27


Generar PDF en Python
Generar PDF en Python
La idea de esta entrada, como su titulo ya describe, es crear en QtDesigner(PyQt) un sencillo formulario gráfico que generará un PDF con los datos ingresados por el usuario.

Algunos ejemplos de uso: Ingreso de un alumno a un curso, ingreso de un nuevo funcionario a una empresa, etc.

La idea es llenar el formulario, y una ves que se presione el botón PDF, se abra automáticamente el archivo Formulario.pdf con los datos que acabamos de llenar.
Si se analiza con profundidad el código, se podrían mejorar muchas cosas, como por ejemplo añadir excepciones de error y alguna cosa mas. Pero la idea principal de la entrada es ver de forma sencilla como crear un Formulario en python y generar un PDF para imprimir o guardar.

Estas pruebas fueron realizadas en un sistema Linux (Ubuntu)
Fecha: 14/04/2015


Dejo también acá, algunas entradas sobre PyQt por si no estas familiarizado con el tema:


La librería que utilizaremos para trabajar con PDF en python será: reportlab

Aquí dejo el link con la guía de instalación tanto para Windows, Mac OS y Linux: https://bitbucket.org/rptlab/reportlab

Diseño en QtDesigner

Nombre que utilicé para los objetos en QtDesigener


1 botón : btn_pdf

6 etiquetas (no cambio el objetName porque en este caso no las utilizo en el código), pero si les agrego el texto (Nombre, Apellido, Correo, Curso, Pais y Observaciones)

6 textEdit :
  1. Para el Nombre = textNombre
  2. Para el Apellido = textApellido
  3. Para el Correo = textCorreo
  4. Para el Curso = textCurso
  5. Para el País = textPais
  6. Para las Observaciones = textObs

Código del Programa


#!/usr/bin/python
# -*- coding: utf-8 -*-

# Formulario que Genera PDF
# www.pythondiario.com

import sys
import os
from reportlab.pdfgen import canvas
from PyQt4 import QtCore, QtGui, uic
 
# Cargar nuestro archivo .ui
form_class = uic.loadUiType("formularioPDF.ui")[0]
 
class MyWindowClass(QtGui.QMainWindow, form_class):
 def __init__(self, parent=None):
  QtGui.QMainWindow.__init__(self, parent)
  self.setupUi(self)
  
  self.btn_pdf.clicked.connect(self.generarPDF)

  
 # Evento del boton btn_pdf
 def generarPDF(self):
  
  # Guardo en las variables los datos de los textEdit Ingresados por el Usuario
  self.nombre = str(self.textNombre.toPlainText())
  self.apellido = str(self.textApellido.toPlainText())
  self.correo = str(self.textCorreo.toPlainText())
  self.curso = str(self.textCurso.toPlainText())
  self.pais = str(self.textPais.toPlainText())
  self.obs = str(self.textObs.toPlainText())
  
    
  # Ruta donde quiero crear el PDF
  c = canvas.Canvas("/home/diego123/Escritorio/Formulario.pdf")
  c.drawString(100,750,"Este formulario fue creado en www.pythondiario.com")
  c.drawString(100,700,("Nombre: "+ self.nombre))
  c.drawString(100,680,("Apellido: "+ self.apellido))
  c.drawString(100,660,("Correo: "+ self.correo))
  c.drawString(100,640,("Curso: "+ self.curso))
  c.drawString(100,620,("Pais: "+ self.pais))
  c.drawString(100,600,("Observaciones: "+ self.obs))
  c.save()
    
  # PARA WINDOWS: os.system("start AcroRD32 ruta_y_archivo.pdf &")
  os.system("evince /home/diego123/Escritorio/Formulario.pdf &") 
  
 
if __name__ == "__main__":
 app = QtGui.QApplication(sys.argv)
 MyWindow = MyWindowClass(None)
 MyWindow.show()
 app.exec_()

Análisis del código

Importamos los módulos necesarios para trabajar:

import sys
import os
from reportlab.pdfgen import canvas
from PyQt4 import QtCore, QtGui, uic

El módulo os será necesario para abrir el archivo.pdf una ves sea creado. También importamos el módulo reportlab para crear el archivo.pdf. Los otros módulos son necesarios para la aplicación gráfica.

Cargamos el archivo.ui de QtDesigner:

# Cargar nuestro archivo .ui
form_class = uic.loadUiType("formularioPDF.ui")[0]

Creamos la clase MyWindowClass con su inicializador

class MyWindowClass(QtGui.QMainWindow, form_class):
 def __init__(self, parent=None):
  QtGui.QMainWindow.__init__(self, parent)
  self.setupUi(self)
  
  self.btn_pdf.clicked.connect(self.generarPDF)

Como podemos ver, creamos un evento (btn_pdf.clicked.connect) que funcionara cada ves que presionemos el botón PDF (hace lo que está en la función generarPDF())

Función generarPDF()

# Evento del boton btn_pdf
 def generarPDF(self):
  
  # Guardo en las variables los datos de los textEdit Ingresados por el Usuario
  self.nombre = str(self.textNombre.toPlainText())
  self.apellido = str(self.textApellido.toPlainText())
  self.correo = str(self.textCorreo.toPlainText())
  self.curso = str(self.textCurso.toPlainText())
  self.pais = str(self.textPais.toPlainText())
  self.obs = str(self.textObs.toPlainText())
  
    
  # Ruta donde quiero crear el PDF
  c = canvas.Canvas("/home/diego123/Escritorio/Formulario.pdf")
  c.drawString(100,750,"Este formulario fue creado en www.pythondiario.com")
  c.drawString(100,700,("Nombre: "+ self.nombre))
  c.drawString(100,680,("Apellido: "+ self.apellido))
  c.drawString(100,660,("Correo: "+ self.correo))
  c.drawString(100,640,("Curso: "+ self.curso))
  c.drawString(100,620,("Pais: "+ self.pais))
  c.drawString(100,600,("Observaciones: "+ self.obs))
  c.save()
    
  # PARA WINDOWS: os.system("start AcroRD32 ruta_y_archivo.pdf &")
  os.system("evince /home/diego123/Escritorio/Formulario.pdf &") 

Esta función se encarga de obtener los datos ingresados por el usuario y generar el PDF a partir de estos datos.
En las variables: self.nombre, self.apellido .... se guarda cada dato ingresado, para eso utilizamos el método toPlainText().
Luego creamos el archivo.pdf con la instrucción:

c = canvas.Canvas("/home/diego123/Escritorio/Formulario.pdf")

y más abajo agregamos los datos con la función drawString(coordenadas + texto).
c.save() se encarga de guardar el archivo, y la última linea:

# PARA WINDOWS: os.system("start AcroRD32 ruta_y_archivo.pdf &")
os.system("evince /home/diego123/Escritorio/Formulario.pdf &")

se encarga de abrir atuomáticamente el archvo.pdf . En el comentario dejo también la instrucción para abrirlo en Windows.

Finalizamos el programa con el bloque de código ya conocido:

if __name__ == "__main__":
 app = QtGui.QApplication(sys.argv)
 MyWindow = MyWindowClass(None)
 MyWindow.show()
 app.exec_()

Espero que esta entrada sea de guia para sus futuras aplicaciones. Dejar sus comentarios ante cualquier duda o sugerencia.

Saludos, Diego.

27 comentarios:
Write comentarios
  1. Muchas Gracias Amigos... Justo lo que buscaba

    ResponderEliminar
  2. Muchas gracias por la información, funciona de maravilla.
    ¿Podrías hacer alguna guía de como crear un ejecutable .exe para esta aplicación si no es mucha molestia?

    ResponderEliminar
    Respuestas
    1. Hola Salvador, me has dado la idea para una nueva entrada. Por el momento no estoy con mucho tiempo, pero ni bien pueda publicaré algo al respecto. Saludos

      Eliminar
    2. Despues de investigar un poco ya pude generar un ejecutable de este ejercicio con cx_Freeze, gracias

      Eliminar
    3. Estaría bueno poder crear alguna entrada con esa información. Saludos

      Eliminar
  3. Excelentes tutoriales.
    Recien empiezo con esto y se entiende todo perfectamente.
    Gracias x compartirlos.

    ResponderEliminar
    Respuestas
    1. Excelente Leonardo, me alegro te sean de ayuda los tutoriales. Gracias por visitar el blog ;)

      Eliminar
  4. Hola, muchas gracias por tus aportes, la verdad que gracias a ellos aprendo mucho.
    Necesito ayuda con este error:

    File "formularioPDF.py", line 27, in generarPDF
    self.nombre = str(self.textNombre.toPlainText())
    AttributeError: 'QLineEdit' object has no attribute 'toPlainText'

    estuve buscando y no encuentro una solucion. Muchas gracias, saludos.

    ResponderEliminar
  5. Hola Nico el error es que tenes que usar en el Diseño TextEdit y no LineEdit

    ResponderEliminar
  6. Excelente aporte, yo quiero crear un pdf mostrando los datos de una tabla de una consulta en postgresql, me funcionaria tu ejemplo? o este es muy básico? por casualidad tienes algún material? Gracias :)

    ResponderEliminar
    Respuestas
    1. Hola. Gracias por visitar el blog. Necesitas utilizar entorno gráfico o sólo generar el pdf? No tengo material al respecto pero pienso que no debe ser complicado cargar los datos de esa consulta y generar el pdf. Saludos

      Eliminar
    2. Gracias por responder :D Tengo un formulario y me muestra la tabla con los datos de la consulta cargados y un botón pdf al darle click quiero que me muestre los datos tal cual como en la tabla. que podría hacer??

      Eliminar
    3. Podrías hacer lo mismo que hice yo: cada campo del formulario pasarlo con la función drawString, puedes guardarlo en una variable para que te quede más cómodo. Saludos

      Eliminar
  7. Que excelente sitio, ojala tuviera mas tiempo para seguirla.

    ResponderEliminar
    Respuestas
    1. Hola, muchas gracias por tu visita y comentarios ;). Saludos

      Eliminar
  8. Hola, seguí los pasos y se crea todo lo que debe generarse, pero al ejecutar la aplicación con el ejecutable generado me salta el siguiente error: 'ImportError: No module named PyQt4'. ¿Existe algún problema con pyqt4 a la hora de generar ejecutable? Muchas gracias de antemano.

    ResponderEliminar
    Respuestas
    1. Hola Salva, gracias por visitar el blog. Fijate en el ejemplo dos de esta entrada: Generar un archivo exe con python. Saludos

      Eliminar
    2. leí todas las entradas, el único problema es que yo no utilice QtDesigner para mi interfaz, la hice a mano con QWidget en vez de MainWindow, ¿puede ser que ese sea el probema? He estado intentando acoplar mi interfaz a una clase QtGui.QMainWindow, pero me salen todos mis widget en el mismo punto de la ventana principal, ya que estaba utilizando un grid.

      Eliminar
    3. Puede venir por ese lado si. Yo hace un tiempito estoy por fuera de PyQt y no se si pueda ayudarte. Vas a tener que seguir metiendo mano, quizá alguien más pueda responderte. Saludos

      Eliminar
    4. Muchas gracias de todas formas, he ido descubriendo que podía ser. Y me he dado cuenta que podría ser un problema de faltas de librerias en windows a la hora de hacer el ejecutable. He instalado el paquete de pandas, numpy, pyqt, fpdf y al menos he conseguido que ejecutara en windows el .py. Aún así cuando se ejecuta la app sigue dando fallos el pandas. Saludos

      Eliminar
  9. Hola diego una pregunta estoy generando un pdf dinamicamente nada mas que tengo un problema ya que al momento de que es dinamico en ocasiones hay datos que sobrepasan los que caben en 1 hoja tendras alguna opcion para que cuando se llene la primera escriba en una segunda hoja

    ResponderEliminar
    Respuestas
    1. Hola, gracias por visitar el blog. Te dejo el enlace de la documentación oficial: https://www.reportlab.com/docs/reportlab-userguide.pdf . Saludos

      Eliminar
  10. Hola, muy interesante este ejemplo. Tengo una pregunta que no tiene nada que ver con esto de pdf sino con otro programa de Python/Tkinter y como no encuentro una sección "general" para hacer preguntas, pues la hago aquí. De antemano perdón si no debí hacerlo aquí.
    Llevo unos meses traveseando con Python y Tkinter. Quiero hacer una aplicación para realizar mapas de direcciones muy básico, que arrastrando formas en un canvas el usuario vaya construyendo el mapa. El problema es que no encuentro la manera de hacer drag&drop sobre una imagen .gif en el canvas pero que NO sea precargada al inicio, sino que el usuario pueda escoger cualquier imagen de un menú y esa imagen la pueda arrastrar con el mouse y ubicarla donde desee en el canvas. Ya tengo hecha toda la GUI, puedo cargar las imágenes .gif que desee en el canvas, las veces que desee y puedo moverlas a diferentes intervalos con el teclado, pero sería más lógico, fácil y rápido hacerlo con el mouse. He buscado por todas partes y sólo encuentro ejemplos que funcionan con una única image cargada desde el inicio junto con la aplicación, pero no que se puedan cargar varias luego ¿Es posible lograr lo que quiero hacer en Python o estoy perdiendo mi tiempo? Todavía no hago el paso a wxPython ni PyQt ni nada de eso, pero ya sólo me falta esto en Tkinter para tener lista mi aplicación y no me quiero dar por vencido. Tal vez mi email: hackerdeus@terra.com Saludos.

    ResponderEliminar
    Respuestas
    1. Hola Alex, gracias por visitar el blog. Hace tiempo no toco nada de Tkinter, quizá algún colega pueda responderte. Saludo!!!

      Eliminar
  11. HOLA ME PODRIAS AYUDAR ME SALE EL SIGUIENTE ERROR .

    Traceback (most recent call last):
    File "C:\Users\Musashi\Documents\PDF.py", line 5, in
    from PyQt4 import QtCore, QtGui, uic
    ImportError: No module named 'PyQt4'

    DESDE YA MUCHAS GRACIAS..!! SALUDOS

    ResponderEliminar
    Respuestas
    1. Hola. Gracias por visitar el blog. Te falta instalar el módulo PyQt4
      Saludos

      Eliminar

Tu comentario es importante y nos motiva a seguir escribiendo...

Entradas más recientes

© 2014 Mi diario Python. Designed by Bloggertheme9 | Distributed By Gooyaabi Templates
Powered by Blogger.