Dialog creation/ru: Difference between revisions

From FreeCAD Documentation
(Updating to match new version of source page)
No edit summary
 
(38 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<languages/>
<languages/>
{{docnav|Line drawing function|Licence}}


{{Docnav/ru
На этой странице мы покажем как создать простой Qt Dialog с помощью [http://qt-project.org/doc/qt-4.8/designer-manual.html Qt Designer], это официальный Qt инструмент для создания интерфейсов, затем сковертировать его в python код, ф затем использовать внутри FreeCAD. Я буде полагать в этом примере, что вы уже знаете как редактировать и запускать сценарии на python, и конечно что вы можете делать просты действия в окне терминала такие как навигация и.т.д. Конечно, у вас также должен быть установлен pyqt.
|[[Interface_creation/ru|Interface creation]]
|[[Licence/ru|Licence]]
}}

{{TOCright}}

== Введение ==

На этой странице мы покажем как создать простой графический интерфейс с помощью [http://qt-project.org/doc/qt-4.8/designer-manual.html Qt Designer], официальный инструмент Qt для создания интерфейсов, диалог будет сковертирован в код [[Python/ru|Python]], затем использован внутри FreeCAD. Мы будем полагать что пользователь знает в общих чертах как редактировать и запускать [[Python/ru|Python]].

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.

[[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.}}


== Проектирование диалога ==
== Проектирование диалога ==


В CAD приложения, очень важно, проектирование хорошего UI (User Interface/Пользовательского Интерфейса). Обо все что будет делать пользователь через части интерфейса: чтение диалоговых окон, нажатие кнопок, выбор между иконками, и.т.д. Так что очень важно тщательно подумать, что вы хотите сделать, как вы хотите чтобы пользователь повел себя и как будут работать ваши действия
В приложениях САПР очень важно проектирование хорошего Пользовательского Интерфейса. Практически всё, что пользователь будет делать, делается через части интерфейса: чтение диалоговых окон, нажатие кнопок, выбор между иконками, и.т.д. Так что очень важно тщательно подумать, что вы хотите сделать, как вы хотите чтобы пользователь повел себя и каков будет рабочий процесс с вашими действиями.


Известно несколько понятий, от том как проектировать интерфейс:
Известно несколько понятий, от том как проектировать интерфейс:
Line 21: Line 34:
[[Image:Qtdesigner-screenshot.jpg]]
[[Image:Qtdesigner-screenshot.jpg]]


== Создание диалога ==
Он очень прост в использовании. На левой панели есть элименты которые можно перетащить на ваш виджет. На правой стороне находится панель свойств отображающая все виды редактируемых свойств, выбранного элемента. Так что начните с создания нового виджета. Выберете "Диалог без кнопок", так как мы не хотим кнопки по умолчанию Ok/Cancel. Затем, перетащите на ваш виджет '''3 этикетки(labels)''', одна для заголовка, одно для надписи "Height" и одна для записи "Width". Этикетки это просто тексты которые появляются на вашем виджете, чтобы проинформировать пользователя. Если вы выбираете этикетку, на правой стороне появляются свойства которые вы можете поменять, если вы хотите, такие как стиль шрифта, высота и.т.д.
Qt Designer очень прост в использовании. На левой панели есть элименты которые можно перетащить на ваш виджет. На правой стороне находится панель свойств отображающая все виды редактируемых свойств, выбранного элемента. Так что начните с создания нового виджета.
# Выберете "Диалог без кнопок", так как мы не хотим кнопки по умолчанию {{KEY|OK}}/{{KEY|Cancel}}.
# Нам нужны '''Labels''. Labels (этикетки) - это просто тексты которые появляются на вашем виджете, чтобы проинформировать пользователя. Если вы выбираете этикетку, на правой стороне появляются свойства которые вы можете поменять, если вы хотите, такие как стиль шрифта, высота и.т.д. Так что перетащите на ваш виджет 3 этикетки:
#* Одна для заголовка,
#* Одно для надписи "Height"
#* Одна для записи "Width".
# Теперь нам нужны LineEdits. Перетащите два из них на виджет. '''LineEdits''' это текстовые поля, которые конечный пользователь может заполнить. Нам нужен один LineEdit для ''Height'' и один для ''Width''. Здесь мы тоже можем редактировать свойства. Например, почему бы не установить значения по умолчанию, например: 1.00 для каждого. Таким образом, пользователь увидит диалог, где оба значения уже заполнены. Если он удовлетворён, он может прямо нажать кнопку, сохраняя время.
# Далее добавим '''PushButton'''. Это кнопка, которую конечному пользователю следует нажать после заполнения обоих полей.


'''Заметьте:''' мы выбрали очень просто управление. В Qt гораздо больше функций, например, например вы можете использовать Spinboxes вместо LineEdits, и.т.д... Обратите внимание на то что доступно, у вас несомнено появятся другие идеи.
Затем, добавте '''2 LineEdits''', которые представляют собой текстовые поля которые пользователь может заполнить, одно для высоты(height) и одно для ширины(width). Здесь также, можно редактировать свойства. Например, почему не задать значение по умолчанию? Например по 1.00 для каждого. Таким образом, когда пользователь увидет диалоговое окно, боа значения будут уже введены и если его они удовлетворяют , он ожет сразу нажать на кнопку, сохранив драгоценное время. Потом, добавим '''PushButton''', которую кнопку необходимо нажать после тогокакон заполнит оба поля.

<div class="mw-translate-fuzzy">
Обратите внимание что здесь я выбрал очень просто управление, но в Qt гораздо больше функций, например, например вы можете использовать Spinboxes вместо LineEdits, и.т.д... Обратите внимание на то что доступно, у вас несомнено появятся другие идеи.
</div>


Вот и все, что мы должны сделать в Qt Designer. Последнее, давайте переименуем все наши элементы дав им более простые имена, так что будет легче определять их в нашем сценарии:
Вот и все, что мы должны сделать в Qt Designer. Последнее, давайте переименуем все наши элементы дав им более простые имена, так что будет легче определять их в нашем сценарии:
Line 36: Line 53:


Теперь сохраните ваш виджет где-нибудь. Он будет сохранен как .ui файл, который мы легко преобразуем в python сценарий с помощью pyuic. В windows, программа pyuic связанна с pyqt (должно быть проверено), на linux вам вероятно нужно будет установить его отдельно в вашем пакетном менеджере (для debian-based систем, это часть пакета pyqt4-dev-tools). Для преобразования, вам необходимо открыть окно терминала (или окно командной строки в windows), переместитесь туда где вы сохранили ваш .ui файл и введите:
Теперь сохраните ваш виджет где-нибудь. Он будет сохранен как .ui файл, который мы легко преобразуем в python сценарий с помощью pyuic. В windows, программа pyuic связанна с pyqt (должно быть проверено), на linux вам вероятно нужно будет установить его отдельно в вашем пакетном менеджере (для debian-based систем, это часть пакета pyqt4-dev-tools). Для преобразования, вам необходимо открыть окно терминала (или окно командной строки в windows), переместитесь туда где вы сохранили ваш .ui файл и введите:
{{Code|code=
<syntaxhighlight>
pyuic mywidget.ui > mywidget.py
pyuic mywidget.ui > mywidget.py
}}
</syntaxhighlight>
In Windows pyuic.py is located in "C:\Python27\Lib\site-packages\PyQt4\uic\pyuic.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:
For conversion create a batch file called "compQt4.bat:
{{Code|code=
<syntaxhighlight>
@"C:\Python27\python" "C:\Python27\Lib\site-packages\PyQt4\uic\pyuic.py" -x %1.ui > %1.py
@"C:\Python27\python" "C:\Python27\Lib\site-packages\PyQt4\uic\pyuic.py" -x %1.ui > %1.py
}}
</syntaxhighlight>
In the DOS console type without extension
In the DOS console type without extension
{{Code|code=
<syntaxhighlight>
compQt4 myUiFile
compQt4 myUiFile
}}
</syntaxhighlight>

In macOS, you can retrieve the appropriate version (the same that is used internally in FreeCAD 0.19) of QT and Pyside with these 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
}}

Into Linux : to do
Into Linux : to do


<!--T:55-->
Since FreeCAD progressively moved away from PyQt after version 0.13, in favour of [http://qt-project.org/wiki/PySide PySide] (Choose your PySide install [http://pyside.readthedocs.org/en/latest/building/ building PySide]), to make the file based on PySide now you have to use:
Since FreeCAD progressively moved away from PyQt after version 0.13, in favour of [http://qt-project.org/wiki/PySide PySide] (Choose your PySide install [http://pyside.readthedocs.org/en/latest/building/ building PySide]), to make the file based on PySide now you have to use:


{{Code|code=
<syntaxhighlight>
pyside-uic mywidget.ui -o mywidget.py
pyside-uic mywidget.ui -o mywidget.py
}}
</syntaxhighlight>
In Windows uic.py are located in "C:\Python27\Lib\site-packages\PySide\scripts\uic.py"
In Windows uic.py are located in "C:\Python27\Lib\site-packages\PySide\scripts\uic.py"
For create batch file "compSide.bat":
For create batch file "compSide.bat":
{{Code|code=
<syntaxhighlight>
@"C:\Python27\python" "C:\Python27\Lib\site-packages\PySide\scripts\uic.py" %1.ui > %1.py
@"C:\Python27\python" "C:\Python27\Lib\site-packages\PySide\scripts\uic.py" %1.ui > %1.py
}}
</syntaxhighlight>
In the DOS console type without extension
In the DOS console type without extension
{{Code|code=
<syntaxhighlight>
compSide myUiFile
compSide myUiFile
}}
</syntaxhighlight>
Into Linux : to do
Into Linux : to do


На некоторых системах программа называется pyuic4 вместо pyuic. Это просто сконвертирует файл .ui файл в сценарий python. Если мы откроем файл mywidget.py, его содержание очень легко понять:

{{Code|code=
<div class="mw-translate-fuzzy">
На некоторых системах вызвайте pyuic4 вместо pyuic. Просто сконвертируйте .ui файл в python сценарий. Если вы откроем файл mywidget.py , его содержание очень легко понять:
</div>
<syntaxhighlight>
from PySide import QtCore, QtGui
from PySide import QtCore, QtGui


Line 91: Line 117:
self.title.setText(QtGui.QApplication.translate("Dialog", "Plane-O-Matic", None, QtGui.QApplication.UnicodeUTF8))
self.title.setText(QtGui.QApplication.translate("Dialog", "Plane-O-Matic", None, QtGui.QApplication.UnicodeUTF8))
...
...
}}
</syntaxhighlight>
Как вы видете, он обладает очень простым устройством: созданный класс называемый Ui_Dialog, он содержит все элементы интерфейса нашего виджета. Этот класс обладает двумя методами, один для создания виджета, и одни для перевода его содержания, которая является частью механизма Qt для перевода элементов интерфейса. Метод установки(setup method) просто создает один за другим, виджетв так как мы задали их в Qt Designer, и задает их настройки так как мы определили ранее. Затем, весь инструмент будет переведен, и наконец, подключаются слоты (мы поговорим об этом позже).
<div class="mw-translate-fuzzy">
Как вы видете, он обладает очень простым устройством: созданный класс называемый Ui_Dialog, он содержит все элементы интерфейса нашего виджета. Этот класс обладает двумя методами, один для создания виджета, и одни для перевода его содержания, эта часть является основным Qt механизмом для перевода элементов интерфейса. Метод установки(setup method) просто создает один за другим, виджетв так как мы задали их в Qt Designer, и задает их настройки так как мы определили ранее. Затем, весь инструмент будет переведен, и наконец, подключаются слоты (мы поговорим об этом позже).
</div>


Теперь мы можем создать новый виджет и использовать этот класс для созданияего интерфейса. Мы уже можем увидеть наш виджет в действии, поместив наш файл mywidget.py в место где FreeCAD сможет найти его (в FreeCAD в паку bin, или в любую Mod поддиректорию), и ввести в интерпретаторе FreeCAD python:
<div class="mw-translate-fuzzy">
{{Code|code=
Теперь мы можем создать новый виджет и использовать этот класс для созданияего интерфейса. Мы уже можем увидеть наш виджет в действии, поместив наш файл mywidget.py в место где FreeCAD сможет найти его (в FreeCAD в паку bin, или в любую Mod поддеерикторию) ,и ввести в FreeCAD python интепритатор:
</div>
<syntaxhighlight>
from PySide import QtGui
from PySide import QtGui
import mywidget
import mywidget
Line 106: Line 128:
d.ui.setupUi(d)
d.ui.setupUi(d)
d.show()
d.show()
}}
</syntaxhighlight>
И наш диалог появится! Заметим, что наш интерпретатор по прежнему работает, т.е у нас не модальный диалог. Так что, закроем его, мы можем (конечно, помимо того как щелкнуть на иконке закрытия) ввести:
<div class="mw-translate-fuzzy">
{{Code|code=
И наш диалог появится! Заметим, что наш интерпритатор по прежнему работает, т.е у нас не модальный диалог. Так что, закроем его, мы можеи (конечно, помимо того как щелкнуть на иконке закрытия) ввести:
</div>
<syntaxhighlight>
d.hide()
d.hide()
}}
</syntaxhighlight>


== делаем так чтобы наш диалог делал что-нибудь ==
== Делаем так чтобы наш диалог делал что-нибудь ==


Теперь когда мы можем показать или скрыть наш диалог, на осталось добавить последнюю часть:Чтобы оно что-то делало! Если вы немного поиграетесь с Qt designer, вы быстро обнаружите целый раздел под название "сигналы и слоты". В основном, это работает следующим образом: элемент на вашем виджете (в Qt терминалогии, эти элементы сами по себе являются виджетами) может отправить сигнал. Этот сигнал отличаются в зависимости от типа виджета. Например, кнопка может подать сигнал при нажатии, и когда она будет отпущена. Этот сигнал может быть соединен со слотами, которые могут быть специальными функциями других виджетов(например диалог обладающий слотом "закрыть" который можно подключить к сигналу от кнопки закрытия), или это могут быть пользовательские функции. [http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/classes.html PyQt Reference Documentation] список всех qt виджетов, что они делают, какие сигналы могут отправлять и.т.д...
Теперь когда мы можем показать или скрыть наш диалог, на осталось добавить последнюю часть:Чтобы оно что-то делало! Если вы немного поиграетесь с Qt designer, вы быстро обнаружите целый раздел под название "сигналы и слоты". В основном, это работает следующим образом: элемент на вашем виджете (в Qt терминалогии, эти элементы сами по себе являются виджетами) может отправить сигнал. Этот сигнал отличаются в зависимости от типа виджета. Например, кнопка может подать сигнал при нажатии, и когда она будет отпущена. Этот сигнал может быть соединен со слотами, которые могут быть специальными функциями других виджетов(например диалог обладающий слотом "закрыть" который можно подключить к сигналу от кнопки закрытия), или это могут быть пользовательские функции. [http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/classes.html PyQt Reference Documentation] список всех qt виджетов, что они делают, какие сигналы могут отправлять и.т.д...


Что мы будем делать здесь, создадим новую функцию , которая создает плоскость основываясь на её длине и ширине, и подключим эту функцию к сигналу нажатия испускаемому нашей кнопкой "Create!" . Так что , давайте начнем с импорта наших модулейr FreeCAD, палагая следующую строку введенной в начале нашего сценария, где мы уже импортировали QtCore и QtGui:
Что мы будем делать здесь, создадим новую функцию , которая создает плоскость основываясь на её длине и ширине, и подключим эту функцию к сигналу нажатия испускаемому нашей кнопкой "Create!" . Так что , давайте начнем с импорта наших модулейr FreeCAD, палагая следующую строку введенной в начале нашего сценария, где мы уже импортировали QtCore и QtGui:
{{Code|code=
<syntaxhighlight>
import FreeCAD, Part
import FreeCAD, Part
}}
</syntaxhighlight>
Затем , давайте добавим новую функцию в наш класс Ui_Dialog:
Затем , давайте добавим новую функцию в наш класс Ui_Dialog:
{{Code|code=
<syntaxhighlight>
def createPlane(self):
def createPlane(self):
try:
try:
Line 130: Line 150:
h = float(self.height.text())
h = float(self.height.text())
except ValueError:
except ValueError:
print "Error! Width and Height values must be valid numbers!"
print("Error! Width and Height values must be valid numbers!")
else:
else:
# create a face from 4 points
# create a face from 4 points
Line 142: Line 162:
Part.show(myface)
Part.show(myface)
self.hide()
self.hide()
}}
</syntaxhighlight>
Потом, нам нужно сообщить Qt о подключении функции к кнопке, разместив следующую строчку перед QtCore.QMetaObject.connectSlotsByName(Dialog):
Потом, нам нужно сообщить Qt о подключении функции к кнопке, разместив следующую строчку перед QtCore.QMetaObject.connectSlotsByName(Dialog):
{{Code|code=
<syntaxhighlight>
QtCore.QObject.connect(self.create,QtCore.SIGNAL("pressed()"),self.createPlane)
QtCore.QObject.connect(self.create,QtCore.SIGNAL("pressed()"),self.createPlane)
}}
</syntaxhighlight>
как вы видете, подключение сигнала pressed() от нашего созданного объекта (кнопка "Create!"), к слоту названому createPlane, который мы только что определили. И это всё!!Теперь,финальный штрих, мы можем добавить маленькую функцию в создание диалога, его легче будет вызвать. Вне класса Ui_Dialog, давайте добавим этот код:
как вы видете, подключение сигнала pressed() от нашего созданного объекта (кнопка "Create!"), к слоту названому createPlane, который мы только что определили. И это всё!!Теперь,финальный штрих, мы можем добавить маленькую функцию в создание диалога, его легче будет вызвать. Вне класса Ui_Dialog, давайте добавим этот код:
{{Code|code=
<syntaxhighlight>
class plane():
class plane():
def __init__(self):
def __init__(self):
Line 155: Line 175:
self.ui.setupUi(self.d)
self.ui.setupUi(self.d)
self.d.show()
self.d.show()
}}
</syntaxhighlight>
(Python reminder: the __init__ method of a class is automatically executed whenever a new object is created!)
(Python reminder: the __init__ method of a class is automatically executed whenever a new object is created!)


Затем , в FreeCAD, нам необходимо сделать только:
Затем , в FreeCAD, нам необходимо сделать только:
{{Code|code=
<syntaxhighlight>
import mywidget
import mywidget
myDialog = mywidget.plane()
myDialog = mywidget.plane()
}}
</syntaxhighlight>
"Это все ребята"... Теперь вы можете попробовать разные вещи, например как вставить ваш виджет в FreeCAD интерфейс (смотри страницу [[Code snippets/ru|Отрывки кода]] ), или создать более продвинутый пользовательский инструмент, используя другие элементы в вашем виджете.
"Это все ребята"... Теперь вы можете попробовать разные вещи, например как вставить ваш виджет в FreeCAD интерфейс (смотри страницу [[Code snippets/ru|Отрывки кода]] ), или создать более продвинутый пользовательский инструмент, используя другие элементы в вашем виджете.


Line 168: Line 188:


Это полный сценарий, для справки:
Это полный сценарий, для справки:
{{Code|code=
<syntaxhighlight>
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'mywidget.ui'
# Form implementation generated from reading ui file 'mywidget.ui'
#
#
Line 209: Line 227:


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 221: Line 239:
h = float(self.height.text())
h = float(self.height.text())
except ValueError:
except ValueError:
print "Error! Width and Height values must be valid numbers!"
print("Error! Width and Height values must be valid numbers!")
else:
else:
# create a face from 4 points
# create a face from 4 points
Line 234: Line 252:


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()
</syntaxhighlight>
==Creation of a dialog with buttons==

===Method 1===
An example of a dialog box complete with its connections.
<syntaxhighlight>
# -*- 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()
</syntaxhighlight>
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]]

<syntaxhighlight>
# -*- 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()
</syntaxhighlight>
Here the code to display the icon on the '''pushButton''', change the name for another button, ('''radioButton, checkBox''') and the path to the icon.
<syntaxhighlight>
# 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
</syntaxhighlight>
The command
'''UserAppData''' gives the user path
'''AppHomePath''' gives the installation path of FreeCAD
<syntaxhighlight>
# path = FreeCAD.ConfigGet("UserAppData")
path = FreeCAD.ConfigGet("AppHomePath")
</syntaxhighlight>
This command reverses the horizontal button, right to left.
<syntaxhighlight>
self.pushButton.setLayoutDirection(QtCore.Qt.RightToLeft) # This command reverses the direction of the button
</syntaxhighlight>

===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'''
<syntaxhighlight>

# -*- 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))
</syntaxhighlight>
The calling file that contains the window and your code.

The file my_file.py

The connections are to do, a good exercise.
<syntaxhighlight>

# -*- 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, "essai 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()
</syntaxhighlight>

'''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}}

<syntaxhighlight>
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

</syntaxhighlight>

Complete example creating a cube and its icon

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


</syntaxhighlight>

==Use QFileDialog for writing to a file==
Complete code:
<syntaxhighlight>
# -*- coding: utf-8 -*-
import PySide
from PySide import QtGui ,QtCore
from PySide.QtGui import *
from PySide.QtCore import *
path = FreeCAD.ConfigGet("UserAppData")

try:
SaveName = QFileDialog.getSaveFileName(None,QString.fromLocal8Bit("Save a file txt"),path, "*.txt") # PyQt4
# "here the text displayed on windows" "here the filter (extension)"
except Exception:
SaveName, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Save a file txt", path, "*.txt") # PySide
# "here the text displayed on windows" "here the filter (extension)"
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)

