QPushButton in QGraphicsView/Scene darstellen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Tyll
User
Beiträge: 21
Registriert: Dienstag 6. August 2013, 12:52

Hallo Leute,

Also ich habe ein Programm geschrieben welches Kamerabilder von einem Stream abruft und diese dann darstellt.
Außerdem ist mit diesem Programm möglich die Kamera zu Steuern (Zoomen, links/rechts Bewegung).

Jetzt möchte ich in dem Kamerabild halb durchsichtige Buttons platzieren,mit welchen die besagte Steuerung möglich ist.
Mein Problem ist das ich die Buttons nicht in der Vordergrund bekomme, und diese immer von dem Kamerabild überzeichnet werden.

Zur Darstellung des Bildes verwende ich eine QGraphicsScene

Code: Alles auswählen

                        self.videoView = GraphicsView(self)
			
			self.videoScene = QGraphicsScene(self)

			self.Button = QPushButton(self)

			self.videoView.setScene(self.videoScene)
			self.videoScene.addWidget(self.Button)
Zuletzt geändert von Anonymous am Donnerstag 3. Juli 2014, 10:44, insgesamt 4-mal geändert.
Grund: Quelltext in Code-Tags gesetzt.
Benutzeravatar
Madmartigan
User
Beiträge: 200
Registriert: Donnerstag 18. Juli 2013, 07:59
Wohnort: Berlin

QGraphicsProxyWidget wird dir weiterhelfen. Das ist genau für solche Zwecke gedacht.
Tyll
User
Beiträge: 21
Registriert: Dienstag 6. August 2013, 12:52

Auf das bin ich auch schon gestoßen aber entweder habe ich das Falsch benutzt oder es funktioniert bei mir nicht!

Ich hab mich dabei an dieses Beispiel gehalten:
http://srinikom.github.io/pyside-docs/P ... idget.html

Mein Code

Code: Alles auswählen

self.videoView = GraphicsView(self)

			self.videoScene = QGraphicsScene(self)

			self.Button = QPushButton(self)
			proxy = QGraphicsProxyWidget()
			proxy = self.videoScene.addWidget(self.Button)


			self.signalSlot.connect(self.guiupdate)	

			self.videoView.setScene(self.videoScene)
			self.videoScene.addWidget(self.Button)
			
			#Layout Settings
			theLayout = QHBoxLayout()
			theLayout.addWidget(self.videoView)


			self.setLayout(theLayout)

			self.show()

Benutzeravatar
Madmartigan
User
Beiträge: 200
Registriert: Donnerstag 18. Juli 2013, 07:59
Wohnort: Berlin

Ich bin absolut sicher, dass es bei dir funktioniert. Es ist eher sehr unwahrscheinlich, dass alle Qt Klassen funktionieren, der QGraphicsView dann aber fehlerhaft sein soll. ;-)

Code: Alles auswählen

self.Button = QPushButton(self)
Du setzt das parent des Buttons auf self, das sollte dir eigentlich eine Fehlermeldung in der Console geben. Bei mir wirft dein Code Folgendes:
QGraphicsProxyWidget::setWidget: cannot embed widget 0x2398920 which is not a toplevel widget, and is not a child of an embedded widget
Lass den parent Parameter im Konstruktor weg, sonst funktioniert das Embedding nicht.

Code: Alles auswählen

proxy = QGraphicsProxyWidget()
Das ist aufgrund seiner nachfolgenden Zeile unnötig.

Code: Alles auswählen

self.videoScene.addWidget(self.Button)
Das macht keinen Sinn, denn der Button ist ja bereits in der Scene.
Tyll
User
Beiträge: 21
Registriert: Dienstag 6. August 2013, 12:52

Mh langsam fange ich an an meinen Fähigkeiten zu zweifeln ich hab die Sachen geändert und auch noch andere Sache ausprobiert, aber es funktioniert immer noch nicht. Vielleicht liegt es auch an etwas anderem also werde ich mal den anderen Code der das Zeichen betrifft hinzufügen.

Was ich halt auch nicht verstehe wie ich das QGraphicsProxyWidget bei diesem "proxy = self.videoScene.addWidget(self.Button)" befehl verwende wenn ich vorher nie so ein Objekt erstellt habe ?

Code: Alles auswählen


import os
import time
import rospy
import rospkg
import sys
import py_fkie
import tf
import math
from sensor_msgs.msg import Image
from camera_msgs_fkie.msg import ZoomStatus, ZoomCommand
from geometry_msgs.msg import PoseStamped, Pose

