Dynamische Linien/Kreise in ein QTabWidget zeichnen.

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Hallo
Mit Qt-Designer habe ich ein GUI erstellt. In dieser verwende ich das QTabWidget.
Innerhalb eines Tab möche ich per Python-Code dynamische Linien/Kreise zeichnen. Geht das? Wie?
Hauptfrage: Wie zeichne ich per Python-Code einen Kreis in das QTabWidget?
Leider hab ich keine ähnlichen Sachen gefunden.

Danke schon mal...
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

QGraphicsView ist dein Freund.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Danke für den "Freund" QGraphicsView, denke das ist er. Nur wie verwende ich den in PythonCode?
Habe diverses gefunden aber so ganz hilfreich war das nicht. Und ehrlich gesagt, möchte ich mich bei schönem Wetter nicht den ganzen Tag damit beschäftigen und morgen sollte ich eine Lösung haben :cry:
Vielleicht kann das jemand gerade so aus dem Ärmel schütteln 8)

Ich habe mein Programm und GUI auf das Minimalste reduziert. Zwischen Zeile 74/77 sollte meine Grafik mit Koordinaten aus "data" zyklisch upgedatet werden.
Dabei soll in das GrafikView-Feld ein Kreis an den erhaltenen Koordinaten gezeichnet werden. Und immer der vorher gezeichnete Kreis gelöscht werden, so dass immer nur ein Kreis da ist. (bitte jetzt nicht über den Sinn nachdenken, es geht ums Prinzip...)

Danke und einen guten Sonntag

Code: Alles auswählen

import sys, os
from PyQt5 import QtWidgets, QtCore, uic, QtGui
from time import time, sleep
from threading import Thread, Event
from queue import Queue
#--------------------------------------------------------------------------------------------
#--- Threads
#--------------------------------------------------------------------------------------------
def generate_data(my_queue, my_event):
    while not my_event.is_set():
        # any code ...
        sleep(5.0)

def get_gps_data(pos_queue, fix_queue, gps_event):
    while not gps_event.is_set():   
        data_pos = 46.123, 8.123, 500.123
        data_fix = '01.01.1970 00:00:00', 0, 0, 0
        pos_queue.put(data_pos)
        fix_queue.put(data_fix)
        sleep(1.0)
#--------------------------------------------------------------------------------------------
#--- GUI
#--------------------------------------------------------------------------------------------
class Ui_MainWindow(QtWidgets.QMainWindow):
    def __init__(self, my_queue, my_event, pos_queue, fix_queue, gps_event, parent=None):

        super().__init__(parent)
        
        self.ui = uic.loadUi(R'C:\Python36\projects\gnss_navi\test.ui', self)

        self.my_queue = my_queue        
        self.thread_kill_my_event = my_event

        self.pos_queue = pos_queue        
        self.fix_queue = fix_queue        
        self.thread_kill_gps_event = gps_event

        # Variablen definieren und initialisieren
        self.a1 = 0.0
        self.b1 = 0.0
 
        # GUI-Slots einrichten
        self.ui.menu_file_exit.triggered.connect(self.on_menu_file_exit)
        self.ui.menu_help_over.triggered.connect(self.on_menu_help_over)

         # zyklisches Update der GUI
        self.tickertimer1 = QtCore.QTimer()
        self.tickertimer1.timeout.connect(self.update_gui)
        self.delay1 = 500 #ms
        self.tickertimer1.start(self.delay1)


    # GUI zyklisch updaten
    def update_gui(self):
        while not self.my_queue.empty():
            data = self.my_queue.get()
            print(data)
            
        while not self.pos_queue.empty():

            data = self.pos_queue.get()
            print(data)
            self.ui.label1.setText(str(data[0]) + ' | ' + str(data[1]) + ' | '  + str(data[2]))

        while not self.fix_queue.empty():
            data = self.fix_queue.get()
            print(data)
            self.ui.label2.setText(data[0])

#??????????????????????????????????????????????????????????????????????????????????
        # Grafik View updaten
        # self.ui.graphicsView.........................
#??????????????????????????????????????????????????????????????????????????????????

    # Menu Bedienung
    def on_menu_file_exit(self):
        self.thread_kill_my_event.set()
        self.thread_kill_gps_event.set()
        self.close()

    def on_menu_help_over(self):
        QtWidgets.QMessageBox.information(self, "über diese Programm")

