Difference between revisions of "Dialog creation/cs"

From FreeCAD Documentation
Jump to navigation Jump to search
(Updating to match new version of source page)
(Updating to match new version of source page)
 
(12 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
<languages/>
 
<languages/>
{{docnav|[[Line drawing function|Line drawing function]]|[[Licence|Licence]]}}
 
  
In this page we will show how to build a simple Qt Dialog with [http://qt-project.org/doc/qt-4.8/designer-manual.html Qt Designer], Qt's official tool for designing interfaces, then convert it to python code, then use it inside FreeCAD. I'll assume in the example that you know how to edit and run python scripts already, and that you can do simple things in a terminal window such as navigate, etc. You must also have, of course, pyqt installed.
+
{{TOCright}}
 +
 
 +
== Introduction ==
 +
 
 +
In this page we will show how to build a simple graphical interface with [http://qt-project.org/doc/qt-4.8/designer-manual.html Qt Designer], Qt's official tool for designing interfaces; the dialog will be converted to [[Python|Python]] code, then it will be used inside FreeCAD. We'll assume that the user knows how to edit and run [[Python|Python]] generally.
 +
 
 +
In this example, the entire interface is defined in [[Python|Python]]. Although this is possible for small interfaces, for larger interfaces the recommendation is to load the created {{FileName|.ui}} files directly into the program. See [[Interface_creation_with_UI_files|Interface creation with UI files]] for more information.
 +
 
 +
[[File:FreeCAD_creating_interfaces.svg|600px]]
 +
{{Caption|Two general methods to create interfaces, by including the interface in the Python file, or by using {{incode|.ui}} files.}}
  
 
== Designing the dialog ==
 
== Designing the dialog ==
 +
 
In CAD applications, designing a good UI (User Interface) is very important. About everything the user will do will be through some piece of interface: reading dialog boxes, pressing buttons, choosing between icons, etc. So it is very important to think carefully to what you want to do, how you want the user to behave, and how will be the workflow of your action.
 
In CAD applications, designing a good UI (User Interface) is very important. About everything the user will do will be through some piece of interface: reading dialog boxes, pressing buttons, choosing between icons, etc. So it is very important to think carefully to what you want to do, how you want the user to behave, and how will be the workflow of your action.
  
Line 20: Line 29:
 
[[Image:Qtdesigner-screenshot.jpg]]
 
[[Image:Qtdesigner-screenshot.jpg]]
  
It is very simple to use. On the left bar you have elements that can be dragged on your widget. On the right side you have properties panels displaying all kinds of editable properties of selected elements. So, begin with creating a new widget. Select "Dialog without buttons", since we don't want the default Ok/Cancel buttons. Then, drag on your widget '''3 labels''', one for the title, one for writing "Height" and one for writing "Width". Labels are simple texts that appear on your widget, just to inform the user. If you select a label, on the right side will appear several properties that you can change if you want, such as font style, height, etc.
+
== Creating the dialog ==
 
+
Qt Designer is very simple to use. On the left bar you have elements that can be dragged on your widget. On the right side you have properties panels displaying all kinds of editable properties of selected elements. So, begin with creating a new widget.  
Then, add '''2 LineEdits''', which are text fields that the user can fill in, one for the height and one for the width. Here too, we can edit properties. For example, why not set a default value? For example 1.00 for each. This way, when the user will see the dialog, both values will be filled already and if he is satisfied he can directly press the button, saving precious time. Then, add a '''PushButton''', which is the button the user will need to press after he filled the 2 fields.
+
# Select "Dialog without buttons", since we don't want the default {{KEY|OK}}/{{KEY|Cancel}} buttons.  
 +
# We need '''Labels''. Labels are simple text strings that appear on your widget to inform the end user. If you select a label, notice that on the right side there will appear several properties that you can modify such as: font style, height, etc... So lets drag 3 separate labels on to our widget: 
 +
#* One label for the title
 +
#* Another label for writing "'''Height'''"
 +
#* Another label for writing "'''Width'''"
 +
# We now need LineEdits (2 of them actually). Drag two of them on to the widget. '''LineEdits''' are text fields that the end user can fill in. So we need one LineEdit for the ''Height'' and one for the ''Width''. Here too, we can edit properties. For example, why not set a default value say for example: 1.00 for each. This way, when the user will see the dialog, both values will be filled already. If the end user is satisfied, they can directly press the button, saving precious time.  
 +
# Next lets add a '''PushButton'''. This is the button the end user will need to press after they've filled both fields.
  
Note that I chose very simple controls here, but Qt has many more options, for example you could use Spinboxes instead of LineEdits, etc... Have a look at what is available, you will surely have other ideas.
+
'''Note:''' that we chose very simple controls here. Qt has many more options, for example one could use '''Spinboxes''' instead of '''LineEdits''', etc... Have a look at what is available, explore...you will surely have other ideas.
  
That's about all we need to do in Qt Designer. One last thing, though, let's rename all our elements with easier names, so it will be easier to identify them in our scripts:
+
That's about all we need to do in Qt Designer. One last thing, though, let's rename all our elements with simpler names, so it will be easier to identify them in our scripts:
  
 
[[Image:Qtpropeditor.jpg]]
 
[[Image:Qtpropeditor.jpg]]
Line 43: Line 58:
 
{{Code|code=
 
{{Code|code=
 
compQt4 myUiFile
 
compQt4 myUiFile
 +
}}
 +
 +
In macOS, you can retrieve the appropriate version (the same that is used internally in FreeCAD 0.19) of QT and Pyside with this commands (pip required)
 +
{{Code|code=
 +
python3 -m pip install pyqt5
 +
python3 -m pip install pySide2
 +
}}
 +
This will install uic in the folder "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/uic", and Designer in "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/Designer.app".
 +
For convenience you can create a link of uic in /usr/local/bin to be able to call it simply with uic -g python ... instead of typing the whole path of the program, and a link to Designer to retrieve it in the mac's Applications folder with
 +
{{Code|code=
 +
sudo ln -s /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/uic /usr/local/bin
 +
ln -s /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/Designer.app /Applications
 
}}
 
}}
  
Line 153: Line 180:
 
This is the complete script, for reference:
 
This is the complete script, for reference:
 
{{Code|code=
 
{{Code|code=
# -*- coding: utf-8 -*-
 
 
 
# Form implementation generated from reading ui file 'mywidget.ui'
 
# Form implementation generated from reading ui file 'mywidget.ui'
 
#
 
#
Line 193: Line 218:
  
 
   def retranslateUi(self, Dialog):
 
   def retranslateUi(self, Dialog):
       Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
+
       Dialog.setWindowTitle("Dialog")
       self.title.setText(QtGui.QApplication.translate("Dialog", "Plane-O-Matic", None, QtGui.QApplication.UnicodeUTF8))
+
       self.title.setText("Plane-O-Matic")
       self.label_width.setText(QtGui.QApplication.translate("Dialog", "Width", None, QtGui.QApplication.UnicodeUTF8))
+
       self.label_width.setText("Width")
       self.label_height.setText(QtGui.QApplication.translate("Dialog", "Height", None, QtGui.QApplication.UnicodeUTF8))
+
       self.label_height.setText("Height")
       self.create.setText(QtGui.QApplication.translate("Dialog", "Create!", None, QtGui.QApplication.UnicodeUTF8))
+
       self.create.setText("Create!")
 
+
      print("tyty")
 
   def createPlane(self):
 
   def createPlane(self):
 
       try:
 
       try:
Line 218: Line 243:
  
 
class plane():
 
class plane():
  def __init__(self):
+
  def __init__(self):
      self.d = QtGui.QWidget()
+
      self.d = QtGui.QWidget()
      self.ui = Ui_Dialog()
+
      self.ui = Ui_Dialog()
      self.ui.setupUi(self.d)
+
      self.ui.setupUi(self.d)
      self.d.show()
+
      self.d.show()
}}
 
==Creation of a dialog with buttons==
 
 
 
===Method 1===
 
An example of a dialog box complete with its connections.
 
{{Code|code=
 
# -*- coding: utf-8 -*-
 
# Create by flachyjoe
 
 
 
from PySide import QtCore, QtGui
 
 
 
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_MainWindow(object):
 
 
 
    def __init__(self, MainWindow):
 
        self.window = MainWindow
 
 
 
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
 
        MainWindow.resize(400, 300)
 
        self.centralWidget = QtGui.QWidget(MainWindow)
 
        self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
 
 
 
        self.pushButton = QtGui.QPushButton(self.centralWidget)
 
        self.pushButton.setGeometry(QtCore.QRect(30, 170, 93, 28))
 
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
 
        self.pushButton.clicked.connect(self.on_pushButton_clicked) #connection pushButton
 
 
 
        self.lineEdit = QtGui.QLineEdit(self.centralWidget)
 
        self.lineEdit.setGeometry(QtCore.QRect(30, 40, 211, 22))
 
        self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
 
        self.lineEdit.returnPressed.connect(self.on_lineEdit_clicked) #connection lineEdit
 
 
 
        self.checkBox = QtGui.QCheckBox(self.centralWidget)
 
        self.checkBox.setGeometry(QtCore.QRect(30, 90, 81, 20))
 
        self.checkBox.setChecked(True)
 
        self.checkBox.setObjectName(_fromUtf8("checkBoxON"))
 
        self.checkBox.clicked.connect(self.on_checkBox_clicked) #connection checkBox
 
 
 
        self.radioButton = QtGui.QRadioButton(self.centralWidget)
 
        self.radioButton.setGeometry(QtCore.QRect(30, 130, 95, 20))
 
        self.radioButton.setObjectName(_fromUtf8("radioButton"))
 
        self.radioButton.clicked.connect(self.on_radioButton_clicked) #connection radioButton
 
 
 
        MainWindow.setCentralWidget(self.centralWidget)
 
 
 
        self.menuBar = QtGui.QMenuBar(MainWindow)
 
        self.menuBar.setGeometry(QtCore.QRect(0, 0, 400, 26))
 
        self.menuBar.setObjectName(_fromUtf8("menuBar"))
 
        MainWindow.setMenuBar(self.menuBar)
 
 
 
        self.mainToolBar = QtGui.QToolBar(MainWindow)
 
        self.mainToolBar.setObjectName(_fromUtf8("mainToolBar"))
 
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
 
 
 
        self.statusBar = QtGui.QStatusBar(MainWindow)
 
        self.statusBar.setObjectName(_fromUtf8("statusBar"))
 
        MainWindow.setStatusBar(self.statusBar)
 
 
 
        self.retranslateUi(MainWindow)
 
 
 
    def retranslateUi(self, MainWindow):
 
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
 
        self.pushButton.setText(_translate("MainWindow", "OK", None))
 
        self.lineEdit.setText(_translate("MainWindow", "tyty", None))
 
        self.checkBox.setText(_translate("MainWindow", "CheckBox", None))
 
        self.radioButton.setText(_translate("MainWindow", "RadioButton", None))
 
 
 
    def on_checkBox_clicked(self):
 
        if self.checkBox.checkState()==0:
 
            App.Console.PrintMessage(str(self.checkBox.checkState())+"  CheckBox KO\r\n")
 
        else:   
 
            App.Console.PrintMessage(str(self.checkBox.checkState())+" CheckBox OK\r\n")
 
#        App.Console.PrintMessage(str(self.lineEdit.setText("tititi"))+" LineEdit\r\n") #write text to the lineEdit window !
 
#        str(self.lineEdit.setText("tititi")) #écrit le texte dans la fenêtre lineEdit
 
        App.Console.PrintMessage(str(self.lineEdit.displayText())+" LineEdit\r\n")
 
 
 
    def on_radioButton_clicked(self):
 
        if self.radioButton.isChecked():
 
            App.Console.PrintMessage(str(self.radioButton.isChecked())+" Radio OK\r\n")
 
        else:
 
            App.Console.PrintMessage(str(self.radioButton.isChecked())+"  Radio KO\r\n")
 
 
 
    def on_lineEdit_clicked(self):
 
#        if self.lineEdit.textChanged():
 
            App.Console.PrintMessage(str(self.lineEdit.displayText())+" LineEdit Display\r\n")
 
 
 
    def on_pushButton_clicked(self):
 
        App.Console.PrintMessage("Terminé\r\n")
 
        self.window.hide()
 
 
 
MainWindow = QtGui.QMainWindow()
 
ui = Ui_MainWindow(MainWindow)
 
MainWindow.show()
 
}}
 
Here the same window but with an icon on each button.
 
 
 
Download associated icons (click right "Copy the image below ...)"
 
 
 
[[File:Icone01.png]]  [[File:Icone02.png]]  [[File:Icone03.png]]
 
 
 
{{Code|code=
 
# -*- coding: utf-8 -*-
 
 
 
from PySide import QtCore, QtGui
 
 
 
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_MainWindow(object):
 
 
 
    def __init__(self, MainWindow):
 
        self.window = MainWindow
 
        path = FreeCAD.ConfigGet("UserAppData")
 
#        path = FreeCAD.ConfigGet("AppHomePath")
 
 
 
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
 
        MainWindow.resize(400, 300)
 
        self.centralWidget = QtGui.QWidget(MainWindow)
 
        self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
 
 
 
        self.pushButton = QtGui.QPushButton(self.centralWidget)
 
        self.pushButton.setGeometry(QtCore.QRect(30, 170, 93, 28))
 
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
 
        self.pushButton.clicked.connect(self.on_pushButton_clicked) #connection pushButton
 
 
 
        self.lineEdit = QtGui.QLineEdit(self.centralWidget)
 
        self.lineEdit.setGeometry(QtCore.QRect(30, 40, 211, 22))
 
        self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
 
        self.lineEdit.returnPressed.connect(self.on_lineEdit_clicked) #connection lineEdit
 
 
 
        self.checkBox = QtGui.QCheckBox(self.centralWidget)
 
        self.checkBox.setGeometry(QtCore.QRect(30, 90, 100, 20))
 
        self.checkBox.setChecked(True)
 
        self.checkBox.setObjectName(_fromUtf8("checkBoxON"))
 
        self.checkBox.clicked.connect(self.on_checkBox_clicked) #connection checkBox
 
 
 
        self.radioButton = QtGui.QRadioButton(self.centralWidget)
 
        self.radioButton.setGeometry(QtCore.QRect(30, 130, 95, 20))
 
        self.radioButton.setObjectName(_fromUtf8("radioButton"))
 
        self.radioButton.clicked.connect(self.on_radioButton_clicked) #connection radioButton
 
 
 
        MainWindow.setCentralWidget(self.centralWidget)
 
 
 
        self.menuBar = QtGui.QMenuBar(MainWindow)
 
        self.menuBar.setGeometry(QtCore.QRect(0, 0, 400, 26))
 
        self.menuBar.setObjectName(_fromUtf8("menuBar"))
 
        MainWindow.setMenuBar(self.menuBar)
 
 
 
        self.mainToolBar = QtGui.QToolBar(MainWindow)
 
        self.mainToolBar.setObjectName(_fromUtf8("mainToolBar"))
 
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
 
 
 
        self.statusBar = QtGui.QStatusBar(MainWindow)
 
        self.statusBar.setObjectName(_fromUtf8("statusBar"))
 
        MainWindow.setStatusBar(self.statusBar)
 
 
 
        self.retranslateUi(MainWindow)
 
 
 
        # Affiche un icone sur le bouton PushButton
 
        # self.image_01 = "C:\Program Files\FreeCAD0.13\Icone01.png" # adapt the icon name
 
        self.image_01 = path+"Icone01.png" # adapt the name of the icon
 
        icon01 = QtGui.QIcon()
 
        icon01.addPixmap(QtGui.QPixmap(self.image_01),QtGui.QIcon.Normal, QtGui.QIcon.Off)
 
        self.pushButton.setIcon(icon01)
 
        self.pushButton.setLayoutDirection(QtCore.Qt.RightToLeft) # This command reverses the direction of the button
 
 
 
        # Affiche un icone sur le bouton RadioButton
 
        # self.image_02 = "C:\Program Files\FreeCAD0.13\Icone02.png" # adapt the name of the icon
 
        self.image_02 = path+"Icone02.png" # adapter le nom de l'icone
 
        icon02 = QtGui.QIcon()
 
        icon02.addPixmap(QtGui.QPixmap(self.image_02),QtGui.QIcon.Normal, QtGui.QIcon.Off)
 
        self.radioButton.setIcon(icon02)
 
        # self.radioButton.setLayoutDirection(QtCore.Qt.RightToLeft) #  This command reverses the direction of the button
 
 
 
        # Affiche un icone sur le bouton CheckBox
 
        # self.image_03 = "C:\Program Files\FreeCAD0.13\Icone03.png" # the name of the icon
 
        self.image_03 = path+"Icone03.png" # adapter le nom de l'icone
 
        icon03 = QtGui.QIcon()
 
        icon03.addPixmap(QtGui.QPixmap(self.image_03),QtGui.QIcon.Normal, QtGui.QIcon.Off)
 
        self.checkBox.setIcon(icon03)
 
        # self.checkBox.setLayoutDirection(QtCore.Qt.RightToLeft) # This command reverses the direction of the button
 
 
 
 
 
    def retranslateUi(self, MainWindow):
 
        MainWindow.setWindowTitle(_translate("MainWindow", "FreeCAD", None))
 
        self.pushButton.setText(_translate("MainWindow", "OK", None))
 
        self.lineEdit.setText(_translate("MainWindow", "tyty", None))
 
        self.checkBox.setText(_translate("MainWindow", "CheckBox", None))
 
        self.radioButton.setText(_translate("MainWindow", "RadioButton", None))
 
 
 
    def on_checkBox_clicked(self):
 
        if self.checkBox.checkState()==0:
 
            App.Console.PrintMessage(str(self.checkBox.checkState())+"  CheckBox KO\r\n")
 
        else:   
 
            App.Console.PrintMessage(str(self.checkBox.checkState())+" CheckBox OK\r\n")
 
          # App.Console.PrintMessage(str(self.lineEdit.setText("tititi"))+" LineEdit\r\n") # write text to the lineEdit window !
 
          # str(self.lineEdit.setText("tititi")) #écrit le texte dans la fenêtre lineEdit
 
        App.Console.PrintMessage(str(self.lineEdit.displayText())+" LineEdit\r\n")
 
 
 
    def on_radioButton_clicked(self):
 
        if self.radioButton.isChecked():
 
            App.Console.PrintMessage(str(self.radioButton.isChecked())+" Radio OK\r\n")
 
        else:
 
            App.Console.PrintMessage(str(self.radioButton.isChecked())+"  Radio KO\r\n")
 
 
 
    def on_lineEdit_clicked(self):
 
          # if self.lineEdit.textChanged():
 
          App.Console.PrintMessage(str(self.lineEdit.displayText())+" LineEdit Display\r\n")
 
 
 
    def on_pushButton_clicked(self):
 
        App.Console.PrintMessage("Terminé\r\n")
 
        self.window.hide()
 
 
 
MainWindow = QtGui.QMainWindow()
 
ui = Ui_MainWindow(MainWindow)
 
MainWindow.show()
 
}}
 
Here the code to display the icon on the '''pushButton''', change the name for another button, ('''radioButton, checkBox''') and the path to the icon.
 
{{Code|code=
 
        # Affiche un icône sur le bouton PushButton
 
        # self.image_01 = "C:\Program Files\FreeCAD0.13\icone01.png" # the name of the icon
 
        self.image_01 = path+"icone01.png" # the name of the icon
 
        icon01 = QtGui.QIcon()
 
        icon01.addPixmap(QtGui.QPixmap(self.image_01),QtGui.QIcon.Normal, QtGui.QIcon.Off)
 
        self.pushButton.setIcon(icon01)
 
        self.pushButton.setLayoutDirection(QtCore.Qt.RightToLeft) # This command reverses the direction of the button
 
}}
 
The command
 
'''UserAppData''' gives the user path
 
'''AppHomePath''' gives the installation path of FreeCAD
 
{{Code|code=
 
#        path = FreeCAD.ConfigGet("UserAppData")
 
        path = FreeCAD.ConfigGet("AppHomePath")
 
}}
 
This command reverses the horizontal button, right to left.
 
{{Code|code=
 
self.pushButton.setLayoutDirection(QtCore.Qt.RightToLeft) # This command reverses the direction of the button
 
}}
 
 
 
===Method 2===
 
Another method to display a window, here by creating a file '''QtForm.py''' which contains the header program (module called with '''import QtForm'''), and a second module that contains the code window all these accessories, and your code (the calling module).
 
 
 
This method requires two separate files, but allows to shorten your program using the file ' ' QtForm.py ' ' import. Then distribute the two files together, they are inseparable.
 
 
 
The file '''QtForm.py'''
 
{{Code|code=
 
 
 
# -*- coding: utf-8 -*-
 
# Create by flachyjoe
 
from PySide import QtCore, QtGui
 
 
 
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 Form(object):
 
  def __init__(self, title, width, height):
 
      self.window = QtGui.QMainWindow()
 
      self.title=title
 
      self.window.setObjectName(_fromUtf8(title))
 
      self.window.setWindowTitle(_translate(self.title, self.title, None))
 
      self.window.resize(width, height)
 
 
 
  def show(self):
 
      self.createUI()
 
      self.retranslateUI()
 
      self.window.show()
 
 
 
  def setText(self, control, text):
 
      control.setText(_translate(self.title, text, None))
 
}}
 
The calling file that contains the window and your code.
 
 
 
The file my_file.py
 
 
 
The connections are to do, a good exercise.
 
{{Code|code=
 
 
 
# -*- coding: utf-8 -*-
 
# Create by flachyjoe
 
from PySide import QtCore, QtGui
 
import QtForm
 
 
 
class myForm(QtForm.Form):
 
  def createUI(self):
 
      self.centralWidget = QtGui.QWidget(self.window)
 
      self.window.setCentralWidget(self.centralWidget)
 
     
 
      self.pushButton = QtGui.QPushButton(self.centralWidget)
 
      self.pushButton.setGeometry(QtCore.QRect(30, 170, 93, 28))
 
      self.pushButton.clicked.connect(self.on_pushButton_clicked)
 
     
 
      self.lineEdit = QtGui.QLineEdit(self.centralWidget)
 
      self.lineEdit.setGeometry(QtCore.QRect(30, 40, 211, 22))
 
     
 
      self.checkBox = QtGui.QCheckBox(self.centralWidget)
 
      self.checkBox.setGeometry(QtCore.QRect(30, 90, 81, 20))
 
      self.checkBox.setChecked(True)
 
     
 
      self.radioButton = QtGui.QRadioButton(self.centralWidget)
 
      self.radioButton.setGeometry(QtCore.QRect(30, 130, 95, 20))
 
 
 
  def retranslateUI(self):
 
      self.setText(self.pushButton, "Fermer")
 
      self.setText(self.lineEdit, "essais de texte")
 
      self.setText(self.checkBox, "CheckBox")
 
      self.setText(self.radioButton, "RadioButton")
 
 
 
  def on_pushButton_clicked(self):
 
      self.window.hide()
 
 
 
myWindow=myForm("Fenetre de test",400,300)
 
myWindow.show()
 
}}
 
 
 
'''Other example'''
 
<center>
 
<gallery widths="400" heights="200">
 
Image:Qt_Example_00.png|Qt example 1
 
Image:Qt_Example_01.png|Qt example details
 
</gallery>
 
</center>
 
{{clear}}
 
 
 
Are treated :
 
 
 
# icon for window
 
# horizontalSlider
 
# progressBar horizontal
 
# verticalSlider
 
# progressBar vertical
 
# lineEdit
 
# lineEdit
 
# doubleSpinBox
 
# doubleSpinBox
 
# doubleSpinBox
 
# button
 
# button
 
# radioButton with icons
 
# checkBox with icon checked and unchecked
 
# textEdit
 
# graphicsView with 2 graphes
 
The code page and the icons [[Qt_Example|Qt_Example]]
 
 
 
==Icon personalised in ComboView==
 
 
 
Here an example to create an object with properties and icon personalised in ComboView
 
 
 
Download the example icon to the same directory as the macro [[File:FreeCADIco.png|icon Example for the macro|24px]]
 
 
 
Use of an icon for three different use cases: icon_in_file_disk (format .png), icon_XPM_in_macro (format .XPM) and icon_resource_FreeCAD
 
 
 
[[File:Qt_Example_02.png|icon personalised]]
 
{{clear}}
 
 
 
{{Code|code=
 
import PySide
 
import FreeCAD, FreeCADGui, Part
 
from pivy import coin
 
from PySide import QtGui ,QtCore
 
from PySide.QtGui import *
 
from PySide.QtCore import *
 
import Draft
 
 
 
global path
 
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macro")# macro path in FreeCAD preferences
 
path = param.GetString("MacroPath","") + "/"                        # macro path
 
path = path.replace("\\","/")                                      # convert the "\" to "/"
 
 
 
 
 
class IconViewProviderToFile:                                      # Class ViewProvider create Property view of object
 
    def __init__( self, obj, icon):
 
        self.icone = icon
 
       
 
    def getIcon(self):                                              # GetIcon
 
        return self.icone
 
       
 
    def attach(self, obj):                                          # Property view of object
 
        self.modes = []
 
        self.modes.append("Flat Lines")
 
        self.modes.append("Shaded")
 
        self.modes.append("Wireframe")
 
        self.modes.append("Points")
 
        obj.addDisplayMode( coin.SoGroup(),"Flat Lines" )          # Display Mode
 
        obj.addDisplayMode( coin.SoGroup(),"Shaded" )
 
        obj.addDisplayMode( coin.SoGroup(),"Wireframe" )
 
        obj.addDisplayMode( coin.SoGroup(),"Points" )
 
        return self.modes
 
 
 
    def getDisplayModes(self,obj):
 
        return self.modes
 
 
 
#####################################################
 
########## Example with icon to file # begin ########
 
#####################################################
 
 
 
object1 = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "Icon_In_File_Disk")                                    # create your object
 
object1.addProperty("App::PropertyString","Identity", "ExampleTitle0", "Identity of object").Identity = "FCSpring"        # Identity of object
 
object1.addProperty("App::PropertyFloat" ,"Pitch",    "ExampleTitle0", "Pitch betwen 2 heads").Pitch  = 2.0              # other Property Data
 
object1.addProperty("App::PropertyBool"  ,"View",    "ExampleTitle1", "Hello world").View            = True              # ...
 
object1.addProperty("App::PropertyColor" ,"LineColor","ExampleTitle2", "Color to choice").LineColor  = (0.13,0.15,0.37)  # ...
 
#...other Property Data
 
#...other Property Data
 
#
 
object1.ViewObject.Proxy = IconViewProviderToFile( object1, path + "FreeCADIco.png")                                      # icon download to file
 
App.ActiveDocument.recompute()
 
#
 
#__Detail__:
 
# FreeCAD.ActiveDocument.addObject( = create now object personalized
 
# "App::FeaturePython",            = object as FeaturePython
 
# "Icon_In_File_Disk")              = internal name of your object
 
#
 
#
 
# "App::PropertyString",    = type of Property , availlable : PropertyString, PropertyFloat, PropertyBool, PropertyColor
 
# "Identity",              = name of the feature
 
# "ExampleTitle0",          = title of the "section"
 
# "Identity of object")    = tooltip displayed on mouse
 
# .Identity                = variable (same of name of the feature)
 
# object1.ViewObject.Proxy  = create the view object and gives the icon
 
#
 
########## example with icon to file end
 
 
 
 
 
 
 
#####################################################
 
########## Example with icon in macro # begin #######
 
#####################################################
 
 
 
def setIconInMacro(self):        # def contener the icon in format .xpm
 
    # File format XPM created by Gimp "https://www.gimp.org/"
 
    # Choice palette Tango
 
    # Create your masterwork ...
 
    # For export the image in XPM format
 
    #    Menu File > Export as > .xpm
 
    # (For convert image true color in Tango color palette :
 
    #    Menu Image > Mode > Indexed ... > Use custom palette > Tango Icon Theme > Convert)
 
    return """
 
            /* XPM */
 
            static char * XPM[] = {
 
            "22 24 5 1",
 
            " c None",
 
            ". c #CE5C00",
 
            "+ c #EDD400",
 
            "@ c #F57900",
 
            "# c #8F5902",
 
            "                      ",
 
            "                      ",
 
            "  ....                ",
 
            "  ..@@@@..            ",
 
            "  . ...@......        ",
 
            "  .+++++++++...      ",
 
            "  .      ....++...    ",
 
            "  .@..@@@@@@.+++++..  ",
 
            "  .@@@@@..#  ++++ ..  ",
 
            "  .      ++++  .@..  ",
 
            "  .++++++++  .@@@.+.  ",
 
            " .      ..@@@@@. ++.  ",
 
            " ..@@@@@@@@@.  +++ .  ",
 
            " ....@...# +++++ @..  ",
 
            " .    ++++++++ .@. .  ",
 
            " .++++++++  .@@@@ .  ",
 
            " .  #....@@@@. ++.  ",
 
            " .@@@@@@@@@.. +++ .  ",
 
            " ........  +++++...  ",
 
            " ...  ..+++++ ..@..  ",
 
            "    ......  .@@@ +.  ",
 
            "          ......++.  ",
 
            "                ...  ",
 
            "                      "};
 
        """
 
 
 
object2 = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "Icon_XPM_In_Macro")                                    #
 
object2.addProperty("App::PropertyString","Identity","ExampleTitle","Identity of object").Identity = "FCSpring"
 
#...other Property Data
 
#...other Property Data
 
#
 
object2.ViewObject.Proxy = IconViewProviderToFile( object2, setIconInMacro(""))              # icon in macro (.XPM)
 
App.ActiveDocument.recompute()
 
########## example with icon in macro end
 
 
 
 
 
 
 
####################################################################
 
########## Example with icon to FreeCAD ressource # begin ##########
 
####################################################################
 
 
 
object3 = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "Icon_Ressource_FreeCAD")                              #
 
object3.addProperty("App::PropertyString","Identity","ExampleTitle","Identity of object").Identity = "FCSpring"
 
#...other Property Data
 
#...other Property Data
 
#
 
object3.ViewObject.Proxy = IconViewProviderToFile( object3, ":/icons/Draft_Draft.svg")      # icon to FreeCAD ressource
 
App.ActiveDocument.recompute()
 
########## example with icon to FreeCAD ressource end
 
 
 
}}
 
 
 
Complete example creating a cube and its icon
 
 
 
{{Code|code=
 
#https://forum.freecadweb.org/viewtopic.php?t=10255#p83319
 
import FreeCAD, Part, math
 
from FreeCAD import Base
 
from PySide import QtGui
 
 
 
global path
 
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macro")# macro path in FreeCAD preferences
 
path = param.GetString("MacroPath","") + "/"                        # macro path
 
path = path.replace("\\","/")                                      # convert the "\" to "/"
 
 
 
def setIconInMacro(self):
 
    return """
 
        /* XPM */
 
        static char * xpm[] = {
 
        "22 22 12 1",
 
        " c None",
 
        ". c #A40000",
 
        "+ c #2E3436",
 
        "@ c #CE5C00",
 
        "# c #F57900",
 
        "$ c #FCAF3E",
 
        "% c #5C3566",
 
        "& c #204A87",
 
        "* c #555753",
 
        "= c #3465A4",
 
        "- c #4E9A06",
 
        "; c #729FCF",
 
        "                      ",
 
        "                      ",
 
        "                      ",
 
        "        ..  ..      ",
 
        "      +@#+++.$$      ",
 
        "      +.#+%..$$      ",
 
        "      &*$  &*#*      ",
 
        "      &  =&=  =      ",
 
        "  ++&  +.==  %=    ",
 
        "  ++$@ ..$ %=  &    ",
 
        "  ..-&%.#$$ &## +=$  ",
 
        "  .#  ..$ ..#%%.#$$  ",
 
        "    ;    =+=## %-$#  ",
 
        "    &=  ;&  %=    ",
 
        "      ;+ &=;  %=      ",
 
        "      ++$- +*$-      ",
 
        "      .#&&+.@$$      ",
 
        "      ..$# ..$#      ",
 
        "      ..  ..        ",
 
        "                      ",
 
        "                      ",
 
        "                      "};
 
        """
 
 
 
class PartFeature:
 
    def __init__(self, obj):
 
        obj.Proxy = self
 
 
 
class Box(PartFeature):
 
    def __init__(self, obj):
 
        PartFeature.__init__(self, obj)
 
        obj.addProperty("App::PropertyLength", "Length", "Box", "Length of the box").Length = 1.0
 
        obj.addProperty("App::PropertyLength", "Width",  "Box", "Width of the box" ).Width  = 1.0
 
        obj.addProperty("App::PropertyLength", "Height", "Box", "Height of the box").Height = 1.0
 
 
 
    def onChanged(self, fp, prop):
 
        try:
 
            if prop == "Length" or prop == "Width" or prop == "Height":
 
                fp.Shape = Part.makeBox(fp.Length,fp.Width,fp.Height)
 
        except:
 
            pass
 
 
 
    def execute(self, fp):
 
        fp.Shape = Part.makeBox(fp.Length,fp.Width,fp.Height)
 
 
 
class ViewProviderBox:
 
    def __init__(self, obj, icon):
 
        obj.Proxy  = self
 
        self.icone = icon
 
       
 
    def getIcon(self):
 
        return self.icone
 
 
 
    def attach(self, obj):
 
        return
 
 
 
    def setupContextMenu(self, obj, menu):
 
        action = menu.addAction("Set default height")
 
        action.triggered.connect(lambda f=self.setDefaultHeight, arg=obj:f(arg))
 
 
 
        action = menu.addAction("Hello World")
 
        action.triggered.connect(self.showHelloWorld)
 
 
 
    def setDefaultHeight(self, view):
 
        view.Object.Height = 15.0
 
 
 
    def showHelloWorld(self):
 
        QtGui.QMessageBox.information(None, "Hi there", "Hello World")
 
 
 
def makeBox():
 
    FreeCAD.newDocument()
 
    a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Box")
 
    Box(a)
 
#    ViewProviderBox(a.ViewObject, path + "FreeCADIco.png")    # icon download to file
 
#    ViewProviderBox(a.ViewObject,  ":/icons/Draft_Draft.svg") # icon to FreeCAD ressource
 
    ViewProviderBox(a.ViewObject,  setIconInMacro(""))        # icon in macro (.XPM)
 
    App.ActiveDocument.recompute()
 
 
 
makeBox()
 
 
 
  
 
}}
 
}}
  
==Use QFileDialog for writing to a file==
+
==More examples ==
Complete code:
 
{{Code|code=
 
# -*- coding: utf-8 -*-
 
import PySide
 
from PySide import QtGui ,QtCore
 
from PySide.QtGui import *
 
from PySide.QtCore import *
 
path = FreeCAD.ConfigGet("UserAppData")
 
  
try:
+
* [[Dialog_creation_with_various_widgets|Dialog creation with various widgets]] with {{incode|QPushButton}}, {{incode|QLineEdit}}, {{incode|QCheckBox}}, {{incode|QRadioButton}}, and others.
    SaveName = QFileDialog.getSaveFileName(None,QString.fromLocal8Bit("Save a file txt"),path,            "*.txt") # PyQt4
+
* [[Dialog_creation_reading_and_writing_files|Dialog creation reading and writing files]] with {{incode|QFileDialog}}.
#                                                                    "here the text displayed on windows" "here the filter (extension)" 
+
* [[Dialog_creation_setting_colors|Dialog creation setting colors]] with {{incode|QColorDialog}}.
except Exception:
+
* [[Dialog_creation_image_and_animated_GIF|Dialog creation image and animated GIF]] with {{incode|QLabel}} and {{incode|QMovie}}.
    SaveName, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Save a file txt", path,             "*.txt") # PySide
+
* [[PySide_usage_snippets|PySide usage snippets]].
#                                                                    "here the text displayed on windows" "here the filter (extension)" 
+
* [[Qt_Example|Qt Example]]
if SaveName == "":                                                            # if the name file are not selected then Abord process
 
    App.Console.PrintMessage("Process aborted"+"\n")
 
else:                                                                        # if the name file are selected or created then
 
    App.Console.PrintMessage("Registration of "+SaveName+"\n")                # text displayed to Report view (Menu > View > Report view checked)
 
    try:                                                                      # detect error ...
 
        file = open(SaveName, 'w')                                            # open the file selected to write (w)
 
        try:                                                                  # if error detected to write ...
 
            # here your code
 
            print("here your code")
 
            file.write(str(1)+"\n")                                          # write the number convert in text with (str())
 
            file.write("FreeCAD the best")                                    # write the the text with ("  ")
 
        except Exception:                                                    # if error detected to write
 
            App.Console.PrintError("Error write file "+"\n")                  # detect error ... display the text in red (PrintError)
 
        finally:                                                              # if error detected to write ... or not the file is closed
 
            file.close()                                                      # if error detected to write ... or not the file is closed
 
    except Exception:
 
        App.Console.PrintError("Error Open file "+SaveName+"\n")      # detect error ... display the text in red (PrintError)
 
  
}}
+
== Relevant links ==
  
==Use QFileDialog to read a file==
 
Complete code:
 
{{Code|code=
 
# -*- coding: utf-8 -*-
 
import PySide
 
from PySide import QtGui ,QtCore
 
from PySide.QtGui import *
 
from PySide.QtCore import *
 
path = FreeCAD.ConfigGet("UserAppData")
 
 
OpenName = ""
 
try:
 
    OpenName = QFileDialog.getOpenFileName(None,QString.fromLocal8Bit("Read a file txt"),path,            "*.txt") # PyQt4
 
#                                                                    "here the text displayed on windows" "here the filter (extension)" 
 
except Exception:
 
    OpenName, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Read a file txt", path,            "*.txt") #PySide
 
#                                                                    "here the text displayed on windows" "here the filter (extension)" 
 
if OpenName == "":                                                            # if the name file are not selected then Abord process
 
    App.Console.PrintMessage("Process aborted"+"\n")
 
else:
 
    App.Console.PrintMessage("Read "+OpenName+"\n")                          # text displayed to Report view (Menu > View > Report view checked)
 
    try:                                                                      # detect error to read file
 
        file = open(OpenName, "r")                                            # open the file selected to read (r)  # (rb is binary)
 
        try:                                                                  # detect error ...
 
            # here your code
 
            print("here your code")
 
            op = OpenName.split("/")                                          # decode the path
 
            op2 = op[-1].split(".")                                          # decode the file name
 
            nomF = op2[0]                                                    # the file name are isolated
 
 
            App.Console.PrintMessage(str(nomF)+"\n")                          # the file name are displayed
 
 
            for ligne in file:                                                # read the file
 
                X  = ligne.rstrip('\n\r') #.split()                          # decode the line
 
                print(X)                                                      # print the line in report view other method
 
                                                                              # (Menu > Edit > preferences... > Output window > Redirect internal Python output (and errors) to report view checked)
 
        except Exception:                                                    # if error detected to read
 
            App.Console.PrintError("Error read file "+"\n")                  # detect error ... display the text in red (PrintError)
 
        finally:                                                              # if error detected to read ... or not error the file is closed
 
            file.close()                                                      # if error detected to read ... or not error the file is closed
 
    except Exception:                                                        # if one error detected to read file
 
        App.Console.PrintError("Error in Open the file "+OpenName+"\n")      # if one error detected ... display the text in red (PrintError)
 
 
}}
 
 
==Use QColorDialog to get the color==
 
Complete code:
 
{{Code|code=
 
# -*- coding: utf-8 -*-
 
# https://deptinfo-ensip.univ-poitiers.fr/ENS/pyside-docs/PySide/QtGui/QColor.html
 
import PySide
 
from PySide import QtGui ,QtCore
 
from PySide.QtGui import *
 
from PySide.QtCore import *
 
path = FreeCAD.ConfigGet("UserAppData")
 
 
couleur = QtGui.QColorDialog.getColor()
 
if couleur.isValid():
 
    red  = int(str(couleur.name()[1:3]),16)    # decode hexadecimal to int()
 
    green = int(str(couleur.name()[3:5]),16)    # decode hexadecimal to int()
 
    blue  = int(str(couleur.name()[5:7]),16)    # decode hexadecimal to int()
 
 
    print(couleur)                              #
 
    print("hexadecimal ",couleur.name())        # color format hexadecimal mode 16
 
    print("Red  color ",red)                  # color format decimal
 
    print("Green color ",green)                # color format decimal
 
    print("Blue  color ",blue)                  # color format decimal
 
 
}}
 
==Use QColorDialog and create your palette colors (Standard and Customize)==
 
 
This example modify the Standard color and the Customize color with the Tango FreeCAD guide.
 
 
The complete code
 
 
 
{{Code|code=
 
# -*- coding: utf-8 -*-
 
# https://deptinfo-ensip.univ-poitiers.fr/ENS/pyside-docs/PySide/QtGui/QColor.html
 
import PySide
 
from PySide import QtGui ,QtCore
 
from PySide.QtGui import *
 
from PySide.QtCore import *
 
 
###############################################
 
##        Window colors organisation        ##
 
##        __________________________        ##
 
## StandardColor:                            ##
 
##                                          ##
 
##          Colonnes:                      ##
 
##          1:  2:  3:  4:  5:  6:  7:  8:  ##
 
##          _______________________________  ##
 
## Line 1:  0  6  12  18  24  30  36  42  ##
 
## Line 2:  1  7  13  19  25  31  37  43  ##
 
## Line 3:  2  8  14  20  26  32  38  44  ##
 
## Line 4:  3  9  15  21  27  33  39  45  ##
 
## Line 5:  4  10  16  22  28  34  40  46  ##
 
## Line 6:  5  11  17  23  29  35  41  47  ##
 
##                                          ##
 
## CustomColor:                              ##
 
##                                          ##
 
##          Colonnes:                      ##
 
##          1:  2:  3:  4:  5:  6:  7:  8:  ##
 
##          _______________________________  ##
 
## Line 1:  0  2  4  6  8  10  12  14  ##
 
## Line 2:  1  3  5  7  9  11  13  15  ##
 
##                                          ##
 
###############################################
 
 
color_Dialog  = QtGui.QColorDialog()
 
# FreeCAD-Tango
 
# Customize the colors in the standard box (in numeric mode)
 
#
 
#### Dialog line 1
 
color_Dialog.setStandardColor( 0, QtGui.QColor(252, 233,  79 , 0).rgba())    # Butte 1
 
color_Dialog.setStandardColor( 6, QtGui.QColor(237, 212,  0 , 0).rgba())    # Butte 2
 
color_Dialog.setStandardColor(12, QtGui.QColor(196, 160,  0 , 0).rgba())    # Butte 3
 
color_Dialog.setStandardColor(18, QtGui.QColor( 48,  43,  0 , 0).rgba())    # Butte 4
 
 
color_Dialog.setStandardColor(24, QtGui.QColor(138, 226,  52 , 0).rgba())    # Chameleo 1
 
color_Dialog.setStandardColor(30, QtGui.QColor(115, 210,  22 , 0).rgba())    # Chameleo 2
 
color_Dialog.setStandardColor(36, QtGui.QColor( 78, 154,  6 , 0).rgba())    # Chameleo 3
 
color_Dialog.setStandardColor(42, QtGui.QColor( 23,  42,  4 , 0).rgba())    # Chameleo 4
 
#### Dialog line 2
 
color_Dialog.setStandardColor( 1, QtGui.QColor(252, 175,  62 , 0).rgba())    # Orang 1
 
color_Dialog.setStandardColor( 7, QtGui.QColor(245, 121,  0 , 0).rgba())    # Orang 2
 
color_Dialog.setStandardColor(13, QtGui.QColor(206,  92,  0 , 0).rgba())    # Orang 3
 
color_Dialog.setStandardColor(19, QtGui.QColor( 50,  25,  0 , 0).rgba())    # Orang 4
 
 
color_Dialog.setStandardColor(25, QtGui.QColor(114, 159, 207 , 0).rgba())    # Sky Blu 1
 
color_Dialog.setStandardColor(31, QtGui.QColor( 52, 101, 164 , 0).rgba())    # Sky Blu 2
 
color_Dialog.setStandardColor(37, QtGui.QColor( 32,  74, 135 , 0).rgba())    # Sky Blu 3
 
color_Dialog.setStandardColor(43, QtGui.QColor( 11,  21,  33 , 0).rgba())    # Sky Blu 4
 
#### Dialog line 3
 
color_Dialog.setStandardColor( 2, QtGui.QColor(173, 127, 168 , 0).rgba())    # Plu 1
 
color_Dialog.setStandardColor( 8, QtGui.QColor(117,  80, 123 , 0).rgba())    # Plu 2
 
color_Dialog.setStandardColor(14, QtGui.QColor( 92,  53, 102 , 0).rgba())    # Plu 3
 
color_Dialog.setStandardColor(20, QtGui.QColor( 23,  16,  24 , 0).rgba())    # Plu 4
 
 
color_Dialog.setStandardColor(26, QtGui.QColor(233, 185, 110 , 0).rgba())    # Chocolat 1
 
color_Dialog.setStandardColor(32, QtGui.QColor(193, 125,  17 , 0).rgba())    # Chocolat 2
 
color_Dialog.setStandardColor(38, QtGui.QColor(143,  89,  2 , 0).rgba())    # Chocolat 3
 
color_Dialog.setStandardColor(44, QtGui.QColor( 39,  25,  3 , 0).rgba())    # Chocolat 4
 
#### Dialog line 4
 
color_Dialog.setStandardColor( 3, QtGui.QColor(239,  41,  41 , 0).rgba())    # Scarle Re 1
 
color_Dialog.setStandardColor( 9, QtGui.QColor(204,  0,  0 , 0).rgba())    # Scarle Re 2
 
color_Dialog.setStandardColor(15, QtGui.QColor(164,  0,  0 , 0).rgba())    # Scarle Re 3
 
color_Dialog.setStandardColor(21, QtGui.QColor( 40,  0,  0 , 0).rgba())    # Scarle Re 4
 
 
color_Dialog.setStandardColor(27, QtGui.QColor( 52, 224, 226 , 0).rgba())    # FreeTea 1
 
color_Dialog.setStandardColor(33, QtGui.QColor( 22, 208, 210 , 0).rgba())    # FreeTea 2
 
color_Dialog.setStandardColor(39, QtGui.QColor(  6, 152, 154 , 0).rgba())    # FreeTea 3
 
color_Dialog.setStandardColor(45, QtGui.QColor(  4,  42,  42 , 0).rgba())    # FreeTea 4
 
#### Dialog line 5
 
color_Dialog.setStandardColor( 4, QtGui.QColor(255, 255, 255 , 0).rgba())    # Snow White
 
 
color_Dialog.setStandardColor(10, QtGui.QColor(238, 238, 236 , 0).rgba())    # Aluminiu 1
 
color_Dialog.setStandardColor(16, QtGui.QColor(211, 215, 207 , 0).rgba())    # Aluminiu 2
 
color_Dialog.setStandardColor(22, QtGui.QColor(186, 189, 182 , 0).rgba())    # Aluminiu 3
 
 
color_Dialog.setStandardColor(28, QtGui.QColor(136, 138, 133 , 0).rgba())    # Aluminiu 4
 
color_Dialog.setStandardColor(34, QtGui.QColor( 85,  87,  83 , 0).rgba())    # Aluminiu 5
 
color_Dialog.setStandardColor(40, QtGui.QColor( 46,  52,  54 , 0).rgba())    # Aluminiu 6
 
 
color_Dialog.setStandardColor(46, QtGui.QColor(  0,  0,  0 , 0).rgba())    # Je Black
 
#### Dialog line 6
 
color_Dialog.setStandardColor( 5, QtGui.QColor(255, 255, 255 , 0).rgba())    # Snow White
 
color_Dialog.setStandardColor(11, QtGui.QColor(255,  0,  0 , 0).rgba())    # Aluminiu 1
 
color_Dialog.setStandardColor(17, QtGui.QColor(  0, 255,  0 , 0).rgba())    # Aluminiu 2
 
color_Dialog.setStandardColor(23, QtGui.QColor(  0,  0, 255 , 0).rgba())    # Aluminiu 3
 
 
color_Dialog.setStandardColor(29, QtGui.QColor(255, 255,  0 , 0).rgba())    # Aluminiu 4
 
color_Dialog.setStandardColor(35, QtGui.QColor(255,  0, 255 , 0).rgba())    # Aluminiu 5
 
color_Dialog.setStandardColor(41, QtGui.QColor(  0, 255, 255 , 0).rgba())    # Aluminiu 6
 
color_Dialog.setStandardColor(47, QtGui.QColor(  0,  0,  0 , 0).rgba())    # Je Black
 
color_Dialog.setStandardColor(47, QtGui.QColor(  0,  0,  0 , 0).rgba())    # Je Black
 
 
#### Customize the colors to Dialog CustomColor (in hexadecimal converted in numeric mode)
 
# Use the Yellow tones for tools that create objects.
 
# Dialog line 1
 
color_Dialog.setCustomColor(0, QtGui.QColor( int("fc",16),int("e9",16),int("4f",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(2, QtGui.QColor( int("ed",16),int("d4",16),int("00",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(4, QtGui.QColor( int("c4",16),int("a0",16),int("00",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(6, QtGui.QColor( int("30",16),int("2b",16),int("00",16) , 0).rgba()) # hexadecimal converted in int
 
 
# Use the Blue tones for tools that modify objects
 
color_Dialog.setCustomColor(8, QtGui.QColor( int("72",16),int("9f",16),int("cf",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(10,QtGui.QColor( int("34",16),int("65",16),int("a4",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(12,QtGui.QColor( int("20",16),int("4a",16),int("87",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(14,QtGui.QColor( int("0b",16),int("15",16),int("21",16) , 0).rgba()) # hexadecimal converted in int
 
 
# Use the Teal tones for view-related tools
 
# Dialog line 2
 
color_Dialog.setCustomColor(1, QtGui.QColor( int("34",16),int("e0",16),int("e2",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(3, QtGui.QColor( int("16",16),int("d0",16),int("d2",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(5, QtGui.QColor( int("06",16),int("98",16),int("9a",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(7, QtGui.QColor( int("04",16),int("2a",16),int("2a",16) , 0).rgba()) # hexadecimal converted in int
 
 
# Use the Red tones for Constraint related tools
 
color_Dialog.setCustomColor(9, QtGui.QColor( int("ef",16),int("29",16),int("29",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(11,QtGui.QColor( int("cc",16),int("00",16),int("00",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(13,QtGui.QColor( int("a4",16),int("00",16),int("00",16) , 0).rgba()) # hexadecimal converted in int
 
color_Dialog.setCustomColor(15,QtGui.QColor( int("28",16),int("00",16),int("00",16) , 0).rgba()) # hexadecimal converted in int
 
 
Color = color_Dialog.getColor()                                  # Color.name() extract the color in Hexadecimal mode (#ad7fa8)
 
 
if Color.isValid():
 
 
    print("__.name()___________")
 
    print("hexadecimal        ", Color.name())                  # color format hexadecimal mode 16
 
    red  = int(str( Color.name()[1:3]),16 )                      # decode hexadecimal to int()
 
    green = int(str( Color.name()[3:5]),16 )                      # decode hexadecimal to int()
 
    blue  = int(str( Color.name()[5:7]),16 )                      # decode hexadecimal to int()
 
 
    print("Red  color decimal ", str( Color.name()[1:3]), red )  # color format hex to decimal
 
    print("Green color decimal ", str( Color.name()[3:5]), green )# color format hex to decimal
 
    print("Blue  color decimal ", str( Color.name()[5:7]), blue ) # color format hex to decimal
 
 
    print("__.red()____________")
 
    print("Red  color decimal ", Color.red() )                  # extract the color RGBa with Qt (0 to 255)
 
    print("Green color decimal ", Color.green() )                # extract the color RGBa with Qt (0 to 255)
 
    print("Blue  color decimal ", Color.blue() )                  # extract the color RGBa with Qt (0 to 255)
 
    print("Alpha      decimal ", Color.alpha() )                # extract the color RGBa with Qt (0 to 255)
 
 
    print("__.redF()___________")
 
    print("Red  color float  ", Color.redF() )                  # extract the color RGBa with Qt (0.0 to 1.0) as FreeCAD
 
    print("Green color float  ", Color.greenF() )                # extract the color RGBa with Qt (0.0 to 1.0) as FreeCAD
 
    print("Blue  color float  ", Color.blueF() )                # extract the color RGBa with Qt (0.0 to 1.0) as FreeCAD
 
    print("Alpha      float  ", Color.alphaF() )                # extract the color RGBa with Qt (0.0 to 1.0) as FreeCAD
 
    print("__enjoy_____________")
 
 
else:
 
    Color = ""
 
 
}}
 
 
 
==Display Image with QLabel and Gif animated with QMovie==
 
 
{{Code|code=
 
import PySide
 
from PySide import QtGui ,QtCore
 
from PySide.QtGui import QPixmap, QMovie, QLabel
 
from PySide.QtCore import *
 
class MyLabelPatience():
 
    label = QtGui.QLabel()
 
    label.setText("<img src=" + path_Name_Image + "><b><center>Wait please</center> \n\n<center>i search the fonts !\n\n</center></b>")
 
    # center screen
 
    ecran = FreeCADGui.getMainWindow().frameGeometry()
 
    xF = 250; yF = 120
 
    xW = (ecran.width()/2) - (xF/2)
 
    yW = (ecran.height()/2)- (yF/2)
 
    label.setGeometry(xW, yW, xF, yF)
 
    ####
 
    label.setStyleSheet("QLabel {background-color : #F0C300;font: 12pt; }");
 
    label.setWindowFlags(Qt.WindowFlags(Qt.FramelessWindowHint))        # pas de bords (not border)
 
    ### un-comment for use ###############
 
    movie = QtGui.QMovie(path_Name_Image)    # anime le fichier Gif anime (decommenter)
 
    label.setMovie(movie)
 
    movie.start()
 
    ##################
 
 
patience = MyLabelPatience().label
 
patience.show()                    #show the image
 
#patience.close()                  #close the Qlabel
 
#MyLabelPatience().movie.start()    #start the animation (after patience.show())
 
#MyLabelPatience().movie.stop()    #stop animation
 
 
}}
 
 
* Example QLabel with image and text
 
 
{{clear}}
 
[[File:Qlabel Image00.png|left|Example QLabel with image]]
 
{{clear}}
 
 
* Example QLabel with image animated Gif
 
 
{{clear}}
 
[[File:Qlabel Image Animee00.gif|left|Example animated Gif]]
 
{{clear}}
 
==Some useful commands==
 
 
{{Code|code=
 
# Here the code to display the icon on the '''pushButton''',
 
# change the name to another button, ('''radioButton, checkBox''') as well as the path to the icon,
 
 
      # Displays an icon on the button PushButton
 
      # self.image_01 = "C:\Program Files\FreeCAD0.13\icone01.png" # he name of the icon
 
      self.image_01 = path+"icone01.png" # the name of the icon
 
      icon01 = QtGui.QIcon()
 
      icon01.addPixmap(QtGui.QPixmap(self.image_01),QtGui.QIcon.Normal, QtGui.QIcon.Off)
 
      self.pushButton.setIcon(icon01)
 
      self.pushButton.setLayoutDirection(QtCore.Qt.RightToLeft) # This command reverses the direction of the button
 
 
 
# path = FreeCAD.ConfigGet("UserAppData") # gives the user path
 
  path = FreeCAD.ConfigGet("AppHomePath") # gives the installation path of FreeCAD
 
 
# This command reverses the horizontal button, right to left
 
self.pushButton.setLayoutDirection(QtCore.Qt.RightToLeft) # This command reverses the horizontal button
 
 
# Displays an info button
 
self.pushButton.setToolTip(_translate("MainWindow", "Quitter la fonction", None)) # Displays an info button
 
 
# This function gives a color button
 
self.pushButton.setStyleSheet("background-color: red") # This function gives a color button
 
 
# This function gives a color to the text of the button
 
self.pushButton.setStyleSheet("color : #ff0000") # This function gives a color to the text of the button
 
 
# combinaison des deux, bouton et texte
 
self.pushButton.setStyleSheet("color : #ff0000; background-color : #0000ff;" ) #  combination of the two, button, and text
 
 
# replace the icon in the main window
 
MainWindow.setWindowIcon(QtGui.QIcon('C:\Program Files\FreeCAD0.13\View-C3P.png'))
 
 
# connects a lineEdit on execute
 
self.lineEdit.returnPressed.connect(self.execute) # connects a lineEdit on "def execute" after validation on enter
 
# self.lineEdit.textChanged.connect(self.execute) # connects a lineEdit on "def execute" with each keystroke on the keyboard
 
 
# display text in a lineEdit
 
self.lineEdit.setText(str(val_X)) # Displays the value in the lineEdit (convert to string)
 
 
# extract the string contained in a lineEdit
 
val_X = self.lineEdit.text() # extract the (string) string contained in lineEdit
 
val_X = float(val_X0)        # converted the string to an floating
 
val_X = int(val_X0)          # convert the string to an integer
 
 
# This code allows you to change the font and its attributes
 
      font = QtGui.QFont()
 
      font.setFamily("Times New Roman")
 
      font.setPointSize(10)
 
      font.setWeight(10)
 
      font.setBold(True) # same result with tags "<b>your text</b>" (in quotes)
 
      self.label_6.setFont(font)
 
      self.label_6.setObjectName("label_6")
 
      self.label_6.setStyleSheet("color : #ff0000") # This function gives a color to the text
 
      self.label_6.setText(_translate("MainWindow", "Select a view", None))
 
}}
 
 
By using the characters with accents, where you get the error :
 
 
<FONT COLOR="#FF0000">'''UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-2: invalid data'''</FONT>
 
 
Several solutions are possible.
 
{{Code|code=
 
# conversion from a lineEdit
 
App.activeDocument().CopyRight.Text = str(unicode(self.lineEdit_20.text() , 'ISO-8859-1').encode('UTF-8'))
 
DESIGNED_BY = unicode(self.lineEdit_01.text(), 'ISO-8859-1').encode('UTF-8')
 
}}
 
or with the procedure
 
{{Code|code=
 
def utf8(unio):
 
    return unicode(unio).encode('UTF8')
 
}}
 
 
<FONT COLOR="#FF0000">'''UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 9: ordinal not in range(128)'''</FONT>
 
 
{{Code|code=
 
# conversion
 
a = u"Nom de l'élément : "
 
f.write('''a.encode('iso-8859-1')'''+str(element_)+"\n")
 
}}
 
or with the procedure
 
{{Code|code=
 
def iso8859(encoder):
 
    return unicode(encoder).encode('iso-8859-1')
 
}}
 
or
 
{{Code|code=
 
iso8859(unichr(176))
 
}}
 
or
 
{{Code|code=
 
unichr(ord(176))
 
}}
 
or
 
{{Code|code=
 
uniteSs = "mm"+iso8859(unichr(178))
 
print(unicode(uniteSs, 'iso8859'))
 
}}
 
 
== Relevant Links ==
 
 
* [[Manual:Creating interface tools]]
 
* [[Manual:Creating interface tools]]
 +
* [[Interface_creation_with_UI_files|Interface creation with UI files]]
  
{{docnav|[[Line drawing function|Line drawing function]]|[[Licence|Licence]]}}
 
 
{{Userdocnavi}}
 
 
<div class="mw-translate-fuzzy">
 
[[Category:Poweruser Documentation/cs]]
 
[[Category:Python Code/cs]]
 
</div>
 
 
[[Category:Python Code]]
 
 
[[Category:Developer]]
 
 
[[Category:Developer Documentation]]
 
  
 +
{{Powerdocnavi{{#translation:}}}}
 +
[[Category:Developer Documentation{{#translation:}}]]
 +
[[Category:Python Code{{#translation:}}]]
 
{{clear}}
 
{{clear}}

Latest revision as of 14:04, 10 March 2021

Other languages:
Deutsch • ‎English • ‎Türkçe • ‎español • ‎français • ‎italiano • ‎polski • ‎română • ‎svenska • ‎čeština • ‎русский

Introduction

In this page we will show how to build a simple graphical interface with Qt Designer, Qt's official tool for designing interfaces; the dialog will be converted to Python code, then it will be used inside FreeCAD. We'll assume that the user knows how to edit and run Python generally.

In this example, the entire interface is defined in Python. Although this is possible for small interfaces, for larger interfaces the recommendation is to load the created .ui files directly into the program. See Interface creation with UI files for more information.

FreeCAD creating interfaces.svg

Two general methods to create interfaces, by including the interface in the Python file, or by using .ui files.

Designing the dialog

In CAD applications, designing a good UI (User Interface) is very important. About everything the user will do will be through some piece of interface: reading dialog boxes, pressing buttons, choosing between icons, etc. So it is very important to think carefully to what you want to do, how you want the user to behave, and how will be the workflow of your action.

There are a couple of concepts to know when designing interface:

  • Modal/non-modal dialogs: A modal dialog appears in front of your screen, stopping the action of the main window, forcing the user to respond to the dialog, while a non-modal dialog doesn't stop you from working on the main window. In some case the first is better, in other cases not.
  • Identifying what is required and what is optional: Make sure the user knows what he must do. Label everything with proper description, use tooltips, etc.
  • Separating commands from parameters: This is usually done with buttons and text input fields. The user knows that clicking a button will produce an action while changing a value inside a text field will change a parameter somewhere. Nowadays, though, users usually know well what is a button, what is an input field, etc. The interface toolkit we are using, Qt, is a state-of-the-art toolkit, and we won't have to worry much about making things clear, since they will already be very clear by themselves.

So, now that we have well defined what we will do, it's time to open the qt designer. Let's design a very simple dialog, like this:

Qttestdialog.jpg

We will then use this dialog in FreeCAD to produce a nice rectangular plane. You might find it not very useful to produce nice rectangular planes, but it will be easy to change it later to do more complex things. When you open it, Qt Designer looks like this:

Qtdesigner-screenshot.jpg

Creating the dialog

Qt Designer is very simple to use. On the left bar you have elements that can be dragged on your widget. On the right side you have properties panels displaying all kinds of editable properties of selected elements. So, begin with creating a new widget.

  1. Select "Dialog without buttons", since we don't want the default OK/Cancel buttons.
  2. We need 'Labels. Labels are simple text strings that appear on your widget to inform the end user. If you select a label, notice that on the right side there will appear several properties that you can modify such as: font style, height, etc... So lets drag 3 separate labels on to our widget:
    • One label for the title
    • Another label for writing "Height"
    • Another label for writing "Width"
  3. We now need LineEdits (2 of them actually). Drag two of them on to the widget. LineEdits are text fields that the end user can fill in. So we need one LineEdit for the Height and one for the Width. Here too, we can edit properties. For example, why not set a default value say for example: 1.00 for each. This way, when the user will see the dialog, both values will be filled already. If the end user is satisfied, they can directly press the button, saving precious time.
  4. Next lets add a PushButton. This is the button the end user will need to press after they've filled both fields.

Note: that we chose very simple controls here. Qt has many more options, for example one could use Spinboxes instead of LineEdits, etc... Have a look at what is available, explore...you will surely have other ideas.

That's about all we need to do in Qt Designer. One last thing, though, let's rename all our elements with simpler names, so it will be easier to identify them in our scripts:

Qtpropeditor.jpg

Converting our dialog to python

Now, let's save our widget somewhere. It will be saved as an .ui file, that we will easily convert to python script with pyuic. On windows, the pyuic program is bundled with pyqt (to be verified), on linux you probably will need to install it separately from your package manager (on debian-based systems, it is part of the pyqt4-dev-tools package). To do the conversion, you'll need to open a terminal window (or a command prompt window on windows), navigate to where you saved your .ui file, and issue:

pyuic mywidget.ui > mywidget.py

In Windows pyuic.py is located in "C:\Python27\Lib\site-packages\PyQt4\uic\pyuic.py" For conversion create a batch file called "compQt4.bat:

@"C:\Python27\python" "C:\Python27\Lib\site-packages\PyQt4\uic\pyuic.py" -x %1.ui > %1.py

In the DOS console type without extension

compQt4 myUiFile

In macOS, you can retrieve the appropriate version (the same that is used internally in FreeCAD 0.19) of QT and Pyside with this commands (pip required)

python3 -m pip install pyqt5
python3 -m pip install pySide2

This will install uic in the folder "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/uic", and Designer in "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/Designer.app". For convenience you can create a link of uic in /usr/local/bin to be able to call it simply with uic -g python ... instead of typing the whole path of the program, and a link to Designer to retrieve it in the mac's Applications folder with

sudo ln -s /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/uic /usr/local/bin
ln -s /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/Designer.app /Applications

Into Linux : to do

Since FreeCAD progressively moved away from PyQt after version 0.13, in favour of PySide (Choose your PySide install building PySide), to make the file based on PySide now you have to use:

pyside-uic mywidget.ui -o mywidget.py

In Windows uic.py are located in "C:\Python27\Lib\site-packages\PySide\scripts\uic.py" For create batch file "compSide.bat":

@"C:\Python27\python" "C:\Python27\Lib\site-packages\PySide\scripts\uic.py" %1.ui > %1.py

In the DOS console type without extension

compSide myUiFile

Into Linux : to do

On some systems the program is called pyuic4 instead of pyuic. This will simply convert the .ui file into a python script. If we open the mywidget.py file, its contents is very easy to understand:

from PySide 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))
        ...

As you see it has a very simple structure: a class named Ui_Dialog is created, that stores the interface elements of our widget. That class has two methods, one for setting up the widget, and one for translating its contents, which is part of the general Qt mechanism for translating interface elements. The setup method simply creates, one by one, the widgets as we defined them in Qt Designer, and sets their options as we decided earlier. Then, the whole interface gets translated, and finally, the slots get connected (we'll talk about that later).

We can now create a new widget and use this class to create its interface. We can already see our widget in action, by putting our mywidget.py file in a place where FreeCAD will find it (in the FreeCAD bin directory, or in any of the Mod subdirectories), and, in the FreeCAD python interpreter, issue:

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

And our dialog will appear! Note that our Python interpreter is still working, we have a non-modal dialog. So, to close it, we can (apart from clicking its close icon, of course) issue:

d.hide()

Making our dialog do something

Now that we can show and hide our dialog, we just need to add one last part: To make it do something! If you play a bit with Qt designer, you'll quickly discover a whole section called "signals and slots". Basically, it works like this: elements on your widgets (in Qt terminology, those elements are themselves widgets) can send signals. Those signals differ according to the widget type. For example, a button can send a signal when it is pressed and when it is released. Those signals can be connected to slots, which can be special functionality of other widgets (for example a dialog has a "close" slot to which you can connect the signal from a close button), or can be custom functions. The PyQt Reference Documentation lists all the qt widgets, what they can do, what signals they can send, etc...

What we will do here, is to create a new function that will create a plane based on height and width, and to connect that function to the pressed signal emitted by our "Create!" button. So, let's begin with importing our FreeCAD modules, by putting the following line at the top of the script, where we already import QtCore and QtGui:

import FreeCAD, Part

Then, let's add a new function to our Ui_Dialog class:

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()

Then, we need to inform Qt to connect the button to the function, by placing the following line just before QtCore.QMetaObject.connectSlotsByName(Dialog):

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

This, as you see, connects the pressed() signal of our create object (the "Create!" button), to a slot named createPlane, which we just defined. That's it! Now, as a final touch, we can add a little function to create the dialog, it will be easier to call. Outside the Ui_Dialog class, let's add this code:

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

(Python reminder: the __init__ method of a class is automatically executed whenever a new object is created!) Then, from FreeCAD, we only need to do:

import mywidget
myDialog = mywidget.plane()

That's all Folks... Now you can try all kinds of things, like for example inserting your widget in the FreeCAD interface (see the Code snippets page), or making much more advanced custom tools, by using other elements on your widget.

The complete script

This is the complete script, for reference:

# Form implementation generated from reading ui file 'mywidget.ui'
#
# Created: Mon Jun  1 19:09:10 2009
#      by: PyQt4 UI code generator 4.4.4
# Modified for PySide 16:02:2015 
# WARNING! All changes made in this file will be lost!

from PySide 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("Dialog")
       self.title.setText("Plane-O-Matic")
       self.label_width.setText("Width")
       self.label_height.setText("Height")
       self.create.setText("Create!")
       print("tyty")
   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():
  def __init__(self):
      self.d = QtGui.QWidget()
      self.ui = Ui_Dialog()
      self.ui.setupUi(self.d)
      self.d.show()

More examples

Relevant links