Obijuan:Notas sobre programación en python en Freecad

De WikiRobotics
Revisión del 09:19 29 ago 2014 de Obijuan (Discusión | contribuciones) (Hito 5: Script con la gui empotrada en la pestaña task)

Saltar a: navegación, buscar

Introducción

Quiero aprender a programar piezas en Freecad, al estilo openscad, para poder hacer piezas paramétricas.

Empezaremos con ruedas paramétricas para printbots

Roadmap

  1. Hello world: programar un cilindro simple, con los parámetros h (grosor) y diámetro (d)
  2. scripts con GUI
  3. script con gui empotrada en Freecad
  4. Script con una GUI diseñada con QTcreator
  5. Script con la gui empotrada en la pestaña task
  6. Programar la rueda del miniskybot, pero con esos mismos parametros variables
  7. Incluir 2 coronas: pequeña y grande y permitir que se puedan seleccionar una u otra para la rueda
  8. ¿Como crear un boton que al pulsarlo se abra el menú y permita meter una rueda definiendo sus parametros?
  9. ¿Cómo programar un workbench de printbots? que incluya botones con piezas: ruedas, portapilas, chásis...

Hito 0: Leer

Hito 1: programa "hola mundo"

Visualizar un cilindro genérico (el mismo que cuando se le da al botón de cilindro en el workbench part)

import FreeCAD
import Part

doc = App.ActiveDocument
cyl = doc.addObject("Part::Cylinder","Cylinder")
cyl.Label = "Cylinder"
doc.recompute()

Otro ejemplo, con la función cilindro definida, donde se le pasan los parámetros de altura y diámetro

import FreeCAD
import Part

def cylinder(h = 8, d = 56):
    doc = App.ActiveDocument
    cyl = doc.addObject("Part::Cylinder","Cylinder")
    cyl.Label = "Cylinder"
    cyl.Height = h
    cyl.Radius = d / 2.0 
cylinder() cylinder(h = 20, d =10) App.ActiveDocument.recompute()

He encontrado una forma más sencilla de hacer el cilindro:

import FreeCAD
import Part

#-- radius = 56, height = 8
cyl = Part.makeCylinder(56, 8)
Part.show(cyl)

sin embargo el objeto que se crea es un "shape". Las propiedades de altura y radio se pierden. Nos servirá por tanto para construir otros objetos, pero no para hacer algo paramétrico que cambie dinámicamente

Hito 2: Scripts con GUI en FREECAD

Ejemplo hola mundo para sacar una ventana emergente

from PyQt4 import QtGui
QtGui.QMessageBox.information(None,"Titulo","Hola Mundo!")

Ventana desde la que especifiar el lado para hacer un cubo

from PyQt4 import QtGui, QtCore
import Part, FreeCAD
from FreeCAD import Base, Vector

class BoxExample(QtGui.QWidget):
	def __init__(self): 
		super(BoxExample, self).__init__()
		self.initUI()

	def initUI(self):
		self.setGeometry(100, 100, 260, 100)
		self.setWindowTitle('Mi cubo')
		self.lengthLabel = QtGui.QLabel("Lado: ",self)
		self.lengthLabel.move(20, 20)
		self.length = QtGui.QLineEdit(self)
		self.length.move(100, 15)
 		
		self.okButton = QtGui.QPushButton("Crear cubo",self)
		self.okButton.move(20, 60)
		self.show()
		
		QtCore.QObject.connect (self.okButton, QtCore.SIGNAL("pressed()"),self.box)
		
	def box(self):
		l = float(self.length.text())
		box = Part.makeBox(l, l, l)
		Part.show(box)


d = BoxExample()

Hito 3: Script con gui empotrada en Freecad

Widget "hola mundo" empotrado en la gui de Freecad, en la parte de la derecha:

import sys
from PyQt4 import QtGui, QtCore
app = QtGui.qApp
mw = app.activeWindow()

myWidget = QtGui.QDockWidget()
mw.addDockWidget(QtCore.Qt.RightDockWidgetArea,myWidget)

myWidget.setObjectName("my Nice New Widget")
myWidget.resize(QtCore.QSize(300,100)) # sets size of the widget
label = QtGui.QLabel("Hello World", myWidget) # creates a label
label.setGeometry(QtCore.QRect(50,50,200,24)) # sets its size
label.setObjectName("myLabel") # sets its name, so it can be found by name

Hito 4: Script con GUI diseñada con QTdesigner