#--------------------------------------------------------------------------------------------
#--- Hauptprogramm
#--------------------------------------------------------------------------------------------
if __name__ == "__main__":

    my_queue = Queue()
    pos_queue = Queue()
    fix_queue = Queue()

    my_event = Event()
    gps_event = Event()

    my_thread = Thread(target=generate_data, args=(my_queue, my_event, ))
    gps_thread = Thread(target=get_gps_data, args=(pos_queue, fix_queue, gps_event, ))

    my_thread.start()
    gps_thread.start()

    app = QtWidgets.QApplication(sys.argv)
    MainWindow = Ui_MainWindow(my_queue, my_event, pos_queue, fix_queue, gps_event)
    MainWindow.show()
    sys.exit(app.exec_())

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="windowModality">
   <enum>Qt::NonModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>799</width>
    <height>450</height>
   </rect>
  </property>
  <property name="sizePolicy">
   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
    <horstretch>0</horstretch>
    <verstretch>0</verstretch>
   </sizepolicy>
  </property>
  <property name="tabletTracking">
   <bool>false</bool>
  </property>
  <property name="windowTitle">
   <string>myGUI</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QTabWidget" name="tabWidget">
    <property name="enabled">
     <bool>true</bool>
    </property>
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>0</y>
      <width>781</width>
      <height>371</height>
     </rect>
    </property>
    <property name="sizePolicy">
     <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
      <horstretch>0</horstretch>
      <verstretch>0</verstretch>
     </sizepolicy>
    </property>
    <property name="font">
     <font>
      <family>Arial</family>
      <pointsize>18</pointsize>
     </font>
    </property>
    <property name="layoutDirection">
     <enum>Qt::LeftToRight</enum>
    </property>
    <property name="tabShape">
     <enum>QTabWidget::Rounded</enum>
    </property>
    <property name="currentIndex">
     <number>0</number>
    </property>
    <property name="iconSize">
     <size>
      <width>18</width>
      <height>20</height>
     </size>
    </property>
    <widget class="QWidget" name="tab">
     <attribute name="title">
      <string>Map</string>
     </attribute>
     <widget class="QGraphicsView" name="graphicsView">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>119</y>
        <width>770</width>
        <height>191</height>
       </rect>
      </property>
     </widget>
     <widget class="QLabel" name="label1">
      <property name="geometry">
       <rect>
        <x>10</x>
        <y>20</y>
        <width>681</width>
        <height>21</height>
       </rect>
      </property>
      <property name="font">
       <font>
        <pointsize>13</pointsize>
       </font>
      </property>
      <property name="text">
       <string>TextLabel1</string>
      </property>
     </widget>
     <widget class="QLabel" name="label2">
      <property name="geometry">
       <rect>
        <x>10</x>
        <y>50</y>
        <width>681</width>
        <height>21</height>
       </rect>
      </property>
      <property name="font">
       <font>
        <pointsize>13</pointsize>
       </font>
      </property>
      <property name="text">
       <string>TextLabel2</string>
      </property>
     </widget>
    </widget>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>799</width>
     <height>26</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuDatei">
    <property name="font">
     <font>
      <family>Arial</family>
      <pointsize>12</pointsize>
     </font>
    </property>
    <property name="title">
     <string>Datei</string>
    </property>
    <addaction name="menu_file_exit"/>
   </widget>
   <widget class="QMenu" name="menuHilfe">
    <property name="title">
     <string>Hilfe</string>
    </property>
    <addaction name="menu_help_over"/>
   </widget>
   <addaction name="menuDatei"/>
   <addaction name="menuHilfe"/>
  </widget>
  <widget class="QStatusBar" name="statusbar">
   <property name="font">
    <font>
     <family>Arial</family>
     <pointsize>12</pointsize>
    </font>
   </property>
  </widget>
  <action name="menu_file_com">
   <property name="text">
    <string>&amp;ComPort öffnen</string>
   </property>
   <property name="font">
    <font>
     <family>Arial</family>
     <pointsize>12</pointsize>
    </font>
   </property>
  </action>
  <action name="menu_datei_neu">
   <property name="text">
    <string>Neu</string>
   </property>
  </action>
  <action name="menu_help_over">
   <property name="text">
    <string>über</string>
   </property>
  </action>
  <action name="menu_file_exit">
   <property name="text">
    <string>&amp;Beenden</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections/>
