Mostrando entradas con la etiqueta PyQt5. Mostrar todas las entradas
Mostrando entradas con la etiqueta PyQt5. Mostrar todas las entradas

miércoles, 12 de agosto de 2015

Tutorial de Python 3 y PyQt5 (Interfaz Gráfica de Usuarios)


Completo tutorial de Python 3 y PyQt5 para el desarrollo de aplicaciones con interfaz gráfica de usuarios.

martes, 28 de julio de 2015

24 - Python PyQt (Interfaz gráfica) - SMTP Email (Hotmail, Gmail, Yahoo, ...)




En este capítulo del tutorial de Python 3 más PyQt5 crearemos una sencilla aplicación que nos permita enviar correos con servidores que dispongan del protocolo SMTP (protocolo para transferencia simple de correo) tales como Hotmail, Gmail, Yahoo, ...

El programa permitirá al usuario configurar sus preferencias tales como el servidor STMP, puerto, credenciales, uso opcional del protocolo starttls, adjuntar multiples archivos (QFileDialog), agregar múltiples destinatarios, etc.

El programa mostrará en una etiqueta QLabel el proceso de envío del correo así como cualquier excepción que pudiera ocurrir.

Configuración para servidores SMTP clásicos:

Hotmail:
– SMTP - smtp.live.com (TLS enabled, port 25)


GMail by Google:
– SMTP - smtp.gmail.com (TLS enabled, port 587)


Yahoo! Mail:
– SMTP - smtp.mail.yahoo.com (port 25)


Lycos Mail:
– SMTP - smtp.mail.lycos.com (port 25)


AOL Mail Settings:
– SMTP - smtp.aol.com (port 25)




smtp.pyw


import sys, smtplib, email
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from PyQt5.QtWidgets import QApplication, QDialog, QGridLayout, QMessageBox, QPushButton, QLabel, QLineEdit, QFileDialog, QTextEdit, QCheckBox


class FileDialog(QFileDialog):
 def __init__(self):
  QFileDialog.__init__(self)
  self.setFileMode(QFileDialog.ExistingFiles) #Selección múltiple
  self.files = [] #Lista que guardará las rutas de los archivos
  self.filesSelected.connect(self.getFiles) #Activar la señal al seleccionar archivos
 def getFiles(self):
  self.files = self.selectedFiles() #Agregar las rutas de archivos a la lista