</syntaxhighlight>

==Use QFileDialog to read a file==
Complete code:
<syntaxhighlight>
# -*- 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)

</syntaxhighlight>

==Use QColorDialog to get the color==
Complete code:
<syntaxhighlight>
# -*- 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

</syntaxhighlight>

==Some useful commands==
<syntaxhighlight>
# 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))
</syntaxhighlight>

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.
<syntaxhighlight>
# 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')
</syntaxhighlight>
or with the procedure
<syntaxhighlight>
def utf8(unio):
return unicode(unio).encode('UTF8')
</syntaxhighlight>


}}
<FONT COLOR="#FF0000">'''UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 9: ordinal not in range(128)'''</FONT>


==More examples ==
<syntaxhighlight>
# conversion
a = u"Nom de l'élément : "
f.write('''a.encode('iso-8859-1')'''+str(element_)+"\n")
</syntaxhighlight>
or with the procedure
<syntaxhighlight>
def iso8859(encoder):
return unicode(encoder).encode('iso-8859-1')
</syntaxhighlight>
or
<syntaxhighlight>
iso8859(unichr(176))
</syntaxhighlight>
or
<syntaxhighlight>
unichr(ord(176))
</syntaxhighlight>
or
<syntaxhighlight>
uniteSs = "mm"+iso8859(unichr(178))
print unicode(uniteSs, 'iso8859')
</syntaxhighlight>


