QtVCP ist eine Infrastruktur zum Erstellen von benutzerdefinierten CNC-Bildschirmen oder Bedienfeldern für LinuxCNC.
Es zeigt eine .ui
-Datei an, die mit dem Qt Designer-Bildschirmeditor erstellt wurde, und kombiniert diese mit Python-Programmierung, um einen GUI-Bildschirm für den Betrieb einer CNC-Maschine zu erstellen.
QtVCP ist vollständig anpassbar: Sie können verschiedene Schaltflächen und Status-LEDs usw. hinzufügen oder Python-Code für eine noch feinere Anpassung einfügen.
1. Schaukasten
Einige Beispiele für mit QtVCP erstellte Bildschirme und virtuelle Bedienfelder:







2. Übersicht
Zwei Dateien werden, einzeln oder in Kombination, verwendet, um Anpassungen vorzunehmen:
-
Eine UI-Datei, bei der es sich um eine XML-Datei handelt, die mit dem grafischen Editor Qt Designer erstellt wurde.
-
Eine Handler-Datei, die eine Textdatei mit Python-Code ist.
Normalerweise verwendet QtVCP die standardmäßige UI- und Handler-Datei, aber Sie können QtVCP so einstellen, dass es "lokale" UI- und Handler-Dateien verwendet.
Eine lokale Datei ist eine Datei, die sich im Konfigurationsordner befindet, der den Rest der Anforderungen des Rechners definiert.
Man ist nicht darauf beschränkt, ein benutzerdefiniertes Panel auf der rechten Seite oder eine benutzerdefinierte Registerkarte hinzuzufügen, da QtVCP den Qt Designer (den Editor) und PyQt5 (das Widget-Toolkit) nutzt.
QtVCP hat einige spezielle LinuxCNC Widgets und Aktionen hinzugefügt.
Es gibt spezielle Widgets, um Widgets von Drittanbietern mit HAL-Pins zu verbinden.
Es ist möglich, Widget-Antworten zu erstellen, indem man Signale mit Python-Code in der Handler-Datei verbindet.
2.1. QtVCP Widgets
QtVCP nutzt die PyQt5-Toolkits für die Einbeziehung von LinuxCNC.
Widget ist der allgemeine Name für die Benutzerschnittstellen-Objekte wie Buttons und Beschriftungen in PyQt5.
Es steht Ihnen frei, alle verfügbaren Standard-Widgets im Qt Designer-Editor zu verwenden.
Es gibt auch spezielle Widgets für LinuxCNC gemacht, dass die Integration einfacher zu machen.
Diese sind in drei Überschriften auf der linken Seite des Editors aufgeteilt:
-
Eine ist nur für HAL Widgets;
-
Eine ist für CNC-Steuerungs-Widgets;
-
Eine ist für Dialog-Widgets.
Es steht Ihnen frei, sie auf Ihrer Tafel beliebig zu mischen.
Ein sehr wichtiges Widget für die CNC-Steuerung ist das ScreenOptions
-Widget: Es fügt dem Bildschirm nichts Visuelles hinzu, sondern ermöglicht die Auswahl wichtiger Details, die dann in der Handler-Datei kodiert werden müssen.
2.2. INI-Einstellungen
Wenn Sie QtVCP zur Erstellung eines CNC-Bewegungssteuerungsbildschirms (und nicht eines HAL-basierten Panels) verwenden, fügen Sie in der INI-Datei im Abschnitt [DISPLAY]
eine Zeile mit folgendem Muster ein:
DISPLAY = qtvcp <Optionen> <Bildschirmname>
Anmerkung
|
Alle "<Optionen>" müssen vor "<Bildschirmname>" stehen. |
-
-d
Debugging an. -
-i
Infoausgabe aktivieren. -
-v
Aktiviert die ausführliche Debug-Ausgabe. -
-q
Aktiviert nur die Fehler-Debug-Ausgabe. -
-a
Fenster immer in Vordergrund (engl. top) setzen. -
-c NAME
Name der HAL-Komponente. Standardmäßig wird der UI-Dateiname verwendet. -
-g GEOMETRIE`Legt die Geometrie WIDTHxHEIGHT+XOFFSET+YOFFSET fest. Die Werte sind in Pixel-Einheiten, XOFFSET/YOFFSET wird vom linken oberen Bildschirmrand aus referenziert. Verwenden Sie -g WIDTHxHEIGHT, um nur die Größe zu bestimmen, oder -g +XOFFSET+YOFFSET, um nur die Position zu bestimmen. Beispiel: `-g 200x400+0+100
-
`-H DATEI`Führt HAL-Anweisungen aus DATEI mit halcmd aus, nachdem die Komponente eingerichtet und bereit ist.
-
-m
Fenster maximieren. -
-f
Vollbild des Fensters. -
-t THEME
Standard ist das Systemdesign -
-x XID
Einbindung in ein X11-Fenster, das nicht die Integration unterstützt. -
--push_xid
Sendet die X11-Fenster-Identifikationsnummer von QtVCP an die Standardausgabe; zum Einbetten. -
-u USERMOD
Dateipfad einer Ersatz-Handler-Datei. -
-o USEROPTS
Übergibt einen String an die Handler-Datei von QtVCP unter der Listenvariablenself.w.USEROPTIONS_
. Können mehrere -o sein.
<Bildschirmname>
ist der Basisname der .ui und _handler.py Dateien. Wenn <Bildschirmname>
fehlt, wird der Standardbildschirm geladen.
QtVCP geht davon aus, dass die UI-Datei und die Handler-Datei den gleichen Basisnamen verwenden.
QtVCP sucht nach Dateien zuerst im LinuxCNC-Konfigurationsverzeichnis, das gestartet wurde, dann im System-Skin-Ordner mit den Standardbildschirmen.
[DISPLAY] CYCLE_TIME = 100 GRAPHICS_CYCLE_TIME = 100 HALPIN_CYCLE = 100
Stellt die Reaktionsgeschwindigkeit der GUI-Aktualisierungen in Millisekunden ein.
Standardwert ist 100, nutzbarer Bereich 50 - 200.
Die Widgets, Grafiken und die HAL-Pin-Aktualisierung können separat eingestellt werden.
Wenn die Aktualisierungszeit nicht richtig eingestellt ist, kann der Bildschirm nicht mehr reagieren oder stark ruckeln.
2.3. Qt Designer UI Datei
Eine Qt Designer-Datei ist eine Textdatei, die im XML-Standard organisiert ist und das Layout und die Widgets des Bildschirms beschreibt.
PyQt5 verwendet diese Datei, um die Anzeige zu erstellen und auf diese Widgets zu reagieren.
Der Qt Designer Editor macht es relativ einfach, diese Datei zu erstellen und zu bearbeiten.
2.4. Handler-Dateien
Eine Handler-Datei ist eine Datei, die Python-Code enthält, der zu den QtVCP-Standardroutinen hinzugefügt wird.
Eine Handler-Datei erlaubt es, Voreinstellungen zu ändern oder einem QtVCP-Bildschirm Logik hinzuzufügen, ohne den Kerncode von QtVCP zu verändern. Auf diese Weise können Sie eigene Verhaltensweisen implementieren.
Falls vorhanden, wird eine Handler-Datei geladen.
Es ist nur eine Datei erlaubt.
2.5. Bibliotheken Module
QtVCP, so wie es gebaut ist, tut wenig mehr als den Bildschirm anzuzeigen und auf Widgets zu reagieren. Für weitere vorgefertigte Verhaltensweisen gibt es verfügbare Bibliotheken (zu finden in lib/python/qtvcp/lib
in RIP LinuxCNC install).
Bibliotheken sind vorgefertigte Python-Module, die Funktionen zu QtVCP hinzufügen.
Auf diese Weise können Sie auswählen, welche Funktionen Sie wünschen - und müssen die verbreiteten nicht selbst bauen.
Solche Bibliotheken umfassen:
-
audio_player
-
aux_program_loader
-
keybindings
-
message
-
preferences
-
notify
-
virtual_keyboard
-
machine_log
2.6. Themen
Designs sind eine Möglichkeit, das look and feel der Widgets auf dem Bildschirm zu ändern.
Zum Beispiel kann die Farbe oder Größe von Schaltflächen und Schiebereglern mit Hilfe von Themen geändert werden.
Das Windows-Thema ist der Standard für Bildschirme.
Das Systemthema ist der Standard für Bedienfelder.
Um die verfügbaren Themen zu sehen, können Sie sie mit dem folgenden Befehl in einem Terminal laden:
qtvcp -d -t <theme_name>
QtVCP kann auch mit Qt-Stylesheets (QSS) unter Verwendung von CSS angepasst werden.
2.7. Lokale Dateien
If present, local UI/QSS/python files in the configuration folder will be loaded instead of the stock UI files.
Local UI/QSS/python files allow you to use your customized designs rather than the default screens.
QtVCP will look for a folder named <screen_name> (in the launched configuration folder that holds the INI file).
In diesem Ordner lädt QtVCP jede der folgenden Dateien:
-
_<screen_name>_.ui
, -
<screen_name>_handler.py
, und -
_<screen_name>_.qss
.
2.8. Veränderung mitglieferter Bildschirmmasken
Es gibt drei Möglichkeiten, einen Bildschirm/Panel anzupassen.
Stylesheets können zum Setzen von Qt-Eigenschaften verwendet werden.
Wenn ein Widget Eigenschaften verwendet, können diese normalerweise durch Stylesheets verändert werden.
State_LED #name_of_led{ qproperty-color: red; qproperty-diameter: 20; qproperty-flashRate: 150; }
Eine weitere Python-Datei kann verwendet werden, um dem Bildschirm Befehle hinzuzufügen, nachdem die Handler-Datei geparst wurde.
In der INI-Datei unter der Überschrift [DISPLAY]
einfügen USER_COMMAND_FILE = _PATH_
PATH kann jeder gültige Pfad sein. Er kann ~
für das Heimatverzeichnis oder WORKINGDIRECTORY
oder CONFIGDIRECTORY
verwenden, um QtVCPs Vorstellung von diesen Verzeichnissen zu repräsentieren, z. B.:
[ANZEIGE] USER_COMMAND_FILE = CONFIGDIRECTORY/<Bildschirm_name_hinzugefuegte_Befehle>
Wenn kein Eintrag in der INI gefunden wird, sucht QtVCP im Standardpfad. Der Standardpfad befindet sich im Konfigurationsverzeichnis als versteckte Datei mit dem Basisnamen des Bildschirms und rc, d.h.: CONFIGDIRECTORY/.<Bildschirmname>rc
.
Diese Datei wird als Python-Code im handler-Dateikontext gelesen und ausgeführt.
Only local functions and local attributes can be referenced. Global libraries can not be referenced. (usually seen as all capital words with no preceding self.)
Was verwendet werden kann, mag je nach Bildschirm und Entwicklungszyklus variieren.
Ein gültiges Beispiel:
self.w.setWindowTitle('Mein Titel-Test')
Wenn Sie einen Standardbildschirm mit voller Kontrolle verändern möchten, kopieren Sie dessen UI und Handler-Datei in Ihren Konfigurationsordner.
Es gibt ein QtVCP-Panel, das dabei hilft:
-
Öffnen Sie ein Terminal und führen den folgenden Befehl aus:
qtvcp copy_dialog
-
Wählen Sie den Bildschirm und den Zielordner im Dialog
-
Wenn Sie Ihren Bildschirm anders benennen möchten als den Standardnamen des eingebauten Bildschirms, ändern Sie den Basisnamen im Bearbeitungsfeld.
-
Bestätigen, um alle Dateien zu kopieren
-
Löschen Sie die Dateien, die Sie nicht ändern möchten, damit die Originaldateien verwendet werden.
3. VCP-Paneele
QtVCP kann verwendet werden, um Bedienfelder zu erstellen, die mit HAL verbunden sind.
3.1. Eingebaute Panels
Es sind mehrere integrierte HAL-Panels verfügbar.
Geben Sie in einem Terminal qtvcp <return>
ein, um eine Liste zu sehen:
-
test_panel
-
Sammlung nützlicher Widgets zum Testen von HAL-Komponenten, einschließlich der Anzeige des LED-Zustands.
Abbildung 8. QtVCP HAL Test Integriertes Panel -
cam_align
-
Ein Kameraanzeige-Widget für die Rotationsausrichtung.
Abbildung 9. cam_align – Kameraausrichtung VCP -
sim_panel
-
Ein kleines Bedienfeld zur Simulation von MPG-Jogging-Steuerungen usw.
Für simulierte Konfigurationen.Abbildung 10. QtVCP Sim Eingebautes Panel -
vismach_mill_xyz
-
3D openGL Ansicht einer 3-Achsen Fräsmaschine.
Abbildung 11. QtVismach - 3-Achsen-Fräse Eingebautes Panel
Sie können diese aus dem Terminal oder aus einer HAL-Datei mit diesem einfachen Befehl laden:
loadusr qtvcp test_panel
Aber typischerweise eher so:
loadusr -Wn test_panel qtvcp test_panel
Auf diese Weise wartet HAL bis die HAL-Pins gesetzt sind, bevor es weitergeht.
3.2. Benutzerdefinierte Bedienfelder
Sie können natürlich Ihr eigenes Panel erstellen und laden.
Wenn Sie eine UI-Datei mit dem Namen my_panel.ui
und eine HAL-Datei mit dem Namen my_panel.hal
erstellt haben, würden Sie diese dann von einem Terminal aus laden mit:
halrun -I -f my_panel.hal
# Echtzeitkomponenten laden loadrt threads loadrt classicladder_rt # load non-realtime programs loadusr classicladder loadusr -Wn my_panel qtvcp my_panel.ui # <1> # Komponenten zum Thread hinzufügen addf classicladder.0.refresh thread1 # Pins verbinden net bit-input1 test_panel.checkbox_1 classicladder.0.in-00 net bit-hide test_panel.checkbox_4 classicladder.0.hide_gui net bit-output1 test_panel.led_1 classicladder.0.out-00 net s32-in1 test_panel.doublescale_1-s classicladder.0.s32in-00 # start thread start
-
In diesem Fall laden wir
qtvcp
mit-Wn
, das wartet, bis das Panel das Laden beendet hat, bevor es mit der Ausführung des nächsten HAL-Befehls fortfährt.
Damit soll gewährleistet werden, dass die vom Panel erstellten HAL-Pins tatsächlich fertig sind, falls sie im Rest der Datei verwendet werden.
4. Erstellen eines einfachen benutzerdefinierten Bildschirms