Hay que instalar el paquete:

  • qt4-designer

El qt designer se ejecuta así:

$ designer-qt4

Con el qt designer se gener un fichero con extensión ui que es el que contiene la interfaz. Esta interfaz se puede pasar a código python mediante el comando:

$ pyuic4 testgui.ui -o python.py

que se instala con:

sudo apt-get install pyqt4-dev-tools

Aquí está integrado en un lateral (aunque por temas de tamaño sale un poco feo, pero funciona)

import sys
from PyQt4 import QtGui, QtCore

app = QtGui.qApp
mw = app.activeWindow()

try:
   _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
   def _fromUtf8(s):
       return s

try:
   _encoding = QtGui.QApplication.UnicodeUTF8
   def _translate(context, text, disambig):
       return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
   def _translate(context, text, disambig):
       return QtGui.QApplication.translate(context, text, disambig)

class Ui_Dialog(object):
   def setupUi(self, Dialog):
       Dialog.setObjectName(_fromUtf8("Dialog"))
       Dialog.resize(400, 300)
       self.buttonBox = QtGui.QDialogButtonBox(Dialog)
       self.buttonBox.setGeometry(QtCore.QRect(30, 240, 341, 32))
       self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
       self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
       self.buttonBox.setObjectName(_fromUtf8("buttonBox"))

       self.retranslateUi(Dialog)
       QtCore.QMetaObject.connectSlotsByName(Dialog)

   def retranslateUi(self, Dialog):
       Dialog.setWindowTitle(_translate("Dialog", "Dialog", None))

myNewFreeCADWidget = QtGui.QDockWidget()
myNewFreeCADWidget.ui = Ui_Dialog() # load the Ui script
myNewFreeCADWidget.ui.setupUi(myNewFreeCADWidget) # setup the ui
mw.addDockWidget(QtCore.Qt.RightDockWidgetArea,myNewFreeCADWidget) # add the widget to the main window

Pregunta: ¿Se puede cargar directamente el fichero ui? --> Buscar!!!!

Hito 5: Script con la gui empotrada en la pestaña task

Este ejemplo esta tomado el banco de trabajo Ship. La GUI está en el fichero TaskPanel.ui. Se carga dinamicamente


import FreeCAD as App
import FreeCADGui as Gui
from PySide import QtGui, QtCore


class TaskPanel:
    def __init__(self):
       """Constructor."""
       self.ui =  "/home/obijuan/.FreeCAD/TaskPanel.ui"
       return

   def reject(self):
       """Cancel the job"""
       return True

   def clicked(self, index):
       pass

   def open(self):
       pass

   def needsFullSpace(self):
       return True

   def isAllowedAlterSelection(self):
       return False

   def isAllowedAlterView(self):
       return True

   def isAllowedAlterDocument(self):
       return False

   def helpRequested(self):
       pass

   def setupUi(self):
       """Setup the task panel user interface."""
       mw = self.getMainWindow()
       form = mw.findChild(QtGui.QWidget, "TaskPanel")
       form.ship = self.widget(QtGui.QComboBox, "Ship")
       form.mainLogo = self.widget(QtGui.QLabel, "MainLogo")
       form.mainLogo.setPixmap(QtGui.QPixmap(":/icons/Ship_Logo.svg"))
       self.form = form
       self.retranslateUi()

   def getMainWindow(self):
       toplevel = QtGui.qApp.topLevelWidgets()
       for i in toplevel:
           if i.metaObject().className() == "Gui::MainWindow":
               return i
       raise Exception("No main window found")

   def widget(self, class_id, name):
       """Return the selected widget.

       Keyword arguments:
       class_id -- Class identifier
       name -- Name of the widget
       """
       mw = self.getMainWindow()
       form = mw.findChild(QtGui.QWidget, "TaskPanel")
       return form.findChild(class_id, name)

   def retranslateUi(self):
       """Set the user interface locale strings."""
       self.form.setWindowTitle(QtGui.QApplication.translate(
           "ship_load",
           "Load example ship",
           None,
           QtGui.QApplication.UnicodeUTF8))
       self.widget(QtGui.QGroupBox, "ShipSelectionBox").setTitle(
           QtGui.QApplication.translate("ship_load",
                                        "Select ship example geometry",
                                        None,
                                        QtGui.QApplication.UnicodeUTF8))

panel = TaskPanel() Gui.Control.showDialog(panel) panel.setupUi()

Log

  • 28/Agosto/2014: Comenzada esta página