class Dialogo(QDialog):
 def __init__(self):
  QDialog.__init__(self)
  self.setWindowTitle("Enviar email SMTP")
  self.resize(450, 600)
  #Crear objetos en el cuadro de diálogo
  self.layout = QGridLayout()
  self.setLayout(self.layout)
  self.label_host = QLabel("Host SMTP:")
  self.txt_host = QLineEdit()
  self.chk_tls = QCheckBox("STARTTLS")
  self.chk_tls.setChecked(True)
  self.label_port = QLabel("Puerto:")
  self.txt_port = QLineEdit()
  self.label_user = QLabel("Usuario:")
  self.txt_user = QLineEdit()
  self.label_pass = QLabel("Password:")
  self.txt_pass = QLineEdit()
  self.txt_pass.setEchoMode(QLineEdit.Password)
  self.label_from = QLabel("Remitente:")
  self.txt_from = QLineEdit()
  self.label_to = QLabel("Destinatario/s:")
  self.txt_to = QLineEdit()
  self.label_subject = QLabel("Asunto:")
  self.txt_subject = QLineEdit()
  self.label_dialog = QLabel("Adjunto:")
  self.btn_dialog = QPushButton("Seleccionar ...")
  self.label_body = QLabel("Mensaje: ")
  self.txt_body = QTextEdit()
  self.label_state = QLabel("")
  self.btn_send = QPushButton("Enviar")
  #Crear objeto de la clase FileDialog()
  self.fileDialog = FileDialog()
  
  #Agregar objetos al layout grid
  self.layout.addWidget(self.label_host)
  self.layout.addWidget(self.txt_host)
  self.layout.addWidget(self.chk_tls)
  self.layout.addWidget(self.label_port)
  self.layout.addWidget(self.txt_port)
  self.layout.addWidget(self.label_user)
  self.layout.addWidget(self.txt_user)
  self.layout.addWidget(self.label_pass)
  self.layout.addWidget(self.txt_pass)
  self.layout.addWidget(self.label_from)
  self.layout.addWidget(self.txt_from)
  self.layout.addWidget(self.label_to)
  self.layout.addWidget(self.txt_to)
  self.layout.addWidget(self.label_subject)
  self.layout.addWidget(self.txt_subject)
  self.layout.addWidget(self.label_dialog)
  self.layout.addWidget(self.btn_dialog)
  self.layout.addWidget(self.label_body)
  self.layout.addWidget(self.txt_body)
  self.layout.addWidget(self.label_state)
  self.layout.addWidget(self.btn_send)
  
  #Señal para abrir el cuadro de diálogo de selección de archivos
  self.btn_dialog.clicked.connect(self.openDialog)
  #Señal para proceder a enviar los correos
  self.btn_send.clicked.connect(self.sendMail)
  
 #Método encargado de abrir el cuadro de diálogo de selección de archivos
 def openDialog(self):
  self.fileDialog.open()
  
 #Método encargado de procesar el envío de correos
 def sendMail(self):
  To = self.txt_to.text().split(", ") #Lista con los destinatarios
  #Capturar cualquier posible excepción y mostrarlo en el label label_state
  try:
   #Recorrer los destinatarios
   for destinatario in To:
    #Guardar los valores del formulario
    Host = self.txt_host.text()
    Port = self.txt_port.text()
    User = self.txt_user.text()
    Pass = self.txt_pass.text()
    From = self.txt_from.text()
    Subject = self.txt_subject.text()
    Body = self.txt_body.toPlainText()
    
    #Objeto para procesar el envío de correo
    smtp = smtplib.SMTP(Host, Port)
    #Si el servidor utilizar el protocolo starttls activarlo
    if self.chk_tls.isChecked(): smtp.starttls()
    #Credenciales
    smtp.login(User, Pass)
    #Iniciar la cabecera
    header = MIMEMultipart()
    header['From'] = From
    header['To'] = destinatario
    header["Subject"] = Subject
    msg = MIMEText(Body, 'html') #Content-type:text/html
    header.attach(msg)
    #Lista para agregrar en la cabecera los archivos a enviar
    parts = []
    for file in self.fileDialog.files:
     parts.append(MIMEBase('application', "octet-stream"))
    
    #Nos permite indexar la ruta de los archivos que se encuentran
    #en el atributo files del objeto fileDialog
    x = 0
    #Recorrer archivo a archivo
    for part in parts:
     #Lectura del archivo
     part.set_payload(open(self.fileDialog.files[x], "rb").read())
     #Codificar el archivo en base64
     encoders.encode_base64(part)
     #Extracción del nombre del archivo
     explode = self.fileDialog.files[x].split("/")
     filename = explode[len(explode)-1]
     #Añadir archivo a la cabecera
     part.add_header('Content-Disposition', 'attachment; filename="'+filename+'"')
     header.attach(part)
     x = x + 1
    #Enviar el correo al destinatario
    smtp.sendmail(From, destinatario, header.as_string())
    #Terminar la conexión con el servidor
    smtp.quit()
    #Mostrar el proceso
    self.label_state.setText("Enviando a " + destinatario + " ... ")
    
  except Exception as e: 
   #Capturar cualquier posible excepción y mostrarla
   self.label_state.setText(str(e))
    
  parts[:] = [] #Limpiar la lista de archivos
  self.fileDialog.files[:] = [] #Limpiar la lista de archivos
  self.label_state.setText("Envío finalizado")
     
app = QApplication(sys.argv)
dialogo = Dialogo()
dialogo.show()
app.exec_()


sábado, 25 de julio de 2015

23 - Python PyQt (Interfaz gráfica) - QtSql MySQL y QTableWidget (Eliminar registros)




En este capítulo del tutorial de Python 3 más PyQt5 seguimos con la continuación de la aplicación que estamos desarrollando desde los dos capítulos anteriores:


En esta ocasión veremos como eliminar fila/s, para esta tarea incluiremos un botón al cuadro de diálogo que al hacer click sobre él, entrará en acción un método llamado Eliminar el cual contendrá el proceso de búsqueda del index de la/s fila/s seleccionada/s por el usuario y su posterior eliminación tanto del objeto table como de la tabla usuarios.


administrar.pyw


import sys
from PyQt5.QtWidgets import QApplication, QDialog, QGridLayout, QMessageBox, QTableWidget, QTableWidgetItem, QPushButton
from PyQt5 import uic
from PyQt5.QtSql import QSqlDatabase, QSqlQuery