from py_fkie.publisher_proxy import PublisherProxy
from py_fkie.subscriber_proxy import SubscriberProxy

from python_qt_binding.QtCore import Qt, pyqtSignal
from python_qt_binding.QtGui import QLabel,QPushButton, QWidget, QHBoxLayout, QColor,QPen, QPixmap ,QBrush, QImage, QGraphicsView ,QGraphicsScene, QGraphicsItem, QGraphicsProxyWidget






class VideoPluginWidget(QWidget):
	
		videoScene 	= None
		videoView 	= None
		imageData 	= None
		Button 		= None

		signalSlot 	= pyqtSignal()

		__crosshairVisible = True
		__subscriber_video = None
		"""docstring for MyPluginWidget"""
		def __init__(self):
	
			super(VideoPluginWidget, self).__init__()

			#Create important Objekts
			self.videoView = GraphicsView(self)

			self.videoScene = QGraphicsScene(self)

			self.Button = QPushButton()
			proxy = self.videoScene.addWidget(self.Button)


			self.signalSlot.connect(self.guiupdate)	

			self.videoView.setScene(self.videoScene)
			
			#Layout Settings
			theLayout = QHBoxLayout()
			theLayout.addWidget(self.videoView)


			self.setLayout(theLayout)

			self.show()

			
			self.listener()
	
			
			pass

def guiupdate(self):
			#print "guiupdate"
			#print self.imageData.encoding
			format = self.img_format_table[self.imageData.encoding]

   			picture = QImage(self.imageData.data,self.imageData.width,self.imageData.height,format)
   			picture = picture.scaled(self.videoView.width() ,self.videoView.height(),Qt.KeepAspectRatio)
   			#picture = picture.rgbSwapped()
   			self.videoScene.clear()
   			self.videoScene.addPixmap(QPixmap().fromImage(picture))
   			


   			if self.__crosshairVisible:
   				self.drawCrosshairs()
   				pass
   			
   			self.videoView.setScene(self.videoScene)
   			
   			self.videoView.show()
			pass


Benutzeravatar
Madmartigan
User
Beiträge: 200
Registriert: Donnerstag 18. Juli 2013, 07:59
Wohnort: Berlin

Der Code ist leider nicht wirklich gut. Davon abgesehen, dass ich ihn nicht testen kann, da ich nicht über die entsprechenden Kamera Module verfüge, zweifle ich stark daran, dass es überhaupt in der Form ausführbar wäre. Oder du hast ihn unvollständig gepostet!?
  • Bei jedem Neuzeichnen setScene() auszuführen, ist keine gute Idee, schon aus reinen Gründen der Performance.
  • videoScene, videoView, imageData und Button sind nicht im Konstruktor deklariert, sondern im Klassen-Header. Ob das Ergebnis wirklich das ist, was du möchtest?
  • Kein camelCase für Bezeichner, PEP8 schreibt es so vor: video_scene, video_view etc.
  • signalSlot wird zwar gebunden, aber wo wird es emittiert?
  • pass macht hier, wo du es verwendet hast, keinen Sinn bzw. ist überflüssig.
  • QImage- und vor allem QPixmap - Instantiierungen beim Neuzeichnen solltest du auf jeden Fall vermeiden.
Hier ist ein minimales Beispiel:

Code: Alles auswählen

import sys
from python_qt_binding.QtCore import Qt, pyqtSignal
from python_qt_binding.QtGui import QApplication, QWidget, QHBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsProxyWidget, QPushButton


class VideoPluginWidget(QGraphicsView):
    
    def __init__(self, parent):
        super(VideoPluginWidget, self).__init__(parent)
        
        self.setScene(QGraphicsScene())
        
        self._crosshair_visible = True
        self._subscriber_window = None


class MainWindow(QWidget):

    def __init__(self):
        super(MainWindow, self).__init__()
        
        self.video_view = VideoPluginWidget(self)
        self.a_useful_button = QPushButton("Hello World")
        
        self.proxy = self.video_view.scene().addWidget(self.a_useful_button)
        
        self.setLayout(QHBoxLayout())
        self.layout().addWidget(self.video_view)                       
        
        
if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())
Natürlich würde ich beide Klassen trennen und nicht in einer Datei pflegen, aber das bleibt dir überlassen.
Ich hoffe das hilft dir weiter.
Antworten