Dialog creation/pl: Difference between revisions

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


{{Docnav/pl
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.
|[[Interface_creation/pl|Tworzenie interfejsu]]
|[[License/pl|Licencja]]
}}


{{TOCright}}
== 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.


<span id="Introduction"></span>
There are a couple of concepts to know when designing interface:
==Wprowadzenie==
* [http://en.wikipedia.org/wiki/Modal_window 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.


Na tej stronie pokażemy, jak zbudować prosty interfejs graficzny za pomocą [http://qt-project.org/doc/qt-4.8/designer-manual.html Qt Designer], oficjalnego narzędzia Qt do projektowania interfejsów. Przekonwertujemy okno dialogowe na kod [[Python/pl|Python]], a następnie będzie używane wewnątrz FreeCAD. Zakładamy, że użytkownik wie, jak edytować i uruchamiać [[Python/pl|Python]].
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:

W tym przykładzie cały interfejs jest zdefiniowany w środowisku [[Python|Python]]. Chociaż jest to możliwe w przypadku małych interfejsów, w przypadku większych interfejsów zaleca się ładowanie utworzonych plików {{FileName|.ui}} bezpośrednio do programu.

[[File:FreeCAD_creating_interfaces.svg|600px]]
{{Caption|Dwie ogólne metody tworzenia interfejsów, poprzez włączenie interfejsu do pliku Python lub poprzez użycie plików {{incode|.ui}}.}}

<span id="Designing_the_dialog"></span>
==Projektujemy okno dialogowe==

W aplikacjach CAD zaprojektowanie dobrego interfejsu użytkownika ''(UI)'' jest bardzo ważne. Prawie wszystko, co użytkownik będzie robił, będzie odbywało się za pośrednictwem jakiegoś elementu interfejsu: czytanie okien dialogowych, naciskanie przycisków, wybieranie między ikonami itp. Dlatego bardzo ważne jest, aby dokładnie przemyśleć co chcesz zrobić, jak chcesz aby użytkownik postępował i jaki będzie przepływ pracy.

Istnieje kilka pojęć, które należy znać podczas projektowania interfejsu:
* [http://en.wikipedia.org/wiki/Modal_window Modalne/niemodalne okna dialogowe]: Modalne okno dialogowe pojawia się przed ekranem, zatrzymując działanie głównego okna, zmuszając użytkownika do odpowiedzi na okno dialogowe, podczas gdy niemodalne okno dialogowe nie przerywa pracy w głównym oknie. W niektórych przypadkach pierwsze rozwiązanie jest lepsze, w innych nie.
* Określenie, co jest wymagane, a co opcjonalne: Upewnij się, że użytkownik wie, co musi zrobić. Oznacz wszystko odpowiednim opisem, użyj podpowiedzi itp.
* Oddzielanie poleceń od parametrów: Zazwyczaj robi się to za pomocą przycisków i pól wprowadzania tekstu. Użytkownik wie, że kliknięcie przycisku spowoduje akcję, podczas gdy zmiana wartości w polu tekstowym zmieni gdzieś parametr. Jednak w dzisiejszych czasach użytkownicy zwykle dobrze wiedzą, co jest przyciskiem, co jest polem wejściowym itp. Zestaw narzędzi interfejsu, którego używamy, Qt, jest najnowocześniejszym zestawem narzędzi i nie będziemy musieli się zbytnio martwić o wyjaśnianie rzeczy, ponieważ będą one już bardzo zrozumiałe same w sobie.

Tak więc, teraz, gdy dobrze zdefiniowaliśmy, co będziemy robić, nadszedł czas, aby otworzyć projektanta QT. Zaprojektujmy bardzo proste okno dialogowe, takie jak to:


[[Image:Qttestdialog.jpg]]
[[Image:Qttestdialog.jpg]]


Następnie użyjemy tego okna dialogowego w programie FreeCAD, aby utworzyć ładną prostokątną płaszczyznę. Może się okazać, że nie jest to zbyt przydatne do tworzenia ładnych prostokątnych płaszczyzn, ale łatwo będzie je później zmienić, aby robić bardziej złożone rzeczy. Po otwarciu Qt Designer wygląda następująco:
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:


[[Image:Qtdesigner-screenshot.jpg]]
[[Image:Qtdesigner-screenshot.jpg]]


==Tworzymy okno dialogowe==
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.
Qt Designer jest bardzo prosty w użyciu. Na lewym pasku znajdują się elementy, które można przeciągnąć na widżet. Po prawej stronie znajdują się panele właściwości wyświetlające wszystkie rodzaje edytowalnych właściwości wybranych elementów. Zacznijmy więc od utworzenia nowego widżetu.

# Wybieramy "Dialog bez przycisków", ponieważ nie chcemy domyślnych przycisków {{KEY|OK}}/{{KEY|Cancel}}.
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.
# Potrzebujemy '''Etykiety'''. Etykiety to proste ciągi tekstowe, które pojawiają się na widżecie, aby poinformować użytkownika końcowego. Jeśli wybierzesz etykietę, zauważysz, że po prawej stronie pojawi się kilka właściwości, które możesz modyfikować, takich jak: styl czcionki, wysokość itp. Przeciągnijmy więc 3 oddzielne etykiety na nasz widżet:
#* Jedna etykieta dla tytułu
#* Kolejna etykieta do napisania "'''Wysokość'''"
#* Kolejna etykieta do napisania "'''Szerokość'''"
# Potrzebujemy teraz LineEdits ''(a właściwie 2 z nich)''. Przeciągnij dwa z nich na widżet. '''LineEdits''' to pola tekstowe, które użytkownik końcowy może wypełnić. Potrzebujemy więc jednego LineEdit dla "Wysokość" i jednego dla "Szerokość". Tutaj również możemy edytować właściwości. Na przykład, dlaczego nie ustawić wartości domyślnej, powiedzmy na przykład: 1.00 dla każdego. W ten sposób, gdy użytkownik zobaczy okno dialogowe, obie wartości będą już wypełnione. Jeśli użytkownik będzie zadowolony, może bezpośrednio nacisnąć przycisk, oszczędzając cenny czas.
# Następnie dodajmy przycisk '''PushButton'''. Jest to przycisk, który użytkownik końcowy będzie musiał nacisnąć po wypełnieniu obu pól.


'''Uwaga:''' wybraliśmy tutaj bardzo proste kontrolki. Qt ma o wiele więcej opcji, na przykład można użyć '''Spinboxes''' zamiast '''LineEdits''' itp. Przyjrzyj się temu, co jest dostępne, zbadaj... na pewno będziesz miał inne pomysły.
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.


To wszystko, co musimy zrobić w Qt Designer. Na koniec zmieńmy nazwy wszystkich elementów na prostsze, aby łatwiej było je zidentyfikować w naszych skryptach:
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:


[[Image:Qtpropeditor.jpg]]
[[Image:Qtpropeditor.jpg]]


<span id="Converting_our_dialog_to_python"></span>
== Converting our dialog to python ==
==Konwersja naszego okna dialogowego do środowiska 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:
Teraz zapiszmy gdzieś nasz widget. Zostanie on zapisany jako plik .ui, który z łatwością przekonwertujemy na skrypt Pythona za pomocą pyuic. Na Windowsie program pyuic jest dołączony do pyqt ''(do sprawdzenia)'', na linuksie prawdopodobnie będziesz musiał zainstalować go osobno z menedżera pakietów ''(na systemach opartych na debianie jest on częścią pakietu pyqt4-dev-tools)''. Aby dokonać konwersji, należy otworzyć okno terminala (lub okno wiersza polecenia w systemie Windows), przejść do miejsca, w którym zapisano plik .ui i wydać polecenie:
{{Code|code=
{{Code|code=
pyuic mywidget.ui > mywidget.py
pyuic mywidget.ui > mywidget.py
}}
}}
In Windows pyuic.py is located in "C:\Python27\Lib\site-packages\PyQt4\uic\pyuic.py"
W systemie Windows pyuic.py znajduje się w "C:\Python27\Lib\site-packages\PyQt4\uic\pyuic.py".
For conversion create a batch file called "compQt4.bat:
Do konwersji należy utworzyć plik wsadowy o nazwie "compQt4.bat":
{{Code|code=
{{Code|code=
@"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
}}
}}
W konsoli DOS wpisz bez rozszerzenia
In the DOS console type without extension
{{Code|code=
{{Code|code=
compQt4 myUiFile
compQt4 myUiFile
}}
}}


W systemie macOS można pobrać odpowiednią wersję ''(tę samą, która jest używana wewnętrznie w FreeCAD 0.19)'' QT i Pyside za pomocą następujących poleceń ''(wymagany program)'':
Into Linux : to do
{{Code|code=
python3 -m pip install pyqt5
python3 -m pip install pySide2
}}
Spowoduje to zainstalowanie uic w folderze "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/uic", a Designer w "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/Designer.app".
Dla wygody można utworzyć link do uic w /usr/local/bin, aby móc go wywołać po prostu za pomocą uic -g python ... zamiast wpisywania całej ścieżki programu, oraz link do Designera, aby pobrać go w folderze Aplikacje na komputerze Mac za pomocą:
{{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
}}

W Linuksie: do zrobienia.


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:
Ponieważ FreeCAD stopniowo odchodził od PyQt po wersji 0.13, na rzecz [http://qt-project.org/wiki/PySide PySide] ''(Wybierz instalację PySide [http://pyside.readthedocs.org/en/latest/building/ budowanie PySide])'', aby plik był oparty na PySide, musisz teraz użyć:


{{Code|code=
{{Code|code=
pyside-uic mywidget.ui -o mywidget.py
pyside-uic mywidget.ui -o mywidget.py
}}
}}
In Windows uic.py are located in "C:\Python27\Lib\site-packages\PySide\scripts\uic.py"
W systemie Windows plik uic.py znajduje się w katalogu "C:\Python27\Lib\site-packages\PySide\scripts\uic.py".
For create batch file "compSide.bat":
Aby utworzyć plik wsadowy "compSide.bat":
{{Code|code=
{{Code|code=
@"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
}}
}}
W konsoli DOS wpisz bez rozszerzenia:
In the DOS console type without extension
{{Code|code=
{{Code|code=
compSide myUiFile
compSide myUiFile
}}
}}
W Linuksie: do zrobienia.
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:
W niektórych systemach program nazywa się pyuic4 zamiast pyuic. Spowoduje to po prostu konwersję pliku .ui na skrypt Pythona. Jeśli otworzymy plik mywidget.py, jego zawartość jest bardzo przejrzysta:
{{Code|code=
{{Code|code=
from PySide import QtCore, QtGui
from PySide import QtCore, QtGui
Line 85: Line 120:
...
...
}}
}}
Jak widać, ma on bardzo prostą strukturę: tworzona jest klasa o nazwie Ui_Dialog, która przechowuje elementy interfejsu naszego widżetu. Ta klasa ma dwie metody, jedną do konfiguracji widżetu, a drugą do tłumaczenia jego zawartości, co jest częścią ogólnego mechanizmu Qt do tłumaczenia elementów interfejsu. Metoda konfiguracji po prostu tworzy, jeden po drugim, widżety tak, jak zdefiniowaliśmy je w Qt Designer i ustawia ich opcje tak, jak zdecydowaliśmy wcześniej. Następnie cały interfejs zostaje przetłumaczony, a na koniec sloty zostają połączone ''(o tym powiem później)''.
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:
Możemy teraz utworzyć nowy widżet i użyć tej klasy do stworzenia jego interfejsu. Możemy już zobaczyć nasz widżet w akcji, umieszczając nasz plik mywidget.py w miejscu, w którym FreeCAD go znajdzie (w katalogu bin FreeCAD lub w dowolnym z podkatalogów Mod), a następnie w interpreterze python FreeCAD wydać polecenie:
{{Code|code=
{{Code|code=
from PySide import QtGui
from PySide import QtGui
Line 96: Line 131:
d.show()
d.show()
}}
}}
I pojawi się nasze okno dialogowe! Zauważ, że nasz interpreter Python nadal działa, mamy niemodalne okno dialogowe. Tak więc, aby je zamknąć, możemy ''(oprócz kliknięcia ikony zamknięcia, oczywiście)'' wydać polecenie:
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:
{{Code|code=
{{Code|code=
d.hide()
d.hide()
}}
}}


== Sprawiamy, by nasze okno dialogowe robiło coś ==
== Making our dialog do something ==
Teraz, gdy możemy pokazywać i ukrywać nasze okno dialogowe, musimy tylko dodać ostatnią część: Sprawić, by coś robiło! Jeśli pobawisz się trochę Qt Designerem, szybko odkryjesz całą sekcję o nazwie "sygnały i sloty". Zasadniczo działa to w następujący sposób: elementy na widżetach ''(w terminologii Qt te elementy są same w sobie widżetami)'' mogą wysyłać sygnały. Sygnały te różnią się w zależności od typu widżetu. Na przykład przycisk może wysyłać sygnał po naciśnięciu i zwolnieniu. Sygnały te mogą być podłączone do slotów, które mogą być specjalnymi funkcjami innych widżetów ''(na przykład okno dialogowe ma slot "zamknij", do którego można podłączyć sygnał z przycisku zamykania)'' lub mogą być funkcjami niestandardowymi. Dokumentacja [http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/classes.html PyQt Reference] zawiera listę wszystkich widżetów qt, co mogą robić, jakie sygnały mogą wysyłać itd.
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 [http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/classes.html PyQt Reference Documentation] lists all the qt widgets, what they can do, what signals they can send, etc...


To, co tutaj zrobimy, to utworzenie nowej funkcji, która utworzy płaszczyznę na podstawie wysokości i szerokości oraz podłączenie tej funkcji do sygnału naciśnięcia emitowanego przez nasz przycisk "Utwórz!". Zacznijmy więc od zaimportowania naszych modułów FreeCAD, umieszczając następującą linię na górze skryptu, gdzie już zaimportowaliśmy QtCore i QtGui:
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:
{{Code|code=
{{Code|code=
import FreeCAD, Part
import FreeCAD, Part
}}
}}
Then, let's add a new function to our Ui_Dialog class:
Następnie dodajmy nową funkcję do naszej klasy Ui_Dialog:
{{Code|code=
{{Code|code=
def createPlane(self):
def createPlane(self):
Line 129: Line 164:
self.hide()
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):
Następnie musimy poinformować Qt, aby podłączył przycisk do funkcji, umieszczając następującą linię tuż przed QtCore.QMetaObject.connectSlotsByName(Dialog):
{{Code|code=
{{Code|code=
QtCore.QObject.connect(self.create,QtCore.SIGNAL("pressed()"),self.createPlane)
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:
To, jak widać, łączy sygnał pressed() naszego obiektu create ''(przycisk "Create!")'' ze slotem o nazwie createPlane, który właśnie zdefiniowaliśmy. To wszystko! Teraz, jako ostatni akcent, możemy dodać małą funkcję do tworzenia okna dialogowego, która będzie łatwiejsza do wywołania. Dodajmy ten kod poza klasą Ui_Dialog:
{{Code|code=
{{Code|code=
class plane():
class plane():
Line 142: Line 177:
self.d.show()
self.d.show()
}}
}}
''(Przypomnienie Pythona: metoda __init__ klasy jest automatycznie wykonywana za każdym razem, gdy tworzony jest nowy obiekt)''!
(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:
Następnie, z FreeCAD, musimy tylko zrobić:
{{Code|code=
{{Code|code=
import mywidget
import mywidget
myDialog = mywidget.plane()
myDialog = mywidget.plane()
}}
}}
To wszystko... Teraz możesz spróbować różnych rzeczy, takich jak na przykład wstawianie widżetu do interfejsu FreeCAD ''(zobacz stronę [[Code_snippets/pl|wycinki kodu]])'' lub tworzenie znacznie bardziej zaawansowanych narzędzi niestandardowych, używając innych elementów na widżecie.
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 ==
== Kompletny skrypt ==
To jest kompletny skrypt, dla porównania:
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 226:


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 251:


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.


<span id="More_examples"></span>
Download associated icons (click right "Copy the image below ...)"
==Więcej przykładów==


* [[Dialog_creation_with_various_widgets/pl|Tworzenie dialogów z różnymi widżetami]] with {{incode|QPushButton}}, {{incode|QLineEdit}}, {{incode|QCheckBox}}, {{incode|QRadioButton}}, and others.
[[File:Icone01.png]] [[File:Icone02.png]] [[File:Icone03.png]]
* [[Dialog_creation_reading_and_writing_files/pl|Tworzenie dialogów odczyt i zapis plików]] with {{incode|QFileDialog}}.
* [[Dialog_creation_setting_colors/pl|Tworzenie okna dialogowego ustawienie kolorów]] with {{incode|QColorDialog}}.
* [[Dialog_creation_image_and_animated_GIF/pl|Tworzenie dialogu grafika i animowany GIF]] with {{incode|QLabel}} and {{incode|QMovie}}.
* [[PySide_usage_snippets/pl|PySide przydatne wycinki]].
* [[Qt_Example/pl|Przykłady Qt]]


<span id="Relevant_links"></span>
{{Code|code=
==Istotne odnośniki internetowe==
# -*- coding: utf-8 -*-


* [[Manual:Creating interface tools/pl|Podręcznik:Tworzenie narzędzi interfejsu]]
from PySide import QtCore, QtGui


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


{{Docnav/pl
try:
|[[Interface_creation/pl|Tworzenie interfejsu]]
_encoding = QtGui.QApplication.UnicodeUTF8
|[[License/pl|Licencja]]
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==
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:
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)

}}

==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]]

{{docnav|[[Line drawing function|Line drawing function]]|[[Licence|Licence]]}}

{{Userdocnavi}}

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

[[Category:Python Code]]

[[Category:Developer]]

[[Category:Developer Documentation]]


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

Latest revision as of 06:30, 6 April 2024

Wprowadzenie

Na tej stronie pokażemy, jak zbudować prosty interfejs graficzny za pomocą Qt Designer, oficjalnego narzędzia Qt do projektowania interfejsów. Przekonwertujemy okno dialogowe na kod Python, a następnie będzie używane wewnątrz FreeCAD. Zakładamy, że użytkownik wie, jak edytować i uruchamiać Python.

W tym przykładzie cały interfejs jest zdefiniowany w środowisku Python. Chociaż jest to możliwe w przypadku małych interfejsów, w przypadku większych interfejsów zaleca się ładowanie utworzonych plików .ui bezpośrednio do programu.

Dwie ogólne metody tworzenia interfejsów, poprzez włączenie interfejsu do pliku Python lub poprzez użycie plików .ui.

Projektujemy okno dialogowe

W aplikacjach CAD zaprojektowanie dobrego interfejsu użytkownika (UI) jest bardzo ważne. Prawie wszystko, co użytkownik będzie robił, będzie odbywało się za pośrednictwem jakiegoś elementu interfejsu: czytanie okien dialogowych, naciskanie przycisków, wybieranie między ikonami itp. Dlatego bardzo ważne jest, aby dokładnie przemyśleć co chcesz zrobić, jak chcesz aby użytkownik postępował i jaki będzie przepływ pracy.

Istnieje kilka pojęć, które należy znać podczas projektowania interfejsu:

  • Modalne/niemodalne okna dialogowe: Modalne okno dialogowe pojawia się przed ekranem, zatrzymując działanie głównego okna, zmuszając użytkownika do odpowiedzi na okno dialogowe, podczas gdy niemodalne okno dialogowe nie przerywa pracy w głównym oknie. W niektórych przypadkach pierwsze rozwiązanie jest lepsze, w innych nie.
  • Określenie, co jest wymagane, a co opcjonalne: Upewnij się, że użytkownik wie, co musi zrobić. Oznacz wszystko odpowiednim opisem, użyj podpowiedzi itp.
  • Oddzielanie poleceń od parametrów: Zazwyczaj robi się to za pomocą przycisków i pól wprowadzania tekstu. Użytkownik wie, że kliknięcie przycisku spowoduje akcję, podczas gdy zmiana wartości w polu tekstowym zmieni gdzieś parametr. Jednak w dzisiejszych czasach użytkownicy zwykle dobrze wiedzą, co jest przyciskiem, co jest polem wejściowym itp. Zestaw narzędzi interfejsu, którego używamy, Qt, jest najnowocześniejszym zestawem narzędzi i nie będziemy musieli się zbytnio martwić o wyjaśnianie rzeczy, ponieważ będą one już bardzo zrozumiałe same w sobie.

Tak więc, teraz, gdy dobrze zdefiniowaliśmy, co będziemy robić, nadszedł czas, aby otworzyć projektanta QT. Zaprojektujmy bardzo proste okno dialogowe, takie jak to:

Następnie użyjemy tego okna dialogowego w programie FreeCAD, aby utworzyć ładną prostokątną płaszczyznę. Może się okazać, że nie jest to zbyt przydatne do tworzenia ładnych prostokątnych płaszczyzn, ale łatwo będzie je później zmienić, aby robić bardziej złożone rzeczy. Po otwarciu Qt Designer wygląda następująco:

Tworzymy okno dialogowe

Qt Designer jest bardzo prosty w użyciu. Na lewym pasku znajdują się elementy, które można przeciągnąć na widżet. Po prawej stronie znajdują się panele właściwości wyświetlające wszystkie rodzaje edytowalnych właściwości wybranych elementów. Zacznijmy więc od utworzenia nowego widżetu.

  1. Wybieramy "Dialog bez przycisków", ponieważ nie chcemy domyślnych przycisków OK/Cancel.
  2. Potrzebujemy Etykiety. Etykiety to proste ciągi tekstowe, które pojawiają się na widżecie, aby poinformować użytkownika końcowego. Jeśli wybierzesz etykietę, zauważysz, że po prawej stronie pojawi się kilka właściwości, które możesz modyfikować, takich jak: styl czcionki, wysokość itp. Przeciągnijmy więc 3 oddzielne etykiety na nasz widżet:
    • Jedna etykieta dla tytułu
    • Kolejna etykieta do napisania "Wysokość"
    • Kolejna etykieta do napisania "Szerokość"
  3. Potrzebujemy teraz LineEdits (a właściwie 2 z nich). Przeciągnij dwa z nich na widżet. LineEdits to pola tekstowe, które użytkownik końcowy może wypełnić. Potrzebujemy więc jednego LineEdit dla "Wysokość" i jednego dla "Szerokość". Tutaj również możemy edytować właściwości. Na przykład, dlaczego nie ustawić wartości domyślnej, powiedzmy na przykład: 1.00 dla każdego. W ten sposób, gdy użytkownik zobaczy okno dialogowe, obie wartości będą już wypełnione. Jeśli użytkownik będzie zadowolony, może bezpośrednio nacisnąć przycisk, oszczędzając cenny czas.
  4. Następnie dodajmy przycisk PushButton. Jest to przycisk, który użytkownik końcowy będzie musiał nacisnąć po wypełnieniu obu pól.

Uwaga: wybraliśmy tutaj bardzo proste kontrolki. Qt ma o wiele więcej opcji, na przykład można użyć Spinboxes zamiast LineEdits itp. Przyjrzyj się temu, co jest dostępne, zbadaj... na pewno będziesz miał inne pomysły.

To wszystko, co musimy zrobić w Qt Designer. Na koniec zmieńmy nazwy wszystkich elementów na prostsze, aby łatwiej było je zidentyfikować w naszych skryptach:

Konwersja naszego okna dialogowego do środowiska Python

Teraz zapiszmy gdzieś nasz widget. Zostanie on zapisany jako plik .ui, który z łatwością przekonwertujemy na skrypt Pythona za pomocą pyuic. Na Windowsie program pyuic jest dołączony do pyqt (do sprawdzenia), na linuksie prawdopodobnie będziesz musiał zainstalować go osobno z menedżera pakietów (na systemach opartych na debianie jest on częścią pakietu pyqt4-dev-tools). Aby dokonać konwersji, należy otworzyć okno terminala (lub okno wiersza polecenia w systemie Windows), przejść do miejsca, w którym zapisano plik .ui i wydać polecenie:

pyuic mywidget.ui > mywidget.py

W systemie Windows pyuic.py znajduje się w "C:\Python27\Lib\site-packages\PyQt4\uic\pyuic.py". Do konwersji należy utworzyć plik wsadowy o nazwie "compQt4.bat":

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

W konsoli DOS wpisz bez rozszerzenia

compQt4 myUiFile

W systemie macOS można pobrać odpowiednią wersję (tę samą, która jest używana wewnętrznie w FreeCAD 0.19) QT i Pyside za pomocą następujących poleceń (wymagany program):

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

Spowoduje to zainstalowanie uic w folderze "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/uic", a Designer w "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PySide2/Designer.app". Dla wygody można utworzyć link do uic w /usr/local/bin, aby móc go wywołać po prostu za pomocą uic -g python ... zamiast wpisywania całej ścieżki programu, oraz link do Designera, aby pobrać go w folderze Aplikacje na komputerze Mac za pomocą:

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

W Linuksie: do zrobienia.

Ponieważ FreeCAD stopniowo odchodził od PyQt po wersji 0.13, na rzecz PySide (Wybierz instalację PySide budowanie PySide), aby plik był oparty na PySide, musisz teraz użyć:

pyside-uic mywidget.ui -o mywidget.py

W systemie Windows plik uic.py znajduje się w katalogu "C:\Python27\Lib\site-packages\PySide\scripts\uic.py". Aby utworzyć plik wsadowy "compSide.bat":

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

W konsoli DOS wpisz bez rozszerzenia:

compSide myUiFile

W Linuksie: do zrobienia.

W niektórych systemach program nazywa się pyuic4 zamiast pyuic. Spowoduje to po prostu konwersję pliku .ui na skrypt Pythona. Jeśli otworzymy plik mywidget.py, jego zawartość jest bardzo przejrzysta:

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

Jak widać, ma on bardzo prostą strukturę: tworzona jest klasa o nazwie Ui_Dialog, która przechowuje elementy interfejsu naszego widżetu. Ta klasa ma dwie metody, jedną do konfiguracji widżetu, a drugą do tłumaczenia jego zawartości, co jest częścią ogólnego mechanizmu Qt do tłumaczenia elementów interfejsu. Metoda konfiguracji po prostu tworzy, jeden po drugim, widżety tak, jak zdefiniowaliśmy je w Qt Designer i ustawia ich opcje tak, jak zdecydowaliśmy wcześniej. Następnie cały interfejs zostaje przetłumaczony, a na koniec sloty zostają połączone (o tym powiem później).

Możemy teraz utworzyć nowy widżet i użyć tej klasy do stworzenia jego interfejsu. Możemy już zobaczyć nasz widżet w akcji, umieszczając nasz plik mywidget.py w miejscu, w którym FreeCAD go znajdzie (w katalogu bin FreeCAD lub w dowolnym z podkatalogów Mod), a następnie w interpreterze python FreeCAD wydać polecenie:

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

I pojawi się nasze okno dialogowe! Zauważ, że nasz interpreter Python nadal działa, mamy niemodalne okno dialogowe. Tak więc, aby je zamknąć, możemy (oprócz kliknięcia ikony zamknięcia, oczywiście) wydać polecenie:

d.hide()

Sprawiamy, by nasze okno dialogowe robiło coś

Teraz, gdy możemy pokazywać i ukrywać nasze okno dialogowe, musimy tylko dodać ostatnią część: Sprawić, by coś robiło! Jeśli pobawisz się trochę Qt Designerem, szybko odkryjesz całą sekcję o nazwie "sygnały i sloty". Zasadniczo działa to w następujący sposób: elementy na widżetach (w terminologii Qt te elementy są same w sobie widżetami) mogą wysyłać sygnały. Sygnały te różnią się w zależności od typu widżetu. Na przykład przycisk może wysyłać sygnał po naciśnięciu i zwolnieniu. Sygnały te mogą być podłączone do slotów, które mogą być specjalnymi funkcjami innych widżetów (na przykład okno dialogowe ma slot "zamknij", do którego można podłączyć sygnał z przycisku zamykania) lub mogą być funkcjami niestandardowymi. Dokumentacja PyQt Reference zawiera listę wszystkich widżetów qt, co mogą robić, jakie sygnały mogą wysyłać itd.

To, co tutaj zrobimy, to utworzenie nowej funkcji, która utworzy płaszczyznę na podstawie wysokości i szerokości oraz podłączenie tej funkcji do sygnału naciśnięcia emitowanego przez nasz przycisk "Utwórz!". Zacznijmy więc od zaimportowania naszych modułów FreeCAD, umieszczając następującą linię na górze skryptu, gdzie już zaimportowaliśmy QtCore i QtGui:

import FreeCAD, Part

Następnie dodajmy nową funkcję do naszej klasy 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()

Następnie musimy poinformować Qt, aby podłączył przycisk do funkcji, umieszczając następującą linię tuż przed QtCore.QMetaObject.connectSlotsByName(Dialog):

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

To, jak widać, łączy sygnał pressed() naszego obiektu create (przycisk "Create!") ze slotem o nazwie createPlane, który właśnie zdefiniowaliśmy. To wszystko! Teraz, jako ostatni akcent, możemy dodać małą funkcję do tworzenia okna dialogowego, która będzie łatwiejsza do wywołania. Dodajmy ten kod poza klasą Ui_Dialog:

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

(Przypomnienie Pythona: metoda __init__ klasy jest automatycznie wykonywana za każdym razem, gdy tworzony jest nowy obiekt)! Następnie, z FreeCAD, musimy tylko zrobić:

import mywidget
myDialog = mywidget.plane()

To wszystko... Teraz możesz spróbować różnych rzeczy, takich jak na przykład wstawianie widżetu do interfejsu FreeCAD (zobacz stronę wycinki kodu) lub tworzenie znacznie bardziej zaawansowanych narzędzi niestandardowych, używając innych elementów na widżecie.

Kompletny skrypt

To jest kompletny skrypt, dla porównania:

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

Więcej przykładów

Istotne odnośniki internetowe