class Dialogo(QDialog):
	def __init__(self):
		QDialog.__init__(self)
		self.setWindowTitle("Administrar usuarios") #Título
		self.resize(800, 600) #Tamaño inicial
		self.layout = QGridLayout() #Crear un layout grid
		self.setLayout(self.layout) #Agregar el layout al cuadro de diálogo
		self.table = QTableWidget() #Crear la tabla
		self.btn_eliminar = QPushButton("Eliminar fila/s")
		self.layout.addWidget(self.btn_eliminar)
		self.layout.addWidget(self.table) #Agregar la tabla al layout
		#Establecer conexión a la base de datos MySql
		self.db = QSqlDatabase.addDatabase('QMYSQL')
		self.db.setHostName("localhost")
		self.db.setDatabaseName("usuarios")
		self.db.setUserName("root")
		self.db.setPassword("password")	
		self.Seleccionar()
		self.table.itemChanged.connect(self.Actualizar)
		self.btn_eliminar.clicked.connect(self.Eliminar)
		
	def Seleccionar(self):
		estado = self.db.open()
		if estado == False:
			QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
		else:
			self.table.setColumnCount(3)
			self.table.setHorizontalHeaderLabels(['id', 'nombre', 'edad'])
			row = 0
			sql = "SELECT * FROM usuarios"
			query = QSqlQuery(sql)
			while query.next():
				self.table.insertRow(row)
				id = QTableWidgetItem(str(query.value(0)))
				nombre = QTableWidgetItem(str(query.value(1)))
				edad = QTableWidgetItem(str(query.value(2)))
				self.table.setItem(row, 0, id)
				self.table.setItem(row, 1, nombre)
				self.table.setItem(row, 2, edad)
				row = row + 1
		self.db.close()
		
	def Actualizar(self):
		estado = self.db.open()
		if estado == False:
			QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
		else:
			column = self.table.currentColumn()
			row = self.table.currentRow()
			id = self.table.item(row, 0).text()
			value = self.table.currentItem().text()
			columns = ['id', 'nombre', 'edad']
			query = QSqlQuery()
			sql = "UPDATE usuarios SET " + columns[column] + "=" + ":value WHERE id=:id"
			query.prepare(sql)
			query.bindValue(":id", id)
			query.bindValue(":value", value)
			estado = query.exec_()
			if estado == False:
				QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
		self.db.close()
	
	def Eliminar(self):
		estado = self.db.open()
		if estado == False:
			QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
		else:
			rows = self.table.selectionModel().selectedRows()
			index = []
			for i in rows:
				index.append(i.row())
			index.sort(reverse=True)
			for i in index:
				id = self.table.item(i, 0).text()
				self.table.removeRow(i)
				sql = "DELETE FROM usuarios WHERE id=:id"
				query = QSqlQuery()
				query.prepare(sql)
				query.bindValue(":id", id)
				estado = query.exec_()
				if estado == False:
					QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
		self.db.close()
					
app = QApplication(sys.argv)
dialogo = Dialogo()
dialogo.show()
app.exec_()


viernes, 24 de julio de 2015

22 - Python PyQt (Interfaz gráfica) - QtSql MySQL y QTableWidget (Actualizar registros)




En este capítulo del tutorial de Python 3 más PyQt5 continuamos realizando consultas a bases de datos MySQL, basándonos en la aplicación del capítulo anterior: http://jquery-manual.blogspot.com.es/2015/07/21-python-pyqt-interfaz-grafica-qtsql.html donde pudimos ver como seleccionar los registros de la tabla usuarios para incluirlos en un objeto de la clase QTableWidget, este objeto es de gran utilidad para mantener un enlace directo con la base de datos, ya que permite la edición de campos (items). El objetivo es actualizar un determinado campo cada vez que el usuario ha realizado una modificación en el mismo, y para ello haremos uso del evento itemChanged de la clase QTableWidget.



administrar.pyw


import sys
from PyQt5.QtWidgets import QApplication, QDialog, QGridLayout, QMessageBox, QTableWidget, QTableWidgetItem
from PyQt5 import uic
from PyQt5.QtSql import QSqlDatabase, QSqlQuery

class Dialogo(QDialog):
 def __init__(self):
  QDialog.__init__(self)
  self.setWindowTitle("Administrar usuarios") #Título
  self.resize(800, 600) #Tamaño inicial
  self.layout = QGridLayout() #Crear un layout grid
  self.setLayout(self.layout) #Agregar el layout al cuadro de diálogo
  self.table = QTableWidget() #Crear la tabla
  self.layout.addWidget(self.table) #Agregar la tabla al layout
  #Establecer conexión a la base de datos MySql
  self.db = QSqlDatabase.addDatabase('QMYSQL')
  self.db.setHostName("localhost")
  self.db.setDatabaseName("usuarios")
  self.db.setUserName("root")
  self.db.setPassword("password") 
  self.Seleccionar()
  self.table.itemChanged.connect(self.Actualizar)
  
 def Seleccionar(self):
  estado = self.db.open()
  if estado == False:
   QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
  else:
   self.table.setColumnCount(3)
   self.table.setHorizontalHeaderLabels(['id', 'nombre', 'edad'])
   row = 0
   sql = "SELECT * FROM usuarios"
   query = QSqlQuery(sql)
   while query.next():
    self.table.insertRow(row)
    id = QTableWidgetItem(str(query.value(0)))
    nombre = QTableWidgetItem(str(query.value(1)))
    edad = QTableWidgetItem(str(query.value(2)))
    self.table.setItem(row, 0, id)
    self.table.setItem(row, 1, nombre)
    self.table.setItem(row, 2, edad)
    row = row + 1
  self.db.close()
  
 def Actualizar(self):
  estado = self.db.open()
  if estado == False:
   QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
  else:
   column = self.table.currentColumn()
   row = self.table.currentRow()
   id = self.table.item(row, 0).text()
   value = self.table.currentItem().text()
   columns = ['id', 'nombre', 'edad']
   query = QSqlQuery()
   sql = "UPDATE usuarios SET " + columns[column] + "=" + ":value WHERE id=:id"
   query.prepare(sql)
   query.bindValue(":id", id)
   query.bindValue(":value", value)
   estado = query.exec_()
   if estado == False:
    QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
  self.db.close()
     
