QEvent-Eigene Events

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

Hallo erstmal,

ich versuche gerade einen einstieg in Python zu finden. Normalerweise bin ich nur in der SPS - Programmierung zu Hause also bitte seit nachsichtig mit mir. :oops:

Zum Problem:
Ich möchte mir, für ein späteres Visualisierungsprojekt, die Fähigkeit aneignen, eigene Buttonklassen zu erstellen. Genauer gesagt, ich will nicht nur einen Butten mit nem Bild drauf, sondern den Button auch aktiv zeichnen bzw. animieren und mit globalen, eigenen Events verbinden können.
Ich versuche dabei einen möglichst objektorientierten Ansatz zu verwenden. Es sollen möglichst alle Funtionaliäten in einer Klasse sein, die ich dann genauso einfach wie zum Beispiel den QPuschButton implementieren kann.
Als Übung habe ich versucht, einen Button automatisch über ein eigenes Event in der mitte des Fensters zu Positionen, wenn sich die Größe des Fensters ändert.
Klar geht das auch über Layouts, es soll nur exemplarisch für ein eigenes, globales Event sein.

Ich denke der Stolperstein ist, das ich in der "Hauptfenster" und der "MyPushbutton" Klasse, jeweils eine eigene Instanz gebildet habe.
Allerdings weiß ich nicht so recht, wie ich das lösen kann.

Code: Alles auswählen

from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
import sys

# Eigene Event Klasse
class OwnEvents(QtCore.QObject):
    global_move = QtCore.pyqtSignal()

# Eigene Buttonklasse
class MyPushButton(QPushButton, OwnEvents):
    fensterW = 10
    fensterH = 10

    def resize_func(self, fenster_w, fenster_h):
        sig = OwnEvents()
        sig.global_move.connect(self.glob_move)
        type(self).fensterW = fenster_w
        type(self).fensterH = fenster_h

        print("resize_func ausgeführt")
    def glob_move(self):
        self.move(int((type(self).fensterW / 2) - (type(self).fensterH / 2)),
                              int((self.width() / 2) - (self.height() / 2)))
        print("Event empfangen Test")

# Hauptfenster Klasse
class MainWidget(QWidget):
    def __init__(self, widget_title):
        super().__init__()
        self.setWindowTitle(widget_title)
        self.windowWidth = self.width()     # aktuelle Fensterbreite speichern
        self.windowHeight = self.height()   # aktuelle Fensterhöhe speichern
        self.exit_button = MyPushButton("Exit", self)
        self.exit_button.clicked.connect(self.close_window)
        self.exit_button.resize_func(self.windowWidth, self.windowHeight)
        self.sig = OwnEvents()

    def resizeEvent(self, event_e):
        self.sig.global_move.emit()
        print(f"Event ausgeführt: {event_e}")

    def close_window(self):
        self.close()

# Applikation starten/beenden
app = QApplication(sys.argv)
widget = MainWidget(widget_title="MainView")
widget.showMaximized()
sys.exit(app.exec_())
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

hm, ziemlich wenig los hier. Hab selber eine Lösung gefunden auch wenn ich denke, das die nicht sehr sauber ist.
Falls jemand nen besseren Vorschlag hat, darf er mich gerne korrigieren.
Ansonsten der Form halber hier meine Lösung:

Code: Alles auswählen

from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
import sys


# Hauptfenster Klasse
class MainWidget(QWidget):
    main_signal = QtCore.pyqtSignal()

    def __init__(self, widget_title):
        super().__init__()
        self.setWindowTitle(widget_title)

        self.exit_button = MyPushButton("Exit", self)
        self.exit_button.clicked.connect(self.close_window)

    def resizeEvent(self, e_event):
        self.main_signal.emit()

    def close_window(self):
        self.close()


# Eigene Buttonklasse
class MyPushButton(QPushButton):

    def __init__(self, target_name, target):
        super().__init__(target_name, target)
        self.target_widget = target
        self.target_widget.main_signal.connect(self.glob_move)

    def glob_move(self):
        self.move(int(self.target_widget.width() / 2) - int(self.width() / 2),
                  int(self.target_widget.height() / 2) - int(self.height() / 2))


# Applikation starten/beenden
app = QApplication(sys.argv)
widget = MainWidget(widget_title="MainView")
widget.showMaximized()
sys.exit(app.exec_())

__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Kopplung ist viel zu eng. Warum muss MyPushButton das Target kennen? Wenn das Signal alle relevanten Informationen (zur Not auch das Target selbst) verschickt, kann sich der Empfänger die Daten rausklauben, ohne ein eigenes Attribut haben zu müssen. Und von außen verknüpft man die entsprechenden Signale und slots. Statt sowas in den Buttons hart zu kodieren.

