Dialog creation/es

En esta página vamos a mostrar cómo crear un simple diálogo con Qt Designer, la herramienta oficial de Qt para el diseño de interfaces, después convertirlo a código python, para luego usarla en el interior de FreeCAD. Vamos a suponer en el ejemplo que usted ya sabe cómo editar y ejecutar scripts python, y que usted puede hacer cosas simples en una ventana de terminal, como navegar, etc También debe tener, por supuesto, PyQt instalado.

Diseñar el cuadro de diálogo
En las aplicaciones de CAD, el diseño de una buena interfaz de usuario (UI, User Interface) es muy importante. Casi todo lo que el usuario haga será a través de alguna pieza de la interfaz: leyendo los cuadros de diálogo, pulsando los botones, eligiendo entre iconos, etc. Así que es muy importante pensar cuidadosamente sobre lo que quiere hacer, cómo desea que el usuario se comporte, y cómo será el flujo de trabajo de su acción.

Hay un par de conceptos que debe saber a la hora de diseñar la interfaz:


 * Modal/non-modal dialogs: Un cuadro de diálogo modal aparece delante de la pantalla, deteniendo la acción de la ventana principal, obligando al usuario a responder al cuadro de diálogo, mientras que un cuadro de diálogo no modal permite seguir el trabajo en la ventana principal. En algunos casos la primera opción es mejor, pero en otros casos no.
 * Identificación de lo que es necesario y lo que es opcional: Asegúrese de que el usuario sabe lo que debe hacer. Etiquete todo con la descripción adecuada, información sobre el uso de las herramientas, etc
 * Separar los comandos de los parámetros: Esto se hace generalmente con botones y campos de entrada de texto. El usuario sabe que al hacer clic en un botón, se produce una acción mientras que al cambiar un valor dentro de un campo de texto va a cambiar un parámetro en alguna parte. Hoy en día, sin embargo, los usuarios suelen conocer bien lo que es un botón, lo que es un campo de entrada, etc El conjunto de herramientas de interfaz que está utilizando, Qt, es el estado del arte de los toolkits, y no tendrá que preocuparse mucho de hacer las cosas claras, puesto que ya va a ser muy clara por sí mismos.

Así que, ahora que tenemos bien definido lo que haremos, es el momento para abrir el diseñador de qt (designer). Diseñemos un diálogo muy sencillo, como esto:



Despues podremos entonces este cuadro de diálogo en FreeCAD para producir un plano rectangular, bonito. Puede que no vea muy útil hacer planos rectangulares, pero será fácil cambiarlo más adelante para hacer cosas más complejas. Cuando lo abre, el aspecto de Qt Designer es el siguiente:



Es muy sencillo de utilizar. En la barra de la izquierda tiene elementos que pueden ser arrastrados a su widget. En el lado derecho tiene los paneles de propiedades mostrando todo tipo de propiedades editables de los elementos seleccionados. Comencemos ahora con la creación de un nuevo widget. Seleccione "diálogo sin botones", ya que no queremos el formato predeterminado de botones Ok/Cancelar. A continuación, arrastre sobre su widget 3 etiquetas, una para el título, una para escribir "Altura" y otra para escribir "Ancho". Las etiquetas son textos sencillos que aparecen en su widget, simplemente para informar al usuario. Si selecciona una etiqueta, en la parte derecha aparecerán varias propiedades que puede cambiar si lo desea, como el estilo de fuente, altura, etc.

A continuación, agregue 2 LineEdits, que son campos de texto que el usuario puede rellenar, uno para la altura y uno para el ancho. También en este caso, podemos editar las propiedades. Por ejemplo, ¿por qué no establecer un valor predeterminado? digamos 1.00 para cada uno. De esta manera, cuando el usuario vea el cuadro de diálogo, ambos campos ya estarán rellenados, y si está conforme puede pulsar el botón directamente, ahorrando un tiempo precioso. A continuación, agregue un PushButton, que es el botón que el usuario deberá pulsar después de llenar los 2 campos.

Tenga en cuenta que he elegido aquí controles muy sencillos, pero Qt tiene muchas más opciones, por ejemplo, podría utilizar Spinboxes en lugar de LineEdits, etc .. Eche un vistazo a lo que está disponible, seguramente tendrá otras ideas.

Eso es prácticamente todo lo que necesitamos hacer en Qt Designer. Una última cosa, sin embargo, vamos a cambiar el nombre de todos nuestros elementos con nombres más adecuados, de modo que sea más fácil identificarlos en nuestros scripts:



