In the last two chapters, we saw how to create Part geometry and create parametric objects. One last piece is missing to gain full control over FreeCAD: Create tools that will interact with the user.
In many situations, it is not very user-friendly to construct an object with zero values, like we did with the rectangle in the previous chapter, and then ask the user to fill in the Height and Width values in the Properties panel. This works for a very small number of objects but will become very tedious if you have a lot of rectangles to make. A better way would be to be able to already give the Height and Width when creating the rectangle.
Python offers a basic tool to have the user enter text on the screen:
text = raw_input("Height of the rectangle?") print("The entered height is ",text)
However, this requires a running Python console, and when running our code from a macro, we are not always sure that the Python console will be turned on on the user's machine.
The Graphical User Interface (GUI)—encompassing the menus, toolbars, 3D view, and other visual components of FreeCAD—is designed to make the software intuitive and accessible. It serves as a bridge between the user and FreeCAD's underlying functionality, allowing both casual users and experts to interact with the program effectively.
FreeCAD’s GUI is built using Qt, a powerful and open-source GUI toolkit that provides a wide range of features. Qt offers essential building blocks for interface design, such as dialog boxes, buttons, labels, text input fields, and pull-down menus, collectively known as "widgets." These widgets form the foundation of FreeCAD's user experience.
One of the key advantages of Qt is its cross-platform compatibility, enabling FreeCAD to run seamlessly on different operating systems like Windows, macOS, and Linux. Additionally, Qt’s flexibility makes it easy for developers to extend or customize FreeCAD’s interface, either by creating new toolbars and menus or by building entirely new modules that integrate into the software. This adaptability ensures that FreeCAD remains both user-friendly and highly extensible.
For users interested in scripting or developing new tools, FreeCAD's Python API also provides access to many Qt features. This means you can not only automate tasks but also create custom widgets or dialogs that integrate directly into the FreeCAD environment.
The Qt tools are very easy to use from Python, thanks to a Python module called PySide. PySide is the official Python binding for the Qt library, providing a seamless way to create and interact with widgets programmatically. It allows developers to design interfaces, manage user inputs (such as reading text from input boxes), and define actions based on user interactions, such as responding to a button press. Using PySide, you can build custom dialog boxes, menus, and toolbars directly within FreeCAD, extending its functionality in a way that integrates smoothly with its existing interface.
PySide makes it easy to connect user actions to specific functions in your code. For example, you can set up a button so that when it’s pressed, it triggers a script to execute a command or modify an object in the 3D view. This interactive capability opens up endless possibilities for customizing workflows and automating repetitive tasks.
Qt also provides another interesting tool called Qt Designer, which is today embedded inside a bigger application called Qt Creator. It makes it possible to design dialog boxes and interface panels graphically, instead of having to code them manually. In this chapter, we will use Qt Creator to design a panel widget that we will use in the Task panel of FreeCAD. So you will need to download and install Qt Creator from its official page if you are on Windows or Mac (on Linux it will usually be available from your software manager application).
In the following exercise, we will first create a panel with Qt Creator that asks for length, width and height values, then we will create a Python class around it, that will read the values entered by the user from the panel, and create a box with the given dimensions. This Python class will then be used by FreeCAD to display and control the task panel:
Let's start by creating the widget. Start Qt Creator, then menu File → New File or Project → Qt → Qt Designer Form → Dialog without buttons. Click Next, give it a filename to save, click Next, leave all project fields to their default value ("<none>"), and Create. FreeCAD's Task system will automatically add OK/Cancel buttons, that's why we chose here a dialog without buttons.
import FreeCAD,FreeCADGui,Part
# CHANGE THE LINE BELOW
path_to_ui = "C:\Users\yorik\Documents\dialog.ui"
class BoxTaskPanel:
def __init__(self):
# this will create a Qt widget from our ui file
self.form = FreeCADGui.PySideUic.loadUi(path_to_ui)
def accept(self):
length = self.form.BoxLength.value()
width = self.form.BoxWidth.value()
height = self.form.BoxHeight.value()
if (length == 0) or (width == 0) or (height == 0):
print("Error! None of the values can be 0!")
# we bail out without doing anything
return
box = Part.makeBox(length,width,height)
Part.show(box)
FreeCADGui.Control.closeDialog()
panel = BoxTaskPanel()
FreeCADGui.Control.showDialog(panel)
In the code above, we used a convenience function PySideUic.loadUi from the FreeCADGui module. That function loads a .ui file, creates a Qt Widget from it, and maps names, so we can easily access the subwidget by their names (ex: self.form.BoxLength).
The "accept" function is also a convenience offered by Qt. When there is an "OK" button in a dialog (which is the case by default when using the FreeCAD Tasks panel), any function named "accept" will automatically be executed when the "OK" button is pressed. Similarly, you can also add a "reject" function which gets executed when the "Cancel" button is pressed. In our case, we omitted that function, so pressing "Cancel" will do the default behaviour (do nothing and close the dialog).
If we implement any of the accept or reject functions, their default behaviour (do nothing and close) will not occur anymore. So we need to close the Task panel ourselves. This is done with:
FreeCADGui.Control.closeDialog()
Once we have our BoxTaskPanel that has 1- a widget called "self.form" and 2- if needed, accept and reject functions, we can open the task panel with it, which is done with these two last lines:
panel = BoxTaskPanel()
FreeCADGui.Control.showDialog(panel)
Note that the widget created by PySideUic.loadUi is not specific to FreeCAD, it is a standard Qt widget that can be used with other Qt tools. For example, we could have shown a separate dialog box with it. Try this in the Python Console of FreeCAD (using the correct path to your .ui file of course):
from PySide import QtGui
w = FreeCADGui.PySideUic.loadUi("C:\Users\yorik\Documents\dialog.ui")
w.show()
Of course, we didn't add any "OK" or "Cancel" buttons to our dialog, since it was made to be used from the FreeCAD Task panel, which already provides such buttons. So there is no way to close the dialog (other than pressing its Window Close button). But the function show() creates a non-modal dialog, which means it doesn't block the rest of the interface. So, while our dialog is still open, we can read the values of the fields:
w.BoxHeight.value()
This is very useful for testing.
Finally, don't forget there is much more documentation about using Qt widgets on the FreeCAD Wiki, in the Python Scripting section, which contains a dialog creation tutorial, a special 3-part PySide tutorial that covers the subject extensively.