</ui>
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich beschäftige mich den ganzen Tat mit Rennen fliegen mit meinem MicroKopter. Deine Hausaufgaben kann ich also nicht erledigen.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

__deets__ hat geschrieben: Sonntag 15. Dezember 2019, 13:00 Deine Hausaufgaben kann ich also nicht erledigen.
Danke - schon klar, dass ich Hausaufgaben selber zu erledigen habe. Es liegt aber vermutlich nur an 3-5 Code-Zeilen die ich mühsam aus dem Netz/Doku suchen muss. Habe ich auch gemacht und nichts passendes gefunden. Zudem ist es nur eine kleine Erweiterung und habe schon länger nicht mehr viel in Python gemacht. Darum gerade etwas blöd zumal ich ziemlich rasch die Erweiterung brauche. Mache gerne meine Hausaufgaben später...

Wie gesagt 3-5 Zeilen, die bestimmt jemand einfach so aus dem Ärmel schütteln kann/könnte.

Vielen Dank.
Benutzeravatar
sparrow
User
Beiträge: 4528
Registriert: Freitag 17. April 2009, 10:28

Was hast du denn schon probiert? Was geht nicht? Welche Doku hast du gelesen? Wo genau liegt deine Schwierigkeit bei der Umsetzung mit QGraphicsView?
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

sparrow hat geschrieben: Sonntag 15. Dezember 2019, 15:57 Wo genau liegt deine Schwierigkeit bei der Umsetzung mit QGraphicsView?
Diese liegt darin, dass ich nicht genau weiss nach was ich suchen muss - klar "QGraphicsView" gegoogelt liefert 152'000 Einträge.
Gefunden habe ich folgendes in https://doc.qt.io/qtforpython/PySide2/Q ... sView.html

Code: Alles auswählen

scene = QGraphicsScene()
scene.addText("Hello, world!")
view = QGraphicsView(scene)
view.show()
Ich denke in dieser Art muss auch das Kreis zeichnen gehen. Nur mein Problem: die GUI ist mit Designer erstellt. Darin in meinem Tab das Widget "QGraphicsView" eingefügt und diesem den ObjektName "graphicsView" gegeben.

Nun muss ich irgendwie mit diesem ObjektName in Python arbeiten.
Z.B. um einen Text/Label zu ändern verwende ich

Code: Alles auswählen

self.ui.label1.setText(str(data[0]) + ' | ' + str(data[1]) + ' | '  + str(data[2]))
also muss das für einen Kreis zu zeichnen doch auch irgendwie mit

Code: Alles auswählen

self.ui.graphicsView.???
gehen? vermutlich ein paar Zeilen mehr als diese eine.

Ich weiss Grundlagen fehlen, bzw vergessen weil nie richtig beherscht und schon lange nicht mehr gebraucht...
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das geht anders. Du musst mit der scene arbeiten, und ein Ellipsen item das du dir merken musst erzeugen. Und das kann verändert werden. https://doc.qt.io/qt-5/qgraphicsscene.html#addEllipse-1
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

also ich versuche es erstmal mit einer Linie (statisch) ist ja kein grosser Unterschied.
so habe ich das verstanden - oder eben nicht - sonst würde es funktionieren :-), bzw. fehlt mir noch die Übergabe an mein "ui.graphicView.???"

Code: Alles auswählen

        # Variablen definieren und initialisieren
        self.scene = QtWidgets.QGraphicsScene()
        self.graphicsView = QtWidgets.QGraphicsView(self.scene)
        self.line = QtWidgets.QGraphicsLineItem(10,10,80,99)
        self.scene.addItem(self.line)
        self.ui.graphicsView.???
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hab mich gerade erinnert - hier habe ich diverse Beispiele zum QGraphicsView beigesteuert. Da kommen auch Ellipsen vor. viewtopic.php?t=44384&start=30
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Hallo
Habe den genannten Link und das mit den Scenen mal studiert und auch sonst weiter gelesen und gesucht.