app = QApplication(sys.argv)
dialogo = Dialogo()
dialogo.show()
app.exec_()


domingo, 12 de julio de 2015

20 - Python PyQt (Interfaz gráfica) - QtSql MySQL (Insertar datos)




En este capítulo del tutorial de Python 3 más PyQt5 veremos como conectar a bases de datos MySQL y generaremos una consulta para insertar registros en una determinada tabla, para ello utilizaremos las clases que proporciona el módulo QtSql.

Para el ejemplo crearemos una base de datos Mysql llamada usuarios, a la cuál agregaremos una tabla también llamada usuarios con las siguientes columnas:
  • id : del tipo INT, Autoincrementable y clave primaria
  • nombre : del tipo VARCHAR y con una longitud de 50
  • edad : del tipo INT

Del módulo QtSql utilizaremos las dos siguiente clases:

QSqlDatabase: para establecer la conexión a la base de datos
QSqlQuery: para generar la consulta





insertar.pyw


import sys
from PyQt5.QtWidgets import QApplication, QDialog, QGridLayout, QMessageBox, QLabel, QPushButton, QLineEdit, QSpinBox
from PyQt5 import uic
from PyQt5.QtSql import QSqlDatabase, QSqlQuery

class Dialogo(QDialog):
 def __init__(self):
  QDialog.__init__(self)
  self.setWindowTitle("Insertar datos") #Título
  self.resize(300, 300) #Tamaño inicial
  self.setMinimumSize(300, 300) #Tamaño mínimo
  self.setMaximumSize(300, 300) #Tamaño máximo
  self.layout = QGridLayout() #Crear un layout grid
  self.setLayout(self.layout) #Agregar el layout al cuadro de diálogo
  self.label_nombre = QLabel("Nombre:") #Etiqueta nombre
  self.txt_nombre = QLineEdit() #Campo para ingresar el nombre
  self.label_edad = QLabel("Edad:") #Etiqueta edad
  self.txt_edad = QSpinBox() #Campo para ingresar la edad
  #Botones
  self.btn_insertar = QPushButton("Insertar")
  self.btn_cancelar = QPushButton("Cancelar")
  #Agregar elementos al layout divido en dos columnas
  self.layout.addWidget(self.label_nombre, 1, 1)
  self.layout.addWidget(self.txt_nombre, 1, 2)
  self.layout.addWidget(self.label_edad, 2, 1)
  self.layout.addWidget(self.txt_edad, 2, 2)
  self.layoutButton = QGridLayout() #Layout para agrupar los botones
  #Agregar los botones al layoutButton
  self.layoutButton.addWidget(self.btn_insertar, 1, 1)
  self.layoutButton.addWidget(self.btn_cancelar, 1, 2)
  #Agregar el layoutButton en la fila 3 columna 2
  self.layout.addLayout(self.layoutButton, 3, 2)
  
  #Establecer conexión a la base de datos MySql
  self.db = QSqlDatabase.addDatabase('QMYSQL')
  self.db.setHostName("localhost")
  self.db.setDatabaseName("usuarios")
  self.db.setUserName("root")
  self.db.setPassword("password")
  
  self.btn_insertar.clicked.connect(self.Insertar)
  self.btn_cancelar.clicked.connect(self.Cancelar)
  
 def Insertar(self):
  estado = self.db.open()
  if estado == False:
   QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
  else:
   nombre = self.txt_nombre.text()
   edad = self.txt_edad.text()
   sql = "INSERT INTO usuarios(nombre, edad) VALUES (:nombre, :edad)"
   consulta = QSqlQuery()
   consulta.prepare(sql)
   consulta.bindValue(":nombre", nombre)
   consulta.bindValue(":edad", edad)
   estado = consulta.exec_()
   if estado == True:
    QMessageBox.information(self, "Correcto", "Datos guardados", QMessageBox.Discard)
   else:
    QMessageBox.warning(self, "Error", self.db.lastError().text(), QMessageBox.Discard)
    
   self.db.close()
 
 def Cancelar(self):
  self.close()
     
app = QApplication(sys.argv)
dialogo = Dialogo()
dialogo.show()
app.exec_()


viernes, 10 de julio de 2015

18 - Python PyQt (Interfaz gráfica) - QGraphicsView Polygon (Dibujar polígonos)




