Dialog creation/de: Difference between revisions

From FreeCAD Documentation
No edit summary
No edit summary
Line 39: Line 39:
# Als nächstes können wir einen '''PushButton''' (Druckknopf) hinzufügen. Dies ist die Schaltfläche, die der Endbenutzer drücken muss, nachdem er beide Felder ausgefüllt hat.
# Als nächstes können wir einen '''PushButton''' (Druckknopf) hinzufügen. Dies ist die Schaltfläche, die der Endbenutzer drücken muss, nachdem er beide Felder ausgefüllt hat.


'''Hinweis:''' dass wir hier sehr einfache Bedienelemente gewählt haben. Qt hat viel mehr Optionen, zum Beispiel könnte man '''Spinboxes''' anstelle von '''LineEdits''' verwenden, usw... Schaudir an, was verfügbar ist, erkunde... Du wirst sicher andere Ideen haben.
<div class="mw-translate-fuzzy">
Beachten Sie, dass ich sehr einfache Steuerungen gewählt habe, aber Qt noch viele andere Optionen hat, zum Beispiel könnten Sie Spinboxes statt LineEdits usw. verwenden. Werfen Sie doch einen Blick darauf, was verfügbar ist, vielleicht kommen Ihnen dabei noch weitere Ideen.
</div>


<div class="mw-translate-fuzzy">
<div class="mw-translate-fuzzy">

Revision as of 15:44, 15 November 2020

Einführung

Auf dieser Seite werden wir zeigen, wie man mit Qt Designer, Qt's offiziellem Werkzeug für die Gestaltung von Oberflächen, eine einfache grafische Oberfläche erstellt; der Dialog wird in Python Code umgewandelt und dann innerhalb von FreeCAD verwendet. Wir gehen davon aus, dass der Benutzer weiß, wie man Python allgemein bearbeitet und ausführt.

In diesem Beispiel ist die gesamte Oberfläche in Python definiert. Obwohl dies bei kleinen Schnittstellen möglich ist, empfiehlt es sich bei größeren Schnittstellen, die erstellten .ui Dateien direkt in das Programm zu laden. Siehe Obeflächenerstellung mit UI Dateien für weitere Informationen.

Zwei allgemeine Methoden zur Erstellung von Oberflächen, durch Einfügen der Schnittstelle in die Python Datei oder durch die Verwendung von .ui Dateien.

Gestalten des Dialogs

In CAD Anwendungen ist es sehr wichtig, eine gute UI (Benutzeroberfläche) zu entwerfend. Beinahe alles, das der Benutzer tun wird, wird über ein Teil der Oberfläche passieren: das Lesen von Dialog Kästen, drücken von Knöpfen, die Auswahl zwischen Piktogrammen, usw. Es ist also sehr wichtig, sich genau zu überlegen, was du tun willst, wie der Benutzer sich verhalten soll und wie der Ablauf deiner Aktion aussehen soll.

Ein paar Konzepte sollte man bei der Gestaltung der Oberfläche kennen:

  • Dialoge: Ein modaler Dialog erscheint auf Ihrem Schirm, unterbricht die Handlung des Hauptfensters, zwingt den Benutzer auf den Dialog zu antworten, während ein nichtmodaler Dialog Sie nicht hindert, am Hauptfenster weiter zu arbeiten. In einigen Fällen ist der erste besser, in anderen Fällen nicht.
  • Erkennen, was erforderlich ist und was optional: Stellen Sie sicher, dass der Benutzer weiß, was er tun muss. Etikettieren Sie alles mit der richtigen Beschreibung, verwenden Sie tooltips usw.
  • Die Trennung von Befehlen und Parametern: Das wird gewöhnlich mit Knöpfen und Texteingabefeldern getan. Der Benutzer weiß, dass das Klicken eines Knopfs eine Handlung erzeugen wird, indem er einen Wert innerhalb eines Textfeldes ändert, wird irgendwo ein Parameter geändert. Heutzutage aber wissen Benutzer gewöhnlich gut, was ein Knopf ist, was ein Eingangsfeld usw ist. Das Schnittstellen-Werkzeug Qt, das wir verwenden, ist eines der modernsten Werkzeuge und wir werden uns nicht viel darum sorgen müssen, Dinge verständlich zu machen, da sie bereits in sich selbst sehr klar sein werden.

Nachdem wir gut definiert haben, was wir tun werden, ist es Zeit, den Qt-Designer zu öffnen. Lassen Sie uns einen sehr einfachen Dialog entwerfen:

Wir werden dann mit diesem Dialog in FreeCAD eine schöne rechteckige Ebene erzeugen. Vielleicht finden Sie es nicht sehr nützlich, nette rechteckige Fläche zu produzieren, aber es wird leicht sein, sie später zu ändern, um komplexere Dinge zu tun. Wenn Sie es öffnen, sieht Qt-Designer wie folgt aus:

Erstellen des Dialogs

Qt Designer ist sehr einfach zu benutzen. Auf der linken Leiste hast du Elemente, die auf dein Widget gezogen werden können. Auf der rechten Seite hast du Eigenschaftspaneels, die alle Arten von editierbaren Eigenschaften der ausgewählten Elemente anzeigen. Beginne also mit der Erstellung eines neuen Widgets.

  1. Wähle "Dialog ohne Schaltflächen", da wir die Standardschaltflächen OK/Abbrechen nicht wollen.
  2. Wir brauchen Labels (Beschriftungen). Labels sind einfache Textzeichenfolgen, die auf deinem Widget erscheinen, um den Endbenutzer zu informieren. Wenn du ein Label auswählst, beachte, dass auf der rechten Seite verschiedene Eigenschaften erscheinen, die du ändern kannst, wie z.B.: Schriftstil, Höhe, usw... Lass uns also 3 separate Label auf unser Widget ziehen:
    • Ein Label für den Titel
    • Ein weiteres Label zum Schreiben von "Height"
    • Ein weiteres Label zum Schreiben von "Width"
  3. Wir brauchen jetzt LineEdits (eigentlich 2 davon). Ziehe zwei davon auf das Widget. LineEdits sind Textfelder, die der Endbenutzer ausfüllen kann. Wir brauchen also einen LineEdit für die Höhe und einen für die Breite. Auch hier können wir Eigenschaften bearbeiten. Warum nicht z.B. einen Standardwert setzen, sagen wir z.B.: 1,00 für jedes. Auf diese Weise werden beide Werte bereits ausgefüllt sein, wenn der Benutzer den Dialog sieht. Wenn der Endbenutzer zufrieden ist, kann er direkt auf die Schaltfläche drücken und so wertvolle Zeit sparen.
  4. Als nächstes können wir einen PushButton (Druckknopf) hinzufügen. Dies ist die Schaltfläche, die der Endbenutzer drücken muss, nachdem er beide Felder ausgefüllt hat.

Hinweis: dass wir hier sehr einfache Bedienelemente gewählt haben. Qt hat viel mehr Optionen, zum Beispiel könnte man Spinboxes anstelle von LineEdits verwenden, usw... Schaudir an, was verfügbar ist, erkunde... Du wirst sicher andere Ideen haben.

Das ist soweit alles, was wir im Qt-Designer tun müssen. Eine letzte Sache, wir sollten alle unsere Elemente mit einfacheren Namen bezeichnen, so dass es leichter wird, sie in unseren Skripten zu identifizieren:

Umwandeln unseres Dialogs zu Python

Jetzt werden wir unser Widget irgendwo speichern. Er wird als .ui-Datei gespeichert, die wir einfach mittels pyuic zu einem Python-Skript wandeln werden. Unter Windows ist das pyuic-Programm meistens mit pyqt gebündelt (zu überprüfen), auf Linux werden Sie es wahrscheinlich extra mit Ihrem Paketmanager installieren müssen (auf Debian-beruhenden Systemen, ist es ein Teil des pyqt4-dev-tools Pakets). Für die Konvertierung müssen Sie ein Terminal-Fenster (oder ein Fenster der Eingabeaufforderung unter Windows) öffnen, in welchem Sie zu Ihrer .ui-Datei navigieren und dort dann folgendes eingeben:

pyuic mywidget.ui > mywidget.py

Unter Windows ist pyuic.py in "C:\Python27\Lib\site-packages\PyQt4\uic\"zu finden. Zu Konvertierung legen wir die Batch-Datei "compQt4.bat" an:

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

In der DOS-Konsole tippen Sie (ohne Dateierweiterung):

compQt4 myUiFile

Unter Linux: to do

Nachdem sich FreeCAD nach v0.13 zunehmend von PyQt zugunsten von PySide entfernt hat (wählen Sie Ihre building PySide-Installation), müssen Sie zur Erstellung der Datei basierend auf PySide folgendes angeben:

pyside-uic mywidget.ui -o mywidget.py

Unter Windows ist uic.py in "C:\Python27\Lib\site-packages\PySide\scripts\" zu finden. Erstellen Sie eine Batch-Datei namens "compSide.bat":

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

In der DOS-Konsole tippen Sie (ohne Dateierweiterung):

compSide myUiFile

Unter Linux: to do

Auf einigen Systemen wird das Programm pyuic4 statt pyuic heißen. Das wird die .ui-Datei in ein Python-Skript umwandeln. Wenn wir die mywidget.py-Datei öffnen, ist der Inhalt sehr leicht zu verstehen:

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