Und ich würde auch in Frage stellen, das man hier ableiten muss. Ist durchaus eine Frage des Stils, aber immer wenn man ableitetet, schränkt man zb die Nutzung des Designers ein.

Last but not least: überhaupt Buttons oder andere GUI-Element zu nutzen ist seeehr fragwürdig. Wenn du da das machst, wonach es aussieht, dann solltest du dir eher mal QGraphicsView anschauen. Das beherrscht uA Hierarchien von graphischen Objekten, so dass du zb ein Objekt verschiebst oder anderweitig transformierst, und allen Kindern geschieht gleich.

Was ist denn das Ziel des ganzen?
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ein QWidget hat eine resizeEvent()-Methode. Die kann man überschreiben, sodass sie Änderungen an den ihr untergeordneten Widgets vornehmen kann. Eine Möglichkeit, das noch sauberer anzugehen, wäre die Anpassung eines Layouts, welches man dann für das Widget setzt. Alles natürlich bezogen auf den Fall, dass ein Standard-Layout nicht ausreicht, um die gewünschten Anpassungen zu übernehmen.
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

Danke für die Antworten.
Späteres Ziel des ganzen soll eine Visualisierung für Sondermaschinen sein. Bisher arbeitet unsere Firma immer je nach Kundenwunsch, mit Systemgebunden Visualisierungen.
Bsp.: Siemens mit seinem WinCC, BoschRexroth mit seinem Opcon+ (Nexeed) usw.
Die sind aber dementsprechend sehr teuer.
Konkretes Bsp.: Bisher haben wir für die Linie eines Kunden sehr kleine Siemenspanels mit Siemens Steuerung verwenden. Die arbeiter-Anweisungen sind mit kurzen Textzeilen Visualisiert worden.
Jetzt möchte der Kunde, das die Anweisungen nicht nur Text, sonder auch Grafiken enthalten sollen bis hin zur kurz-Animation wo ein Teil wie hin soll.
Das ist mit WinCC durchaus möglich und es gibt auch Große Touchpanels dafür. Aber die kosten dann mal schnell mal 4000€ pro Stück. Bei 10 Maschinen in der Linie sind das 40.000€, nur um ein paar Bilder anzuzeigen.
Natürlich ist da keiner bereit, das zu bezahlen. Wir haben jetzt die Lösung gewählt, mit nem RassberryPi und einem einfachen Touchdisplay. Kostenpunkt ca. 700€/Stück.
Man hat da auf die schnelle eine 0815 TCP/IP-Verbindung mit der SPS-Steuerung mit Python realisiert und mit einfachen Kommandos die entsprechenden Bilder geladen. Diese hängen zusätzlich zu den eigentlichen Bedienpanel an den Anlagen.

Ich will jetzt der Firma langfristig ein eigenes, Platformunabhängiges, Visualisierungskonzept vorschlagen. Klar gibt es da Produkte wie Zenon oder ähnliches, aber die sind dann eben auch wieder sehr teuer.
Das muss halt Flexibel und einfach zu lesen bzw. zu erstellen sein. Weil meine Programmierkollegen brauche ich nicht mit einer Hochsprache zu kommen, wo sie für jeden Button noch nen haufen Code für die Funktionen Tippen müssen.
Die sind gewohnt mit nem GUI-Designer nen Button auf's Fenster zu ziehen, Variable mit Button verbinden fertig.
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

__deets__ hat geschrieben: Mittwoch 18. November 2020, 23:12 Die Kopplung ist viel zu eng. Warum muss MyPushButton das Target kennen?
Das war nur ein Beispiel. Prinzipell geht es darum, das ein globales Event (Notaus-Aktiv, Betriebsartenwechsel) das Erscheinungsbild des Buttons verändert und desen Bedienbarkeit z.B. sperrt.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Trotzdem, oder gerade weil da jemand was mit qt-Designer zusammen klicken will, besteht keine Notwendigkeit, sich eine eigene Klasse zu schreiben.
Was ist denn das konkrete Problem?
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der Zusammenhang zwischen deiner Aufgabe und Deinem Lösungsversuch ist mir unklar. Wenn du ein einfaches, deklaratives System, angepasst auf deinen Domäne, haben willst, solltest du eher darein investieren, ein Beschreibungsformat zu definieren. Ähnlich wie HTML oder Kivy das machen. Wenn das denn den Kollegen zumutbar ist. Wenn es tatsächlich nur mit einer visuellen Programmierung lösbar ist, wirst du sehr, sehr viel Arbeit da reinstecken müssen. Ob sich das lohnt, wage ich zu bezweifeln.
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