* [[Dialog_creation_with_various_widgets|Dialog creation with various widgets]] with {{incode|QPushButton}}, {{incode|QLineEdit}}, {{incode|QCheckBox}}, {{incode|QRadioButton}}, and others.
* [[Dialog_creation_reading_and_writing_files|Dialog creation reading and writing files]] with {{incode|QFileDialog}}.
* [[Dialog_creation_setting_colors|Dialog creation setting colors]] with {{incode|QColorDialog}}.
* [[Dialog_creation_image_and_animated_GIF|Dialog creation image and animated GIF]] with {{incode|QLabel}} and {{incode|QMovie}}.
* [[PySide_usage_snippets|PySide usage snippets]].
* [[Qt_Example|Qt Example]]


== Relevant links ==
{{docnav/ru|Line drawing function/ru|Licence/ru}}


* [[Manual:Creating interface tools]]
{{Userdocnavi}}


<div class="mw-translate-fuzzy">
[[Category:Poweruser Documentation/ru]]
[[Category:Python Code/ru]]
</div>


{{Docnav/ru
[[Category:Python Code]]
|[[Interface_creation/ru|Interface creation]]
|[[Licence/ru|Licence]]
}}


{{Powerdocnavi{{#translation:}}}}
{{clear}}
[[Category:Developer Documentation{{#translation:}}]]
[[Category:Python Code{{#translation:}}]]

Latest revision as of 14:59, 14 November 2021

Введение

На этой странице мы покажем как создать простой графический интерфейс с помощью Qt Designer, официальный инструмент Qt для создания интерфейсов, диалог будет сковертирован в код Python, затем использован внутри FreeCAD. Мы будем полагать что пользователь знает в общих чертах как редактировать и запускать Python.

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.

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

Проектирование диалога

В приложениях САПР очень важно проектирование хорошего Пользовательского Интерфейса. Практически всё, что пользователь будет делать, делается через части интерфейса: чтение диалоговых окон, нажатие кнопок, выбор между иконками, и.т.д. Так что очень важно тщательно подумать, что вы хотите сделать, как вы хотите чтобы пользователь повел себя и каков будет рабочий процесс с вашими действиями.

Известно несколько понятий, от том как проектировать интерфейс:

  • Modal/non-modal dialogs: Модальное окно появляется поверх всех окон, останавливая действия происходящие в главном окне приложения, заставляя пользователя отвечать в диалоговом окне, тогда как не модальный диалог не останавливает вас от работы в главном окне. В некоторых случаях лучше первое, в других нет.
  • Определение того, что требуется и что считается дополнительны: Убедитесь что пользователь знает что он должен делать. Ставте на все метки с описанием, используйте подсказки, и.т.д.
  • Отделяйте команды от параметров: Это обычно делается с помощью кнопок и полей текстовых ввода. Пользователь знает что нажатие кнопки будет производить действие тогда как изменение значения внутри текстового поля где-то будет изменять параметр. В настоящие время, однако, пользователи обычно отлично знают что есть кнопка, а что есть поле ввода, и.т.д. В качестве графического инструментария используется, Qt, это современный инструментарий, и мы не должны больш беспокоится о создании ясности, так как он уже сам по себе очень ясный/понятный интерфейс.

Таким образом, теперь когда мы четко определили что должны делать, откройте qt designer. Давайте спроектируем очень простой диалог, как здесь:

Мы будем использовать этот диалог в FreeCAD для создания хороших прямоугольных плоскосте. Вам может показаться что это не очень удобно для создания прямоугольных плоскосте, но его легко можно изменить позже, чтобы делать более сложные вещи. Когда вы откроете Qt Designer, он выглядит следующим образом:

Создание диалога

Qt Designer очень прост в использовании. На левой панели есть элименты которые можно перетащить на ваш виджет. На правой стороне находится панель свойств отображающая все виды редактируемых свойств, выбранного элемента. Так что начните с создания нового виджета.

  1. Выберете "Диалог без кнопок", так как мы не хотим кнопки по умолчанию OK/Cancel.
  2. Нам нужны 'Labels. Labels (этикетки) - это просто тексты которые появляются на вашем виджете, чтобы проинформировать пользователя. Если вы выбираете этикетку, на правой стороне появляются свойства которые вы можете поменять, если вы хотите, такие как стиль шрифта, высота и.т.д. Так что перетащите на ваш виджет 3 этикетки:
    • Одна для заголовка,
    • Одно для надписи "Height"
    • Одна для записи "Width".
  3. Теперь нам нужны LineEdits. Перетащите два из них на виджет. LineEdits это текстовые поля, которые конечный пользователь может заполнить. Нам нужен один LineEdit для Height и один для Width. Здесь мы тоже можем редактировать свойства. Например, почему бы не установить значения по умолчанию, например: 1.00 для каждого. Таким образом, пользователь увидит диалог, где оба значения уже заполнены. Если он удовлетворён, он может прямо нажать кнопку, сохраняя время.
  4. Далее добавим PushButton. Это кнопка, которую конечному пользователю следует нажать после заполнения обоих полей.

Заметьте: мы выбрали очень просто управление. В Qt гораздо больше функций, например, например вы можете использовать Spinboxes вместо LineEdits, и.т.д... Обратите внимание на то что доступно, у вас несомнено появятся другие идеи.

Вот и все, что мы должны сделать в Qt Designer. Последнее, давайте переименуем все наши элементы дав им более простые имена, так что будет легче определять их в нашем сценарии:

Конвертация нашего диалога в python

Теперь сохраните ваш виджет где-нибудь. Он будет сохранен как .ui файл, который мы легко преобразуем в python сценарий с помощью pyuic. В windows, программа pyuic связанна с pyqt (должно быть проверено), на linux вам вероятно нужно будет установить его отдельно в вашем пакетном менеджере (для debian-based систем, это часть пакета pyqt4-dev-tools). Для преобразования, вам необходимо открыть окно терминала (или окно командной строки в windows), переместитесь туда где вы сохранили ваш .ui файл и введите:

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 these 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

На некоторых системах программа называется pyuic4 вместо pyuic. Это просто сконвертирует файл .ui файл в сценарий python. Если мы откроем файл mywidget.py, его содержание очень легко понять:

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

Как вы видете, он обладает очень простым устройством: созданный класс называемый Ui_Dialog, он содержит все элементы интерфейса нашего виджета. Этот класс обладает двумя методами, один для создания виджета, и одни для перевода его содержания, которая является частью механизма Qt для перевода элементов интерфейса. Метод установки(setup method) просто создает один за другим, виджетв так как мы задали их в Qt Designer, и задает их настройки так как мы определили ранее. Затем, весь инструмент будет переведен, и наконец, подключаются слоты (мы поговорим об этом позже).

Теперь мы можем создать новый виджет и использовать этот класс для созданияего интерфейса. Мы уже можем увидеть наш виджет в действии, поместив наш файл mywidget.py в место где FreeCAD сможет найти его (в FreeCAD в паку bin, или в любую Mod поддиректорию), и ввести в интерпретаторе FreeCAD python:

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

И наш диалог появится! Заметим, что наш интерпретатор по прежнему работает, т.е у нас не модальный диалог. Так что, закроем его, мы можем (конечно, помимо того как щелкнуть на иконке закрытия) ввести:

d.hide()

Делаем так чтобы наш диалог делал что-нибудь

Теперь когда мы можем показать или скрыть наш диалог, на осталось добавить последнюю часть:Чтобы оно что-то делало! Если вы немного поиграетесь с Qt designer, вы быстро обнаружите целый раздел под название "сигналы и слоты". В основном, это работает следующим образом: элемент на вашем виджете (в Qt терминалогии, эти элементы сами по себе являются виджетами) может отправить сигнал. Этот сигнал отличаются в зависимости от типа виджета. Например, кнопка может подать сигнал при нажатии, и когда она будет отпущена. Этот сигнал может быть соединен со слотами, которые могут быть специальными функциями других виджетов(например диалог обладающий слотом "закрыть" который можно подключить к сигналу от кнопки закрытия), или это могут быть пользовательские функции. PyQt Reference Documentation список всех qt виджетов, что они делают, какие сигналы могут отправлять и.т.д...

Что мы будем делать здесь, создадим новую функцию , которая создает плоскость основываясь на её длине и ширине, и подключим эту функцию к сигналу нажатия испускаемому нашей кнопкой "Create!" . Так что , давайте начнем с импорта наших модулейr FreeCAD, палагая следующую строку введенной в начале нашего сценария, где мы уже импортировали QtCore и QtGui:

import FreeCAD, Part

Затем , давайте добавим новую функцию в наш класс 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()

Потом, нам нужно сообщить Qt о подключении функции к кнопке, разместив следующую строчку перед QtCore.QMetaObject.connectSlotsByName(Dialog):

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

как вы видете, подключение сигнала pressed() от нашего созданного объекта (кнопка "Create!"), к слоту названому createPlane, который мы только что определили. И это всё!!Теперь,финальный штрих, мы можем добавить маленькую функцию в создание диалога, его легче будет вызвать. Вне класса Ui_Dialog, давайте добавим этот код:

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

Затем , в FreeCAD, нам необходимо сделать только:

import mywidget
myDialog = mywidget.plane()

"Это все ребята"... Теперь вы можете попробовать разные вещи, например как вставить ваш виджет в FreeCAD интерфейс (смотри страницу Отрывки кода ), или создать более продвинутый пользовательский инструмент, используя другие элементы в вашем виджете.

Готовый сценарий

Это полный сценарий, для справки:

# 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