Unten habe ich mal aus dem Link den Code zusammengekürzt um mal so etwas zu zeichnen, was ich brauche. Das Resultat wäre okey, aber mein Unterschied ist immer noch, dass ich das GUI mit Qt Designer erstellt habe und darin das QGraphicsView-Widget nutze mit dem Objektnamen "graphicsView"

Nun verstehe ich das so, dass ich die scene-Sachen wie unten im Code verarbeiten muss, und am Schluss die scene an das Objekt graphicsView übergeben muss...
so ala dies hier etwa?

Code: Alles auswählen

self.ui.graphicsView() = scene()
Ist das komplett verkehrt?
Fehlermeldung: SyntaxError: can't assign to function call

Code: Alles auswählen

from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsEllipseItem, QGraphicsLineItem

class GraphicsWindow(QGraphicsView):
    def __init__(self, parent=None):
        super(GraphicsWindow, self).__init__(parent)
        scene = QGraphicsScene(self)
        self.setScene(scene)

        ellipse = QGraphicsEllipseItem(200,200,50,90)
        scene.addItem(ellipse)
        scene.addLine(20,20,300,200, QtCore.Qt.red)
        scene.addLine(180,20,200,300, QtCore.Qt.blue)

        scene.setSceneRect(0, 0, 400, 400)
        self.setCacheMode(QGraphicsView.CacheBackground)

def main():
    import sys
    app = QApplication(sys.argv)
    graphics_window = GraphicsWindow()
    graphics_window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja, offensichtlich. Raten hilft halt nicht. In dem Code den du selbst postest steht wie man eine scene in einen view steckt. Egal woher der nun kommt.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Danke
Richtig: Raten hilft da nicht weiter. Und meine Hausaufgaben sollt ihr auch nicht machen, auch erwarte ich nicht fertigen Code. Grundlagen und Dok. lese ich auch. Am besten lerne ich aber mit Beispielen. Und für das was ich vor habe, finde ich partout keine Beispiele. Am ehesten findet man noch was mit C-Code aber auch nicht wirklich. :roll:


Wie in meinem Code gepostet. Ändere ich folgende Zeile von ... nach... oder muss ich das nicht, weil ich das QtWidget im Qt-Designer schon erstellt habe.

Code: Alles auswählen

#von
class Ui_MainWindow(QtWidgets.QMainWindow):
    def __init__(self, my_queue, my_event, pos_queue, fix_queue, gps_event, parent=None):
        super().__init__(parent)
        self.ui = uic.loadUi(R'C:\Python36\projects\test.ui', self)

#nach
class Ui_MainWindow(QtWidgets.QMainWindow, QtWidgets.QGraphicsView):
    def __init__(self, my_queue, my_event, pos_queue, fix_queue, gps_event, parent=None):
        super().__init__(parent)
        self.ui = uic.loadUi(R'C:\Python36\projects\test.ui', self)
und nochmals die Frage. Wie bringe ich das erstellte Objekt "QGraphicsView" in Qt-Designer mit dem Objektnamen "graphicsView" ins Spiel?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dein eigener Code beinhaltet den Zugriff auf per ui Dateien erzeugter Widgets. Der GraphicsView ist in dieser Beziehung kein bisschen anders. Wieso du das da kannst, aber dann dann wie oben abstruse Syntax Fehler zusammenklöppelst, wenn es um den GraphicsView geht, bleibt dein Geheimnis.

Und wenn du Qt benutzt, wird du meistens C++ Beispiele finden. Denn das ist nunmal ein c++ Framework. Und Beispiele habe ich dir gegeben. Die wirklich simplen Methodenaufrufen, wie sie sich aus der Dokumentation ergeben, und auch schon in Python in dem von mir gezeigten Code übersetzt wurden, selbst hinzuschreiben, kann dir keiner abnehmen. Erst recht nicht im Urlaub mit einem iPad zum tippen.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und noch ein Nachtrag: die oben gezeigte zusätzliche Ableitung vom GraphicsView in deinem Code Schnipsel ist unnötig. Der Designer hat davon eine Instanz erzeugt (oder kann das zumindest, kenne das Ui file ja nicht). Es muss nichts abgeleitet werden. Das ist Teil des von Atalantore begonnenen Beispiels, das er auch irgendwo gefunden hat. Aber nicht notwendig für dich.
Antworten