Convertir nuestro diálogo a Python
Ahora, vamos a salvar nuestro widget en alguna parte. Se guardará como un archivo .ui, que fácilmente se convertirá en un script python por medio de pyuic. En Windows, el programa pyuic se ve enriquecido con PyQt (por verificar), en linux es probable que tenga que instalarlo por separado desde su gestor de paquetes (en sistemas basados en Debian, es parte del paquete de herramientas PyQt4-dev-tools). Para realizar la conversión, usted tendrá que abrir una ventana de terminal (o una ventana de símbolo de sistema en Windows), vaya a donde guardó el archivo .ui, y escriba:

pyuic mywidget.ui > mywidget.py

En algunos sistemas el programa se llama pyuic4 en lugar de pyuic. Esa operación simplemente convertirá el archivo .ui en un script python. Si abrimos el archivo mywidget.py, su contenido es muy fácil de entender:

from PyQt4 import QtCore, QtGui class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(187, 178) self.title = QtGui.QLabel(Dialog) self.title.setGeometry(QtCore.QRect(10, 10, 271, 16)) self.title.setObjectName("title") self.label_width = QtGui.QLabel(Dialog) ...        self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8)) self.title.setText(QtGui.QApplication.translate("Dialog", "Plane-O-Matic", None, QtGui.QApplication.UnicodeUTF8)) ...

Como verá, tiene una estructura muy simple: se crea una clase denominada Ui_Dialog, que almacena los elementos de interfaz de nuestro widget. Esa clase tiene dos métodos, uno para la configuración del widget, y otro para la traducción de su contenido, que forma parte del mecanismo general de Qt para la traducción de elementos de la interfaz. El método de configuración simplemente crea, uno por uno, los widgets tal como usted los haya definido en Qt Designer, y establece sus opciones, como hayamos decidido con anterioridad. Despues, toda la interfaz se traduce, y por último, se conectan las ranuras (slots) (hablaremos de eso más adelante).

Ahora podemos crear un nuevo widget, y utilizar esta clase para crear su interfaz. Ya podemos ver nuestro widget en acción, poniendo nuestro archivo mywidget.py en un lugar donde FreeCAD lo encontrará (en el directorio bin FreeCAD, o en cualquiera de los subdirectorios Mod), y, escribiendo en el intérprete de Python FreeCAD, ejecutamos:

from PyQt4 import QtGui import mywidget d = QtGui.QWidget d.ui = mywidget.Ui_Dialog d.ui.setupUi(d) d.show

¡Y nuestro diálogo aparecerá! Tenga en cuenta que nuestro intérprete python todavía está trabajando, ya que hemos usado un cuadro de diálogo no modal. Por lo tanto, para cerrarlo, podemos (aparte de hacer clic en el icono de cerrar, por supuesto) escribir:

d.hide

Hacer algo con nuestro diálogo
Ahora que podemos mostrar y ocultar nuestro diálogo, sólo tenemos que añadir una última parte: ¡que haga algo! Si juega un poco con el diseñador Qt, usted descubrirá rápidamente toda una sección llamada "señales y slots". Básicamente, funciona así: los elementos de los widgets (en la terminología de Qt, estos elementos son a su vez widgets) pueden enviar señales. Estas señales varían según el tipo de widget (artilugio). Por ejemplo, un botón puede enviar una señal cuando se presiona y cuando es soltado. Estas señales se pueden conectar a los slots, que puede ser una funcionalidad especial de otros widgets (por ejemplo, un cuadro de diálogo tiene un slot (ranura) "close" (cerrado) en el que se puede conectar la señal de un botón close (de cierre)), o pueden ser funciones de usuario. El PyQt Reference Documentation enumera todos los widgets qt, lo que pueden hacer, que señales pueden enviar, etc ..

Lo que haremos aquí, es crear una nueva función que va a formar un plano basado en la altura y anchura, y conectar dicha función a la señal de "pulsado" emitida por nuestro botón "Create!". Empezaremos con la importación de nuestros módulos FreeCAD, poniendo la siguiente línea al comienzo del script, donde ya hemos mandado también la importación de QtCore y QtGui:

import FreeCAD, Part

ahora, añadamos una nueva función a nuestra clase Ui_Dialog:

def createPlane(self): try: # first we check if valid numbers have been entered w = float(self.width.text) h = float(self.height.text) except ValueError: print "Error! Width and Height values must be valid numbers!" else: # create a face from 4 points p1 = FreeCAD.Vector(0,0,0) p2 = FreeCAD.Vector(w,0,0) p3 = FreeCAD.Vector(w,h,0) p4 = FreeCAD.Vector(0,h,0) pointslist = [p1,p2,p3,p4,p1] mywire = Part.makePolygon(pointslist) myface = Part.Face(mywire) Part.show(myface) self.hide

A continuación, tenemos que informar a Qt para que conecte el botón con la función, mediante la colocación de la siguiente línea justo antes de QtCore.QMetaObject.connectSlotsByName(Dialog):

QtCore.QObject.connect(self.create,QtCore.SIGNAL("pressed"),self.createPlane)

Como ve, esto conecta la señal pressed de nuestro objeto create (el Botón "Create!"), a un slot (espacio, hueco) llamado createPlane, que acabamos de definir. Eso es todo! Ahora, como toque final, podemos añadir una pequeña función para crear el cuadro de diálogo. Así será más fácil hacer las llamadas. Fuera de la clase Ui_Dialog, vamos a añadir este código:

class plane: d = QtGui.QWidget d.ui = Ui_Dialog d.ui.setupUi(d) d.show

A continuación, en FreeCAD, sólo tenemos que hacer:

import mywidget mywidget.plane

Y eso es todo amigos ... Ahora usted puede probar todo tipo de cosas, como por ejemplo insertar su widget en la interfaz de FreeCAD (véase la página Code snippets), o la fabricación de herramientas personalizadas mucho más avanzado, mediante el uso de otros elementos en su widget.

El script completo
Este es el script completo, como referencia:

# # from PyQt4 import QtCore, QtGui import FreeCAD, Part class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(187, 178) self.title = QtGui.QLabel(Dialog) self.title.setGeometry(QtCore.QRect(10, 10, 271, 16)) self.title.setObjectName("title") self.label_width = QtGui.QLabel(Dialog) self.label_width.setGeometry(QtCore.QRect(10, 50, 57, 16)) self.label_width.setObjectName("label_width") self.label_height = QtGui.QLabel(Dialog) self.label_height.setGeometry(QtCore.QRect(10, 90, 57, 16)) self.label_height.setObjectName("label_height") self.width = QtGui.QLineEdit(Dialog) self.width.setGeometry(QtCore.QRect(60, 40, 111, 26)) self.width.setObjectName("width") self.height = QtGui.QLineEdit(Dialog) self.height.setGeometry(QtCore.QRect(60, 80, 111, 26)) self.height.setObjectName("height") self.create = QtGui.QPushButton(Dialog) self.create.setGeometry(QtCore.QRect(50, 140, 83, 26)) self.create.setObjectName("create") self.retranslateUi(Dialog) QtCore.QObject.connect(self.create,QtCore.SIGNAL("pressed"),self.createPlane) QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8)) self.title.setText(QtGui.QApplication.translate("Dialog", "Plane-O-Matic", None, QtGui.QApplication.UnicodeUTF8)) self.label_width.setText(QtGui.QApplication.translate("Dialog", "Width", None, QtGui.QApplication.UnicodeUTF8)) self.label_height.setText(QtGui.QApplication.translate("Dialog", "Height", None, QtGui.QApplication.UnicodeUTF8)) self.create.setText(QtGui.QApplication.translate("Dialog", "Create!", None, QtGui.QApplication.UnicodeUTF8)) def createPlane(self): try: # first we check if valid numbers have been entered w = float(self.width.text) h = float(self.height.text) except ValueError: print "Error! Width and Height values must be valid numbers!" else: # create a face from 4 points p1 = FreeCAD.Vector(0,0,0) p2 = FreeCAD.Vector(w,0,0) p3 = FreeCAD.Vector(w,h,0) p4 = FreeCAD.Vector(0,h,0) pointslist = [p1,p2,p3,p4,p1] mywire = Part.makePolygon(pointslist) myface = Part.Face(mywire) Part.show(myface) class plane: d = QtGui.QWidget d.ui = Ui_Dialog d.ui.setupUi(d) d.show
 * 1) -*- coding: utf-8 -*-
 * 1) Form implementation generated from reading ui file 'mywidget.ui'
 * 1) Created: Mon Jun  1 19:09:10 2009
 * 2)      by: PyQt4 UI code generator 4.4.4
 * 1) WARNING! All changes made in this file will be lost!