En este capítulo del tutorial de Python 3 más PyQt5 nos basaremos en el sencillo programa de los dos capítulos anteriores el cual nos permite crear gráficos con diferentes herramientas. Concretamente veremos como dibujar polígonos o también conocidos como polilíneas.

Capítulos anteriores:


El procedimiento será el siguiente: al hacer click y soltar el mouse en un lugar del plano de dibujo almacenaremos ese punto QPointF(x, y) en una lista, el usuario podrá agregar tantos puntos como necesite, cada punto señalado en el plano marcará el punto de unión de cada línea del polígono.

Para crear el polígono utilizaremos el siguiente método: addPolygon(QPolygonF(), QPen(), QBrush())


graficos.pyw


import sys
from PyQt5.QtWidgets import QApplication, QDialog, QGraphicsView, QGraphicsScene, QGridLayout, QPushButton, QComboBox
from PyQt5.QtCore import QPointF, QRectF, Qt
from PyQt5.QtGui import QPen, QBrush, QPolygonF
from PyQt5 import uic

class Paint(QGraphicsView):
 def __init__(self):
  QGraphicsView.__init__(self)
  self.setSceneRect(QRectF(self.viewport().rect()))
  self.scene = QGraphicsScene()
  self.isPaint = False
  self.isDelete = False
  self.isClear = False
  self.isObject = None
  self.startX = None
  self.startY = None
  self.pointPolygon = None
  self.arrayPolygon = []
  
  
 def tools(self, e):
  if self.isPaint == True:
   pen = QPen(Qt.black)
   brush = QBrush(Qt.SolidPattern)
   self.scene.addItem(self.scene.addEllipse(e.x(), e.y(), 3, 3, pen, brush))
   self.setScene(self.scene)
  if self.isDelete == True:
   items = self.items(e.x(), e.y())
   for item in items:
    self.scene.removeItem(item)
    
 def paintObject(self, e):
  if self.isObject != None:
   object = self.isObject
   if object == 1: #Line
    pen = QPen(Qt.black)
    self.scene.addItem(self.scene.addLine(self.startX, self.startY, e.x(), e.y(), pen))
    self.setScene(self.scene)
   elif object == 2: #Rect
    pen = QPen(Qt.black)
    brush = QBrush(Qt.SolidPattern)
    self.scene.addItem(self.scene.addRect(self.startX, self.startY, e.x()-self.startX, e.y()-self.startY, pen, brush))
    self.setScene(self.scene)
   elif object == 3: #Ellipse
    pen = QPen(Qt.black)
    brush = QBrush(Qt.SolidPattern)
    self.scene.addItem(self.scene.addEllipse(self.startX, self.startY, e.x()-self.startX, e.y()-self.startY, pen, brush))
    self.setScene(self.scene)
    
 def paintPolygon(self, e):
  if self.isObject != None:
   object = self.isObject
   if object == 4: #Polygon
    self.pointPolygon = QPointF(e.x(), e.y())
    self.arrayPolygon.append(self.pointPolygon)
    pen = QPen(Qt.green)
    brush = QBrush()
    self.scene.addItem(self.scene.addPolygon(QPolygonF(self.arrayPolygon), pen, brush))
    self.setScene(self.scene)
    
    
 def mousePressEvent(self, event):
  e = QPointF(self.mapToScene(event.pos()))
  self.tools(e)
  self.startX = e.x()
  self.startY = e.y()
  
 def mouseReleaseEvent(self, event):
  e = QPointF(self.mapToScene(event.pos()))
  self.paintObject(e)
  self.paintPolygon(e)
  
 def mouseMoveEvent(self, event):
  e = QPointF(self.mapToScene(event.pos()))
  self.tools(e)