Wie Sie sehen, hat es eine sehr einfache Struktur: eine Klasse genannt Ui_Dialog wird erstellt, die die Elemente der Benutzeroberfläche unseres Widgets speichert. Diese Klasse hat zwei Methoden, eine für die Einrichtung des Widgets und eine für die Übersetzung ihres Inhalts, was ein Teil des allgemeinen Qt-Mechanismus für die Übersetzung von Interface-Elementen ist. Das Setup-Verfahren erzeugt einfach eins nach dem anderen die Widgets, wie wir sie in Qt-Designer definiert haben und setzt ihre Optionen, die wir ebenfalls gewählt haben. Dann wird die ganze Schnittstelle schließlich übersetzt, die SLOTS werden verbunden (wir werden darüber später sprechen).

Wir können jetzt ein neues Widget erstellen und diese Klasse verwenden, um seine Schnittstelle zu schaffen. Wir können bereits unser Widget in Aktion sehen, indem wir unsere mywidget.py Datei an einem Ort speichern, wo FreeCAD es findet (im FreeCAD bin-Verzeichnis, oder in einem der Mod-Unterverzeichnisse), und dann im FreeCAD Python-Interpreter eintippen:

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

Und unser Dialog wird erscheinen! Beachten Sie, dass unser Python-Interpreter immer noch arbeitet, wir haben einen nichtmodalen Dialog. Um es zu abzuschließen, können wir (abgesehen von einem Klick auf das Schließen-Symbol, natürlich) eingeben:

d.hide()

Lassen wir unseren Dialog etwas tun

Wo wir jetzt unseren Dialog schon anzeigen und ausblenden können, gibt es nur eines zu tun: Es muss auch etwas ausführen! Wenn Sie ein bisschen mit dem Qt-Designer spielen, entdecken Sie schnell eine ganze Abteilung genannt "Signale und Slots". Grundsätzlich funktioniert es so: Elemente auf Ihren Widgets (in Qt-Terminologie, diese Elemente sind selbst Widgets) können Signale senden. Diese Signale unterscheiden sich je nach Widget-Typ. Zum Beispiel kann eine Taste ein Signal senden, wenn sie gedrückt wird und wenn sie losgelassen wird. Diese Signale können mit Slots verbunden werden, die spezielle Funktionen von anderen Widgets (z. B. einen Dialog, einen "close"-Slot, auf den Sie das Signal von einem Schließen-Button verbinden) oder benutzerdefinierte Funktionen sein können. Die Seite PyQt Reference Documentation listet alle Qt-Widgets, was sie tun können, welche Signale sie senden können, etc.

Was wir hier tun werden, ist eine neue Funktion zu erstellen, die eine Ebene erzeugt, beruhend auf Höhe und Breite, und in Verbindung steht diese Funktion mit dem "gedrückt"-Signal, das unser "Create"-Knopf abgibt. Also wollen wir mit dem Importieren unserer FreeCAD Module beginnen, indem Sie die folgende Zeile am Anfang des Skripts, wo wir bereits QtCore und QtGui importieren, einfügen:

import FreeCAD, Part

Jetzt werden wir eine neue Funktion in unsere Ui_Dialog-Klasse einfügen:

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

Nun müssen wir Qt klarmachen, dass der Knopf mit der Funktion verbunden werden muss. Dazu geben wir die folgende Zeile ein, aber VOR der Zeile QtCore.QMetaObject.connectSlotsByName(Dialog):

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

Dies, wie Sie sehen, verbindet das pressed()-Signal unseres create-Objekts (den "Create!" button), zu einem Slot mit Namen createPlane, den wir gerade definiert haben. Das ist alles! Jetzt, als eine Feinschliff, können wir eine kleine Funktion hinzufügen, um den Dialog zu erzeugen, dadurch wird der Aufruf erleichtert. Außerhalb der Ui_Dialog Klasse, wollen wir diesen Code hinzufügen:

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

(Python-Erinnerung: Die __init__-Methode einer Klasse wird automatisch ausgeführt, wenn ein neues Objekt erzeugt wird!)

Dann brauchen wir in FreeCAD (Pythonkonsole) nur noch folgendes zu tun:

import mywidget
myDialog = mywidget.plane()

Das ist alles, Leute ... Jetzt können Sie alle möglichen Dinge versuchen, wie zum Beispiel das Einfügen Ihres Widgets in die FreeCAD-Oberfläche (siehe Code snippets/de-Seite) oder erstellen Sie weitere, fortgeschrittene benutzerdefinierte Tools, durch die Verwendung anderer Elemente auf Ihrem Widget.

Das komplette Script

Dies ist das komplette Script, nur als Referenz:

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

Erstellung eines Dialogs mit Knöpfen