4.1. Übersicht
So erstellen Sie ein Bedienfeld oder einen Bildschirm:
-
Verwenden Sie Qt Designer, um ein Design zu erstellen, das Ihnen gefällt, und speichern Sie es in Ihrem Konfigurationsordner unter einem Namen Ihrer Wahl, der mit
.ui
endet -
Ändern Sie die Konfigurations-INI-Datei, um QtVCP mit Ihrer neuen
.ui
-Datei zu laden. -
Dann verbinden Sie alle erforderlichen HAL-Kenntnisse in einer HAL-Datei.
4.2. Holen Sie sich Qt Designer, um LinuxCNC-Widgets einzubinden
Zuerst müssen Sie den Qt Designer installieren.
Die folgenden Befehle sollten ihn zu Ihrem System hinzufügen, oder verwenden Sie Ihren Paketmanager, um dasselbe zu tun:
sudo apt-get install qttools5-dev-tools qttools5-dev libpython3-dev
qtvcp_plugin.py
zum Qt Designer SuchpfadDann müssen Sie einen Link zu qtvcp_plugin.py
in einem der Ordner hinzufügen, in denen Qt Designer suchen wird.
In einer RIP (engl. Abkürzung von "run in place", d.h. das Programm started dort wo es durch den Quellcode auch kompiliert wurde) Version von LinuxCNC wird qtvcp_plugin.py
sein:
'~/LINUXCNC_PROJECT_NAME/lib/python/qtvcp/plugins/qtvcp_plugin.py'
Die installierte Paketversion sollte sein:
'usr/lib/python2.7/qtvcp/plugins/qtvcp_plugin.py' or
'usr/lib/python2.7/dist-packages/qtvcp/plugins/qtvcp_plugin.py'
Legen Sie einen symbolischen Link auf die obige Datei an und verschieben Sie sie an einen der Orte, an denen Qt Designer sucht.
Qt Designer sucht an diesen beiden Stellen nach Links (wählen Sie einen aus):
'/usr/lib/x86_64-linux-gnu/qt5/plugins/designer/python' or
'~/.designer/plugins/python'
Möglicherweise müssen Sie den Ordner plugins/python
erstellen.
-
Für eine RIP-Installation:
Öffnen Sie ein Terminal, setzen Sie die Umgebungsvariablen für LinuxCNC <1>, dann laden Sie Qt Designer <2> mit :. scripts/rip-environment <1> designer -qt=5 <2>
-
Für eine Paketinstallation:
Öffnen Sie ein Terminal und geben Sie ein:designer -qt=5
Wenn alles gut geht, wird Qt Designer gestartet und Sie werden die auswählbaren LinuxCNC Widgets auf der linken Seite sehen.
4.3. Erstellen Sie die .ui
-Datei des Bildschirms
MainWindow
WidgetsWenn Qt Designer zum ersten Mal gestartet wird, erscheint ein 'New Form' Dialog.
Wählen Sie 'Main Window' und drücken Sie die Schaltfläche 'Create'.
Ein MainWindow
-Widget wird angezeigt.
Wir werden diesem Fenster eine bestimmte, nicht veränderbare Größe geben:
-
Fassen Sie die Ecke des Fensters an und ändern Sie die Größe auf eine geeignete Größe, z. B. 1000x600.
-
Klicken Sie mit der rechten Maustaste auf das Fenster und klicken Sie auf Mindestgröße einstellen.
-
Wiederholen Sie dies und stellen Sie maximale Größe ein.
Unser Beispiel-Widget ist nun nicht mehr größenveränderbar.
ScreenOptions
Ziehen Sie das ScreenOptions
-Widget per Drag-and-Drop an eine beliebige Stelle im Hauptfenster.
Dieses Widget fügt visuell nichts hinzu, richtet aber einige allgemeine Optionen ein.
Es wird empfohlen, dieses Widget immer vor allen anderen hinzuzufügen.
Klicken Sie mit der rechten Maustaste auf das Hauptfenster, nicht auf das "ScreenOptions"-Widget, und stellen Sie "Layout" auf "Vertikal", um "ScreenOptions" in voller Größe anzuzeigen.
Auf der rechten Seite befindet sich ein Panel mit Registerkarten für einen Eigenschaftseditor und einen Objektinspektor.
Klicken Sie im Objektinspektor auf ScreenOptions.
Wechseln Sie dann zum Eigenschaftseditor (engl. property editor) und schalten Sie unter der Überschrift ScreenOptions die filedialog_option
um.
Ziehen Sie ein GCodeGraphics
widget und ein GcodeEditor
widget per Drag and Drop.
Platzieren Sie sie und ändern Sie die Größe, wie Sie es für richtig halten, und lassen Sie etwas Platz für Schaltflächen.
Fügen Sie dem Hauptfenster 7 Aktionsschaltflächen hinzu.
Wenn Sie auf die Schaltfläche (engl. button) doppelklicken, können Sie Text hinzufügen.
Bearbeiten Sie die Schaltflächenbeschriftungen für "Notaus" (engl. "E-stop"), "Maschine ein", Referenzpunkt (engl. "Home"), "Laden" (engl. "Load"), "Ausführen" (engl. "Run"), "Pause" und "Stopp".
Aktionsschaltflächen sind standardmäßig auf keine Aktion eingestellt, daher müssen wir die Eigenschaften für definierte Funktionen ändern. Sie können die Eigenschaften bearbeiten:
-
direkt im Eigenschaften-Editor auf der rechten Seite des Qt-Designers, oder
-
conveniently, left double clicking on the button to launch a properties dialog that allows selecting actions while only displaying relevant data to the action.
Wir werden zunächst den bequemen Weg beschreiben:
-
Klicken Sie mit der rechten Maustaste auf die Schaltfläche Maschine ein (engl.machine on) und wählen Sie Aktionen festlegen (engl. set actions).
-
Wenn das Dialogfeld angezeigt wird, verwenden Sie die Combobox, um zu
MASCHINENSTEUERUNGEN - Maschine ein
(engl.MACHINE CONTROLS - Machine On
) zu navigieren. -
In diesem Fall gibt es keine Option für diese Aktion, also wählen Sie "OK".
Jetzt schaltet die Taste das Gerät ein, wenn sie gedrückt wird.
Und nun der direkte Weg mit dem Eigenschaftseditor von Qt Designer:
-
Wählen Sie die Schaltfläche "Maschine ein".
-
Gehen Sie zum Eigenschaftseditor auf der rechten Seite von Qt Designer.
-
Blättern Sie nach unten, bis Sie die Überschrift ActionButton finden.
-
Klicken Sie auf das Kontrollkästchen für die Aktion "Machine_on", das Sie in der Liste der Eigenschaften und Werte sehen.
Die Taste steuert nun das Ein- und Ausschalten der Maschine.
Machen Sie das Gleiche für alle anderen Schaltflächen und fügen Sie noch einen hinzu:
-
Bei der Schaltfläche "Home" müssen wir auch die Eigenschaft
joint_number
auf1
ändern.
Dadurch wird der Controller angewiesen, alle Achsen und nicht nur eine bestimmte Achse zu referenzieren. -
Mit dem Button "Pause":
-
Unter der Überschrift
Indicated_PushButton
überprüfen Sie dieIndicator_option
. -
Unter der Überschrift
QAbstactButton
markieren Siecheckable
.
-