class Dialogo(QDialog):
 def __init__(self):
  QDialog.__init__(self)
  self.resize(500, 500)
  self.layout = QGridLayout()
  self.setLayout(self.layout)
  self.paint = Paint()
  self.btn_paint = QPushButton("Dibujar")
  self.combo_object = QComboBox()
  self.combo_object.addItem("Seleccionar")
  self.combo_object.addItem("Line")
  self.combo_object.addItem("Rect")
  self.combo_object.addItem("Ellipse")
  self.combo_object.addItem("Polygon")
  self.btn_delete = QPushButton("Borrar")
  self.btn_clear = QPushButton("Clear")
  self.layout.addWidget(self.btn_paint)
  self.layout.addWidget(self.combo_object)
  self.layout.addWidget(self.btn_delete)
  self.layout.addWidget(self.btn_clear)
  self.layout.addWidget(self.paint)
  self.btnDefault = "background-color: grey; border: 0; padding: 10px"
  self.btnActive = "background-color: orange; border: 0; padding: 10px"
  
  self.btn_paint.setStyleSheet(self.btnDefault)
  self.combo_object.setStyleSheet(self.btnDefault)
  self.btn_delete.setStyleSheet(self.btnDefault)
  self.btn_clear.setStyleSheet(self.btnDefault)
  
  self.btn_paint.clicked.connect(self.isPaint)
  self.combo_object.currentIndexChanged.connect(self.isObject)
  self.combo_object.activated.connect(self.isObject)
  self.btn_delete.clicked.connect(self.isDelete)
  self.btn_clear.clicked.connect(self.isClear)
  
 def resizeEvent(self, event):
  self.paint.setSceneRect(QRectF(self.paint.viewport().rect()))
   
 def isPaint(self):
  if self.paint.isPaint == False:
   self.paint.isPaint = True
   self.btn_paint.setStyleSheet(self.btnActive)
  else:
   self.paint.isPaint = False
   self.btn_paint.setStyleSheet(self.btnDefault)
  
  self.paint.isObject = None  
  self.paint.isDelete = False
  self.paint.isClear = False
  self.btn_delete.setStyleSheet(self.btnDefault)
  self.btn_clear.setStyleSheet(self.btnDefault)
  del self.paint.arrayPolygon[:]
  
 def isObject(self):
  object = self.combo_object.currentIndex()
  self.paint.isObject = object
  self.paint.isPaint = False
  self.paint.isDelete = False
  self.paint.isClear = False
  self.btn_paint.setStyleSheet(self.btnDefault)
  self.btn_delete.setStyleSheet(self.btnDefault)
  self.btn_clear.setStyleSheet(self.btnDefault)
  del self.paint.arrayPolygon[:]
  
   
 def isDelete(self):
  if self.paint.isDelete == False:
   self.paint.isDelete = True
   self.btn_delete.setStyleSheet(self.btnActive)
  else:
   self.paint.isDelete = False
   self.btn_delete.setStyleSheet(self.btnDefault)
   
  self.paint.isObject = None 
  self.paint.isPaint = False
  self.paint.isClear = False
  self.btn_paint.setStyleSheet(self.btnDefault)
  self.btn_clear.setStyleSheet(self.btnDefault)
  del self.paint.arrayPolygon[:]
  
 def isClear(self):
  if self.paint.isClear == False:
   self.paint.isClear = True
   self.btn_clear.setStyleSheet(self.btnActive)
  else:
   self.paint.isClear = False
   self.btn_clear.setStyleSheet(self.btnDefault)
   
  self.paint.isObject = None 
  self.paint.isPaint = False
  self.paint.isDelete = False
  self.btn_paint.setStyleSheet(self.btnDefault)
  self.btn_delete.setStyleSheet(self.btnDefault)
  self.paint.scene.clear()
  del self.paint.arrayPolygon[:]
  
app = QApplication(sys.argv)
dialogo = Dialogo()
dialogo.show()
app.exec_()


jueves, 9 de julio de 2015

17 - Python PyQt (Interfaz gráfica) - Dibujar objetos (addLine, addRect & addEllipse)




En este capítulo del tutorial Python 3 más PyQt5 veremos como agregar objetos como pueden ser líneas, objetos rectángulares y elipses al plano de dibujo (QGraphicsView), este capítulo básicamente es la continuación del capítulo anterior: http://jquery-manual.blogspot.com/2015/07/16-python-pyqt-interfaz-grafica.html. 

Para poder agregar dichos objetos a la escena utilizaremos los siguientes métodos de la clase QGraphicsScene:

Agrega una línea: addLine(x1, y1, x2, y2, QPen) 
Agrega un objeto rectángular: addRect(x, y, width, height, QPen, QBrush)
Agrega un objeto elíptico: addEllipse(x, y, width, height, QPen, QBrush)

La posición inicial x e y será obtenida por el evento MousePressEvent, es decir, cuando el usuario haga click en el plano de dibujo.

La posición final x e y será obtenida por el evento MouseReleaseEvent, es decir, cuando el usuario suelte el mouse en el plano de dibujo.


graficos.pyw


import sys
from PyQt5.QtWidgets import QApplication, QDialog, QGraphicsView, QGraphicsScene, QGridLayout, QPushButton, QComboBox
from PyQt5.QtCore import QPointF, QRectF, Qt
from PyQt5.QtGui import QPen, QBrush
from PyQt5 import uic