__deets__ hat geschrieben: Donnerstag 19. November 2020, 09:08 Der Zusammenhang zwischen deiner Aufgabe und Deinem Lösungsversuch ist mir unklar. Wenn du ein einfaches, deklaratives System, angepasst auf deinen Domäne, haben willst, solltest du eher darein investieren, ein Beschreibungsformat zu definieren. Ähnlich wie HTML oder Kivy das machen. Wenn das denn den Kollegen zumutbar ist. Wenn es tatsächlich nur mit einer visuellen Programmierung lösbar ist, wirst du sehr, sehr viel Arbeit da reinstecken müssen. Ob sich das lohnt, wage ich zu bezweifeln.
Wie bekomme ich rein mit HTML oder ähnliches die Komunikation mit einer SPS hin? Gut, die neueren Modele haben durchaus eine Möglichkeit für eine Webserveranwendung, aber ältere bzw. kleinere Modelle nicht. Ich will z.B. auch Direktanbindungen zu Kameras und Visonsensoren ermöglichen. Die nutzen fast alle nur direkte TCP/IP Komunikation mit eigenen Protokollen.
Python hat den für mich interessanten Vorteil, das es Platformunabhängig (Linux, Windows, Mac) ist und darüberhinaus auch von vielen Systemkomponenten wie z.B. Labview unterstützt wird. Beipielsweise kann ich auch an Labview anbinden, um die Funktionalität zu erweitern.

Ich mus mich jetzt auf ein System festlegen, wo ich später nach Möglichkeit nicht an Grenzen stoße. Mit HTML glaub ich, bin nicht so Flexibel, gerade was die Hardwareanbindung angeht.
Das es erstmal sehr viel Vorarbeit bedarf, ist mir klar. Deswegen will ich klein Anfangen (Firmeneigene Standart TCP/IP Kommunikation für alle eigenen Maschinensteuerungs-Typen, um eine Zusatz-Visualisierung für alle zu ermöglichen), bis hin zu komplexeren Sachen wie Daten von Verschiedenen Komponenten aufzeichnen/aufbereiten/anzeigen/an SPS weiterreichen.
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

Sirius3 hat geschrieben: Donnerstag 19. November 2020, 07:57 Trotzdem, oder gerade weil da jemand was mit qt-Designer zusammen klicken will, besteht keine Notwendigkeit, sich eine eigene Klasse zu schreiben.
Was ist denn das konkrete Problem?
Naja wenn ich jetzt den QPushbutton auf mein Fenster ziehe, dann ist der zwar da, macht aber noch nix. Ich muss die Funktionalität erst noch Programmieren und wenn ich z.B. als Button keine Rechteckige Schaltfläche, sondern ein Piktogram (z.B. Play-zeichen von der Fernbedienung) in "Glasoptik" haben will, muss ich da auch erstmal ne ganze Menge Code tippen. Mit einer eigenen Klasse, die von QPushbutton abgeleit ist, kann ich das dann schon integrieren. Im QtDesigner kann man auch eigene Ressourcen anlegen, und die dann wie den QPushButton auf's Fenster ziehen.
So zumindest die Theorie :lol:
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wie du aus “ähnlich wie HTML” zu “HTML, und auch nur das” kommst, ist mit schleierhaft. Der Vorschlag war eine simple Auszeichnungssprache zu schaffen, wie HTML es eben für Dokumente ist. Davon eine HTML-Lösung abzuliefern war nicht die Rede. Es ist allerdings durchaus keine schlechte Wahl. Die gestalterische Flexibilität ist größer als anderswo.

Deine ganzen Einwände sind da auch gegenstandslos, weil das natürlich immer mit einer Server-Seite kommt. Dieser Server läuft auch auf dem gleichen Rechner, kann in Python geschrieben sein, und hat Zugriff auf alle Ressourcen und Bibliotheken, die man sich wünscht.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@Treter_Peter: wenn Du die Oberfläche so stark verändern willst, bist Du mit HTML besser bedient. Auf dem Rechner läuft ein Browser in Vollbild (Kioskmode) und spricht mit einem Python-Server, der im Hintergrund läuft.
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

Sirius3 hat geschrieben: Donnerstag 19. November 2020, 12:09 @Treter_Peter: wenn Du die Oberfläche so stark verändern willst, bist Du mit HTML besser bedient. Auf dem Rechner läuft ein Browser in Vollbild (Kioskmode) und spricht mit einem Python-Server, der im Hintergrund läuft.
Ok, jetzt hab ich auch endlich verstanden, worauf _deeds hinaus wollte. Ich glaub, der meinte das Gleiche.