.ui
-Datei speichernDiesen Entwurf müssen wir dann als tester.ui
im Ordner sim/qtvcp
speichern.
Wir speichern sie unter dem Namen tester, da dies ein Dateiname ist, den QtVCP erkennt und eine eingebaute Handler-Datei verwendet, um sie anzuzeigen.
4.4. Handler-Datei
Eine Handler-Datei ist erforderlich.
Er ermöglicht das Schreiben von Anpassungen in Python.
Zum Beispiel werden Tastatursteuerungen normalerweise in die Handler-Datei geschrieben.
In diesem Beispiel wird die eingebaute Datei tester_handler.py
automatisch verwendet: Sie tut das Minimum, das erforderlich ist, um den in tester.ui
definierten Bildschirm darzustellen und einfache Tastatureingaben vorzunehmen.
4.5. INI-Konfiguration
Wenn Sie QtVCP zur Erstellung eines CNC-Steuerungsbildschirms verwenden, setzen Sie unter der Überschrift INI-Datei [DISPLAY]
:
DISPLAY = qtvcp <Bildschirmname>
_<Bildschirmname>_
ist der Basisname der Dateien .ui
und _handler.py
.
In unserem Beispiel gibt es bereits eine Sim-Konfiguration namens tester, die wir zur Anzeige unseres Testbildschirms verwenden werden.
Wenn Ihr Bildschirm Widgets mit HAL-Pins verwendet, dann müssen Sie diese in einer HAL-Datei verbinden.
QtVCP sucht in der INI-Datei unter der Überschrift [HAL]
nach den folgenden Einträgen:
-
POSTGUI_HALFILE=<Dateiname>
-
Der Konvention nach wäre
<Dateiname>
als+<Bildschirm_name>_postgui.hal+
genannt, aber es kann jeder legale Dateiname sein.
Sie können mehrerePOSTGUI_HALFILE
-Zeilen in der INI haben: jede wird nacheinander in der Reihenfolge ausgeführt, in der sie erscheint.
Diese Befehle werden nach der Erstellung des Bildschirms ausgeführt, um sicherzustellen, dass die HAL-Pins des Widgets verfügbar sind. -
POSTGUI_HALCMD=<Befehl>
-
<Befehl>
wäre jeder gültige HAL-Befehl.
Sie können mehrerePOSTGUI_HALCMD
-Zeilen in der INI haben: jede wird nacheinander in der Reihenfolge ausgeführt, in der sie erscheint.
Um zu garantieren, dass die HAL-Pins des Widgets verfügbar sind, werden diese Befehle ausgeführt:-
nachdem der Bildschirm gebaut ist,
-
nachdem alle POSTGUI_HALFILEs ausgeführt wurden.
-
In unserem Beispiel gibt es keine HAL-Pins zu verbinden.
5. Handler-Datei im Detail
Handler-Dateien werden zur Erstellung von benutzerdefinierten Steuerelementen mit Python verwendet.
5.1. Übersicht
Hier ist ein Beispiel für eine Handler-Datei.
Es ist in Abschnitte unterteilt, um die Diskussion zu erleichtern.
############################ # **** IMPORT SECTION **** # ############################ import sys import os import linuxcnc from PyQt5 import QtCore, QtWidgets from qtvcp.widgets.mdi_line import MDILine as MDI_WIDGET from qtvcp.widgets.gcode_editor import GcodeEditor as GCODE from qtvcp.lib.keybindings import Keylookup from qtvcp.core import Status, Action # Set up logging from qtvcp import logger LOG = logger.getLogger(__name__) # Set the log level for this module #LOG.setLevel(logger.INFO) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL ########################################### # **** BIBLIOTHEKEN INSTANZIIEREN **** # ########################################### KEYBIND = Keylookup() STATUS = Status() ACTION = Action() ################################### # **** HANDLER CLASS SECTION **** # ################################### class HandlerClass: ######################## # **** INITIALIZE **** # ######################## # Widgets ermöglicht den Zugriff auf Widgets aus den QtVCP-Dateien # An dieser Stelle werden die Widgets und HAL-Pins nicht instanziiert def __init__(self, halcomp,widgets,paths): self.hal = halcomp self.w = widgets self.PATHS = paths ########################################## # SPECIAL FUNCTIONS SECTION # ########################################## # at this point: # the widgets are instantiated. # the HAL pins are built but HAL is not set ready # This is where you make HAL pins or initialize state of widgets etc def initialized__(self): pass def processed_key_event__(self,receiver,event,is_pressed,key,code,shift,cntrl): # when typing in MDI, we don't want keybinding to call functions # so we catch and process the events directly. # We do want ESC, F1 and F2 to call keybinding functions though if code not in(QtCore.Qt.Key_Escape,QtCore.Qt.Key_F1 ,QtCore.Qt.Key_F2, QtCore.Qt.Key_F3,QtCore.Qt.Key_F5,QtCore.Qt.Key_F5): # search for the top widget of whatever widget received the event # then check if it's one we want the keypress events to go to flag = False receiver2 = receiver while receiver2 is not None and not flag: if isinstance(receiver2, QtWidgets.QDialog): flag = True break if isinstance(receiver2, MDI_WIDGET): flag = True break if isinstance(receiver2, GCODE): flag = True break receiver2 = receiver2.parent() if flag: if isinstance(receiver2, GCODE): # if in manual do our keybindings - otherwise # send events to G-code widget if STATUS.is_man_mode() == False: if is_pressed: receiver.keyPressEvent(event) event.accept() return True elif is_pressed: receiver.keyPressEvent(event) event.accept() return True else: event.accept() return True if event.isAutoRepeat():return True # ok if we got here then try keybindings try: return KEYBIND.call(self,event,is_pressed,shift,cntrl) except NameError as e: LOG.debug('Exception in KEYBINDING: {}'.format (e)) except Exception as e: LOG.debug('Exception in KEYBINDING:', exc_info=e) print('Error in, or no function for: %s in handler file for-%s'%(KEYBIND.convert(event),key)) return False ######################## # CALLBACKS FROM STATUS # ######################## ####################### # CALLBACKS FROM FORM # ####################### ##################### # GENERAL FUNCTIONS # ##################### # keyboard jogging from key binding calls # double the rate if fast is true def kb_jog(self, state, joint, direction, fast = False, linear = True): if not STATUS.is_man_mode() or not STATUS.machine_is_on(): return if linear: distance = STATUS.get_jog_increment() rate = STATUS.get_jograte()/60 else: distance = STATUS.get_jog_increment_angular() rate = STATUS.get_jograte_angular()/60 if state: if fast: rate = rate * 2 ACTION.JOG(joint, direction, rate, distance) else: ACTION.JOG(joint, 0, 0, 0) ##################### # KEY BINDING CALLS # ##################### # Machine control def on_keycall_ESTOP(self,event,state,shift,cntrl): if state: ACTION.SET_ESTOP_STATE(STATUS.estop_is_clear()) def on_keycall_POWER(self,event,state,shift,cntrl): if state: ACTION.SET_MACHINE_STATE(not STATUS.machine_is_on()) def on_keycall_HOME(self,event,state,shift,cntrl): if state: if STATUS.is_all_homed(): ACTION.SET_MACHINE_UNHOMED(-1) else: ACTION.SET_MACHINE_HOMING(-1) def on_keycall_ABORT(self,event,state,shift,cntrl): if state: if STATUS.stat.interp_state == linuxcnc.INTERP_IDLE: self.w.close() else: self.cmnd.abort() # Linear Jogging def on_keycall_XPOS(self,event,state,shift,cntrl): self.kb_jog(state, 0, 1, shift) def on_keycall_XNEG(self,event,state,shift,cntrl): self.kb_jog(state, 0, -1, shift) def on_keycall_YPOS(self,event,state,shift,cntrl): self.kb_jog(state, 1, 1, shift) def on_keycall_YNEG(self,event,state,shift,cntrl): self.kb_jog(state, 1, -1, shift) def on_keycall_ZPOS(self,event,state,shift,cntrl): self.kb_jog(state, 2, 1, shift) def on_keycall_ZNEG(self,event,state,shift,cntrl): self.kb_jog(state, 2, -1, shift) def on_keycall_APOS(self,event,state,shift,cntrl): pass #self.kb_jog(state, 3, 1, shift, False) def on_keycall_ANEG(self,event,state,shift,cntrl): pass #self.kb_jog(state, 3, -1, shift, linear=False) ########################### # **** closing event **** # ########################### ############################## # required class boiler code # ############################## def __getitem__(self, item): return getattr(self, item) def __setitem__(self, item, value): return setattr(self, item, value) ################################ # required handler boiler code # ################################ def get_handlers(halcomp,widgets,paths): return [HandlerClass(halcomp,widgets,paths)]
5.2. IMPORT Bereich
Dieser Abschnitt ist für Import der erforderlichen Bibliotheksmodule für Ihren Bildschirm.
Es wäre typisch, die QtVCP-Bibliotheken keybinding, Status und Action zu importieren.
5.3. Abschnitt INSTANTIATE BIBRARIES
Indem wir die Bibliotheken hier instanziieren, erzeugen wir eine globale Referenz.
Sie können dies an den Befehlen erkennen, denen kein "self" vorangestellt ist.
Konventionell werden die Namen von global referenzierten Bibliotheken großgeschrieben.
5.4. HANDLER CLASS-Abschnitt
Der angepasste Code wird in einer Klasse platziert, damit QtVCP ihn verwenden kann.
Dies ist die Definition der Handler-Klasse.
5.5. INITIALIZE Abschnitt
Wie alle Python-Bibliotheken wird die +__init__+
-Funktion aufgerufen, wenn die Bibliothek erstmals instanziiert wird.
Hier können Sie Standardwerte, Referenzvariablen und globale Variablen einrichten.
Die Referenzen der Widgets sind zu diesem Zeitpunkt nicht verfügbar.
Die Variablen halcomp
, widgets
und paths
ermöglichen den Zugriff auf QtVCP’s HAL-Komponenten, Widgets bzw. Pfadinformationen.
5.6. Abschnitt zu BESONDEREN FUNKTIONEN
Es gibt mehrere spezielle Funktionen, nach denen QtVCP in der Handler-Datei sucht. Wenn QtVCP diese findet, ruft es sie auf, wenn nicht, ignoriert es sie stillschweigend.
-
initialized__(self):
-
Diese Funktion wird aufgerufen, nachdem die Widgets und HAL-Pins erstellt wurden.
Sie können hier die Widgets und HAL-Pins manipulieren oder weitere HAL-Pins hinzufügen.
In der Regel gibt es-
Einstellungen überprüft und eingestellt,
-
auf Widgets angewendete Stile,
-
Status von LinuxCNC verbunden mit Funktionen.
-
Tastenbelegungen würden hinzugefügt.
-
-
class_patch__(self):
-
Class patching, auch bekannt als monkey patching, erlaubt es, Funktionsaufrufe in einem importierten Modul zu überschreiben.
Klassen-Patching muss vor der Instanziierung des Moduls durchgeführt werden und verändert alle danach erstellten Instanzen.
Ein Beispiel wäre das Patchen von Schaltflächenaufrufen aus dem G-Code-Editor, um stattdessen Funktionen in der Handler-Datei aufzurufen.
-
processed_key_event__(self,receiver,event,is_pressed,key,code,shift,cntrl):
-
Diese Funktion wird aufgerufen, um Tastatur-Jogging usw. zu erleichtern.
Durch die Verwendung derkeybinding
-Bibliothek kann dies verwendet werden, um einfach Funktionen hinzuzufügen, die an Tastendrücke gebunden sind. -
keypress_event__(self,receiver, event):
-
Diese Funktion liefert rohe Tastendruckereignisse.
Sie hat _Vorrang vor demverarbeiteten_Tastenereignis
. -
keyrelease_event__(receiver, event):
-
Diese Funktion gibt raw key release events aus.
Es hat Vorrang vor demprocessed_key_event
. -
before_loop__(self):
-
Diese Funktion wird kurz vor dem Eintritt in die Qt-Ereignisschleife aufgerufen. Zu diesem Zeitpunkt sind alle Widgets/Bibliotheken/Initialisierungscodes abgeschlossen und der Bildschirm wird bereits angezeigt.
-
system_shutdown_request__(self):
-
Falls vorhanden, überschreibt diese Funktion die normale Funktion, die beim vollständigen Herunterfahren des Systems aufgerufen wird.
Sie kann dazu benutzt werden, vor dem Herunterfahren Hausarbeiten zu erledigen.
+
Das Linux System wird nicht heruntergefahren, wenn Sie diese Funktion verwenden, Sie müssen das selbst tun.
QtVCP/LinuxCNC beendet sich ohne eine Eingabeaufforderung, sobald diese Funktion zurückkehrt. -
closing_cleanup__(self):
-
Diese Funktion wird kurz vor dem Schließen des Bildschirms aufgerufen. Sie kann verwendet werden, um vor dem Schließen aufzuräumen.
5.7. STATUS CALLBACKS Abschnitt
Konventionell würden Sie hier Funktionen unterbringen, die Rückrufe von STATUS-Definitionen sind.
5.8. CALLBACKS FROM FORM Abschnitt
Konventionell würden Sie hier Funktionen ablegen, die Rückrufe von den Widgets sind, die mit dem MainWindow im Qt Designer-Editor verbunden sind.
5.9. Abschnitt mit ALLGEMEINEN FUNKTIONEN
Konventionell werden hier die allgemeinen Funktionen untergebracht.
5.10. Abschnitt zur KEY BINDING (engl. für Tastenbelegung)
Wenn Sie die Keybinding
-Bibliothek_ verwenden, platzieren Sie hier Ihre benutzerdefinierten Tastenaufrufroutinen.
Die Funktionssignatur ist:
def on_keycall_KEY(self,event,state,shift,cntrl): if state: self.do_something_function()
KEY
ist der Code (aus der Keybindings-Bibliothek) für den gewünschten Schlüssel.
5.11. CLOSING EVENT Sektion
Wenn Sie die Funktion closeEvent
hier einfügen, werden Schließungsereignisse abgefangen.
Dies replaces eine vordefinierte 'closeEvent'-Funktion von QtVCP.
def closeEvent(self, event): self.do_something() event.accept()
Anmerkung
|
Normalerweise ist es besser, die spezielle Funktion closing_cleanup__ zu verwenden. |
6. Verbinden von Widgets mit Python-Code
Es ist möglich, Widgets über Signale und Slots mit Python-Code zu verbinden.
Auf diese Weise können Sie:
-
LinuxCNC-Widgets neue Funktionen geben, oder
-
Standard Qt-Widgets zur Steuerung von LinuxCNC verwenden.
6.1. Übersicht
Im Qt Designer-Editor:
-
Sie erstellen Benutzerfunktions-Slots
-
Sie verbinden die Slots mit Widgets, indem Sie Signale verwenden.
In der Handler-Datei:
-
Sie erstellen die Funktionen des Slots, die im Qt Designer definiert sind.
6.2. Hinzufügen von Slots mit Qt Designer
Wenn Sie Ihren Bildschirm in Qt Designer geladen haben, fügen Sie einen einfachen PushButton
zu dem Bildschirm hinzu.
Sie könnten den Namen der Schaltfläche in etwas Interessantes wie "test_button" ändern.
Es gibt zwei Möglichkeiten, Verbindungen zu bearbeiten - Dies ist die grafische Methode.
-
In der oberen Werkzeugleiste von Qt Designer gibt es eine Schaltfläche zum Bearbeiten von Signalen. Wenn Sie auf die Schaltfläche klicken und sie gedrückt halten, wird ein Pfeil angezeigt (sieht aus wie ein Erdungssignal aus einem elektrischen Schaltplan).
-
Schieben Sie diesen Pfeil auf einen Bereich des Hauptfensters, in dem sich keine Widgets befinden.
-
Ein Dialogfeld „Verbindungen konfigurieren“ wird angezeigt.
-
Die Liste auf der linken Seite enthält die verfügbaren Signale des Widgets.
-
Die Liste auf der rechten Seite sind die verfügbaren Slots im Hauptfenster und Sie können sie ergänzen.
-
-
Wählen Sie das Signal
clicked()
- dies macht die Slot-Seite verfügbar. -
Klicken Sie in der Slotliste auf "Bearbeiten" (engl. edit).
-
Ein Dialogfeld "Slots/Signale des Hauptfensters" wird angezeigt.
-
In der Slots-Liste oben befindet sich ein "+"-Symbol - klicken Sie darauf.
-
Sie können nun einen neuen Slotnamen bearbeiten.
-
Löschen Sie den Standardnamen
slot()
und ändern Sie ihn intest_button()
. -
Drücken Sie die Taste OK.
-
Sie gelangen zurück zum Dialog Verbindungen konfigurieren.
-
Nun können Sie Ihren neuen Slot in der Slotliste auswählen.
-
Drücken Sie dann auf "OK" und speichern Sie die Datei.

6.3. Änderungen am Python-Handler
Nun müssen Sie die Funktion in die Handler-Datei einfügen.
Die Funktionssignatur lautet def slot_name(self):
.
Für unser Beispiel fügen wir etwas Code hinzu, um den Namen des Widgets zu auszugeben:
def test_button(self): name = self.w.sender().text() print(name)
Fügen Sie diesen Code unter dem Abschnitt namens:
####################### # Callbacks vom Formular #######################
Tatsächlich spielt es keine Rolle, wo in der Handler-Klasse Sie die Befehle ablegen, aber per Konvention ist dies der Ort, an dem Sie sie ablegen müssen.
Speichern der Handlerdatei.
Wenn Sie nun Ihren Bildschirm laden und die Schaltfläche drücken, sollte der Name der Schaltfläche im Terminal angezeigt werden.