class Paint(QGraphicsView):
 def __init__(self):
  QGraphicsView.__init__(self)
  self.setSceneRect(QRectF(self.viewport().rect()))
  self.scene = QGraphicsScene()
  self.isPaint = False
  self.isDelete = False
  self.isClear = False
  self.isObject = None
  self.startX = None
  self.startY = None
  
 def tools(self, e):
  if self.isPaint == True:
   pen = QPen(Qt.black)
   brush = QBrush(Qt.SolidPattern)
   self.scene.addItem(self.scene.addEllipse(e.x(), e.y(), 3, 3, pen, brush))
   self.setScene(self.scene)
  if self.isDelete == True:
   items = self.items(e.x(), e.y())
   for item in items:
    self.scene.removeItem(item)
    
 def paintObject(self, e):
  if self.isObject != None:
   object = self.isObject
   if object == 1: #Line
    pen = QPen(Qt.black)
    self.scene.addItem(self.scene.addLine(self.startX, self.startY, e.x(), e.y(), pen))
    self.setScene(self.scene)
   elif object == 2: #Rect
    pen = QPen(Qt.black)
    brush = QBrush(Qt.SolidPattern)
    self.scene.addItem(self.scene.addRect(self.startX, self.startY, e.x()-self.startX, e.y()-self.startY, pen, brush))
    self.setScene(self.scene)
   elif object == 3: #Ellipse
    pen = QPen(Qt.black)
    brush = QBrush(Qt.SolidPattern)
    self.scene.addItem(self.scene.addEllipse(self.startX, self.startY, e.x()-self.startX, e.y()-self.startY, pen, brush))
    self.setScene(self.scene)
    
    
 def mousePressEvent(self, event):
  e = QPointF(self.mapToScene(event.pos()))
  self.tools(e)
  self.startX = e.x()
  self.startY = e.y()
  
 def mouseReleaseEvent(self, event):
  e = QPointF(self.mapToScene(event.pos()))
  self.paintObject(e)
  
 def mouseMoveEvent(self, event):
  e = QPointF(self.mapToScene(event.pos()))
  self.tools(e)

class Dialogo(QDialog):
 def __init__(self):
  QDialog.__init__(self)
  self.resize(500, 500)
  self.layout = QGridLayout()
  self.setLayout(self.layout)
  self.paint = Paint()
  self.btn_paint = QPushButton("Dibujar")
  self.combo_object = QComboBox()
  self.combo_object.addItem("Seleccionar")
  self.combo_object.addItem("Line")
  self.combo_object.addItem("Rect")
  self.combo_object.addItem("Ellipse")
  self.btn_delete = QPushButton("Borrar")
  self.btn_clear = QPushButton("Clear")
  self.layout.addWidget(self.btn_paint)
  self.layout.addWidget(self.combo_object)
  self.layout.addWidget(self.btn_delete)
  self.layout.addWidget(self.btn_clear)
  self.layout.addWidget(self.paint)
  self.btnDefault = "background-color: grey; border: 0; padding: 10px"
  self.btnActive = "background-color: orange; border: 0; padding: 10px"
  
  self.btn_paint.setStyleSheet(self.btnDefault)
  self.combo_object.setStyleSheet(self.btnDefault)
  self.btn_delete.setStyleSheet(self.btnDefault)
  self.btn_clear.setStyleSheet(self.btnDefault)
  
  self.btn_paint.clicked.connect(self.isPaint)
  self.combo_object.currentIndexChanged.connect(self.isObject)
  self.btn_delete.clicked.connect(self.isDelete)
  self.btn_clear.clicked.connect(self.isClear)
  
 def resizeEvent(self, event):
  self.paint.setSceneRect(QRectF(self.paint.viewport().rect()))
   
 def isPaint(self):
  if self.paint.isPaint == False:
   self.paint.isPaint = True
   self.btn_paint.setStyleSheet(self.btnActive)
  else:
   self.paint.isPaint = False
   self.btn_paint.setStyleSheet(self.btnDefault)
  
  self.paint.isObject = None  
  self.paint.isDelete = False
  self.paint.isClear = False
  self.btn_delete.setStyleSheet(self.btnDefault)
  self.btn_clear.setStyleSheet(self.btnDefault)
  
 def isObject(self):
  object = self.combo_object.currentIndex()
  self.paint.isObject = object
  self.paint.isPaint = False
  self.paint.isDelete = False
  self.paint.isClear = False
  self.btn_paint.setStyleSheet(self.btnDefault)
  self.btn_delete.setStyleSheet(self.btnDefault)
  self.btn_clear.setStyleSheet(self.btnDefault)
  
   
 def isDelete(self):
  if self.paint.isDelete == False:
   self.paint.isDelete = True
   self.btn_delete.setStyleSheet(self.btnActive)
  else:
   self.paint.isDelete = False
   self.btn_delete.setStyleSheet(self.btnDefault)
   
  self.paint.isObject = None 
  self.paint.isPaint = False
  self.paint.isClear = False
  self.btn_paint.setStyleSheet(self.btnDefault)
  self.btn_clear.setStyleSheet(self.btnDefault)
  
 def isClear(self):
  if self.paint.isClear == False:
   self.paint.isClear = True
   self.btn_clear.setStyleSheet(self.btnActive)
  else:
   self.paint.isClear = False
   self.btn_clear.setStyleSheet(self.btnDefault)
   
  self.paint.isObject = None 
  self.paint.isPaint = False
  self.paint.isDelete = False
  self.btn_paint.setStyleSheet(self.btnDefault)
  self.btn_delete.setStyleSheet(self.btnDefault)
  self.paint.scene.clear()
  