Also die Hardwareseitige Anbindung mit Python an die SPS und mit HTML wiederum an mein Pythonprogramm, richtig?
Da muss ich ja noch ne Programmiersprache mehr lernen :lol:
Nein im ernst, ich erkenne schon den Sinn darin. Aber die Rahmenstruktur und die Designelemente erstelle ich ja mehr oder weniger nur einmal und verwende die dann nur in unterschiedlichen variationen.
Ich denke da würde das PyQT-Framework mit dem Q-Designer schon reichen.
Aber ich schau mir mal an, wie "kompliziert" das ganze für mich wird. Eine 2te Sprache parallel zu lernen.

Danke.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Qt ist auch eine eigene Sprache für sich. Und wenn Du die Styles von Qt-Buttons ändern willst, machst Du das auch mit CSS, also exakt gleich wie bei HTML.
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Auch das ist nicht so ganz was ich meinte. Du kannst Qt zur Darstellung nutzen oder HTML oder Tkinter. Hat alles so seine Vor- und Nachteile.

Die Frage ist, wie deine Kollegen die Oberflächen definieren. Und auch dazu musst du eine Lösung finden. Eine speziell darauf abgestimmte Auszeichnungssprache ist eine Antwort, die relativ einfach umsetzbar ist. Einen fetten GUI Editor mit allem Schnick und Schnack zu schreiben kostet dich Monate wenn nicht länger. Und selbst dann wäre eine Zwischenschicht mit einem Format in XML oder ähnlichem sinnvoll. Siehe den Qt-Designer selbst.
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

__deets__ hat geschrieben: Donnerstag 19. November 2020, 14:10 Die Frage ist, wie deine Kollegen die Oberflächen definieren. Und auch dazu musst du eine Lösung finden.
Die sollen den QtDesigner selbst nutzen. Nur eben mit erweiterten StandartObjekten.
Z.B. der QPushButton wird durch eine eigene Version erweitert, in dem z.B. das ändern der Form/Farbe wenn Betriebsart nicht freigegen schon enthalten sind. Die Variablenanbindung will ich dann über Symbolfiles o.ä. umsetzen, die wiederum in einen eigenen, kleinen Dialog-Program erstellt werden.
Ob das so funktioniert, muss ich aber zugegebenermaßen erst noch testen.
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich halte das für zu ambitioniert und frickelig. Der Qt-Designer erlaubt viel zu viel, und ist gleichzeitig nicht einfach genug, um zB deinen custom Widgets ohne leicht Fehler machen zu können einzubinden. Da muss dann ein passender Klassennname an das Widget geschrieben werden, und an der Darstellung ändert sich nichts. Das ist IMHO Murks.

Vor allem ist code zu schreiben ohne mal konkret getestet zu haben, wie denn das zu handhaben ist, mit einfach einem gemockten setup (unsere User Researcher nutzen dazu Papier-Prototypen oder Framer oder LEGO und Knetgummi), eine ziemliche Garantie, viel für die Tonne zu schreiben. Denn dann ist irgendwas halbgares fertig, und keiner mag es benutzen.
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

__deets__ hat geschrieben: Donnerstag 19. November 2020, 14:10 Die Frage ist, wie deine Kollegen die Oberflächen definieren. Und auch dazu musst du eine Lösung finden.
Die sollen den QtDesigner selbst nutzen. Nur eben mit erweiterten StandartObjekten.
Z.B. der QPushButton wird durch eine eigene Version erweitert, in dem z.B. das ändern der Form/Farbe wenn Betriebsart nicht freigegen schon enthalten sind. Die Variablenanbindung will ich dann über Symbolfiles o.ä. umsetzen, die wiederum in einen eigenen, kleinen Dialog-Program erstellt werden.
Ob das so funktioniert, muss ich aber zugegebenermaßen erst noch testen.
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Warum auch immer das zweimal aufgetaucht ist - ich schrieb ja schon, wie ich darüber denke.
Treter_Peter
User
Beiträge: 11
Registriert: Montag 16. November 2020, 07:00

Ok, dann werde mal Konkret. Welchen Designer/Tool für die Kollegen sollte ich denn nehmen? Wie soll die Anbindung an Hardwarekomponenten erfolgen?
Ist mit dem Tool/Designer die Anforderung erfüllt, das die Kollegen nur die gewünschten Elemente auf die Öberfläche ziehen brauchen und die Verbindungsvariable auswählen bzw. anlegen müssen, ohne noch irgendwelchen Code tippen zu müssen?
2te Anforderung können z.B. Button's effekte im Designer zugeordnet werden wie z.B. "Image-Button", Schlagschatten, eigene Konturen etc., oder müssen die auch erst wieder mit evt. einer anderen Sprache Programmiert werden.
Wie sieht es mit Lizenz-Kosten für das/die Tool's aus? Brauchen die so erstellten GUI's eigene Runtimes?
Antworten