app = QApplication(sys.argv)
dialogo = Dialogo()
dialogo.show()
app.exec_()


jueves, 2 de julio de 2015

13 - Python PyQt (Interfaz gráfica) - WebKit (Navegador Web con pestañas de navegación)




En este capítulo del tutorial de Python 3 más PyQt5 veremos lo útil que es trabajar con objetos de la clase QTabWidget, para ello nos basaremos en crear un navegador con las herramientas de WebKit y apoyándonos en un Tab Widget para ir agregando o eliminando páginas de navegación mediante los conocidos tabs o pestañas.


Crearemos un archivo ui con Designer en una ventana principal (Main Window) al cual agregaremos:

  • Un objeto Tab Widget con nombre tabWidget que es el que viene por defecto.
  • Un objeto Push Button con nombre btn_mas y como texto el signo "+" para agregar páginas.
  • Un objeto Push Button con nombre btn_menos y como texto el signo "-" para eliminar páginas.
  • Un objeto Line Edit con nombre url para la navegación.
  • Agrupar los elementos en un Lay Out in a Grid.
  • Guardar el archivo como webkit-tab.ui

webkit-tab.pyw


import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import QUrl
from PyQt5.QtWebKitWidgets import QWebView
from PyQt5 import uic

class Navegador(QMainWindow):
 def __init__(self):
  QMainWindow.__init__(self)
  uic.loadUi("webkit-tab.ui", self)
  self.pages = [] #array donde se guardará cada página objeto
  self.index = 0 #Al crear o eliminar tabs incrementar o disminuir el index
  self.add_tab() #Crear un tab por defecto
  
  #Agregar un nuevo tab con página
  self.btn_mas.clicked.connect(self.add_tab)
  #Eliminar un tab
  self.btn_menos.clicked.connect(self.remove_tab)
  #Cargar información de la página activa al terminar de cargarla
  self.pages[self.tabWidget.currentIndex()].loadFinished.connect(self.getInfo)
  #Actualizar información de la página del tab activo
  self.tabWidget.currentChanged.connect(self.current_changed)
  #Buscar la url indicada por el usuario
  self.url.returnPressed.connect(self.search)
 
 
 #Agregar un nuevo tab con página
 def add_tab(self):
  #Comprobar el número de páginas/tabs e incrementar en 1 para el index del nuevo elemento
  if len(self.pages) > 0:
   for i in range(len(self.pages)):
    self.index = i + 1
  #Crear objeto página
  pagina = QWebView()
  #Agregar objeto página al array pages
  self.pages.append(pagina)
  #Cargar la url por defecto
  self.pages[self.index].load(QUrl("http://www.google.com"))
  #Agregar el objeto página a un nuevo tab
  self.tabWidget.addTab(self.pages[self.index], "")
  #Poner el foco en el nuevo tab
  self.tabWidget.setCurrentIndex(self.index)
  
 def getInfo(self):
  #Index del tab que tiene el foco
  index = self.tabWidget.currentIndex()
  #Título de la página web
  title = self.pages[index].title()
  #Agregar título al tab
  self.tabWidget.setTabText(index, title)
  #Agregar título a la ventana
  self.setWindowTitle(title)
  #Actualizar la url del buscador
  url = self.pages[index].url()
  self.url.setText(url.toString())
  
  
 def current_changed(self):
  #Index del tab que tiene el foco
  index = self.tabWidget.currentIndex()
  #Actualizar la información de la página si un tab obtiene el foco
  self.pages[index].loadFinished.connect(self.getInfo)
  #Título de la página web
  title = self.pages[index].title()
  #Agregar título al tab
  self.tabWidget.setTabText(index, title)
  #Agregar título a la ventana
  self.setWindowTitle(title)
  #Actualizar la url del buscador
  url = self.pages[index].url()
  self.url.setText(url.toString())
  
 def search(self):
  #Url del campo de búsqueda
  url = QUrl(self.url.text())
  #Obtener el index del tab que tiene el foco
  index = self.tabWidget.currentIndex()
  #Navegar a la url
  self.pages[index].setUrl(url)
  
 def remove_tab(self):
  #Obtener el index del tab que tiene el foco
  index = self.tabWidget.currentIndex()
  #Eliminar el tab
  self.tabWidget.removeTab(index)
  #Eliminar la página objeto del array pages
  self.pages.pop(index)
  #Actualizar el valor del atributo index
  if self.index > 0: self.index = self.index - 1
  #Actualizar la información del tab que obtendrá el foco tras la eliminación del seleccionado
  self.current_changed()
  
app = QApplication(sys.argv)
navegador = Navegador()
navegador.show()
app.exec_()