Rotierendes QGraphicsView

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
bob
User
Beiträge: 8
Registriert: Samstag 3. August 2013, 11:13

Moin,

ich versuche schon seit einiger Zeit ein rundes, um den Mittelpunkt rotierendes QGraphicsView zu erstellen. (Es soll dann als Overlay dienen) Das Problem ist: es "eiert" um den Mittelpunkt und ich bekomme es einfach nicht zentreiert und kann das Problem nicht erkennen.

Frage: Wie bekomme ich den Rotationsmittelpunkt in der Abbildung zentriert?
Hat hier jemand eine Idee?

Code: Alles auswählen

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Overlay(QWidget):
	def __init__(self,parent=None):
		QWidget.__init__(self,parent)
		self.height = parent.size().height()/2
		self.width = parent.size().width()/2
		self.setGeometry(80,20,self.height, self.height)
		
		scene = QGraphicsScene(0,0,self.height,self.height)
		scene.addItem(self.create_letter())
		
		scene.addEllipse(0, 0, self.height ,self.height, QPen(Qt.NoPen), QBrush(QColor(0,129,94,40)))
		
		self.view = QGraphicsView(self)
		self.view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
		self.view.setStyleSheet("background: rgba(100,100,100,50); border: transparent")
		
		self.view.setScene(scene)
		
	def create_letter(self):
		n = self.height
		group = QGraphicsItemGroup()
		txt = QGraphicsTextItem("N")
		txt.setFont(QFont("Arial", 20))
		txt.translate(n/2-14, 30)
		group.addToGroup(txt)
		
		txt = QGraphicsTextItem("E")
		txt.setFont(QFont("Arial", 20))
		txt.translate(n-30, n/2 - 13)
		txt.setRotation(90)
		group.addToGroup(txt)
		
		txt = QGraphicsTextItem("S")
		txt.setFont(QFont("Arial", 20))
		txt.translate(n/2+13, n - 30)
		txt.setRotation(180)
		group.addToGroup(txt)
		
		txt = QGraphicsTextItem("W")
		txt.setFont(QFont("Arial", 20))
		txt.translate(30, n/2 + 16)
		txt.setRotation(270)
		group.addToGroup(txt)
		
		return group
	
	def rot_compass(self, angle=0):
		self.view.rotate(80)

class Main(QWidget):
	def __init__(self):
		QWidget.__init__(self)
		self.setGeometry(300,300,600,400)
		
		self.overlay = Overlay(self)
		
		self.t()
		
	def paintEvent(self, event):
		path = QPainterPath()
		path.addRoundRect(0,0,500,380,25)
		
		painter = QPainter(self)
		pen = QPen(QColor(90,90,90))
		pen.setWidth(2)
		painter.setBrush(QColor(248,241,225))
		painter.setPen(pen)
		painter.drawPath(path)
		
	def t(self):
		print("Timer start")
		self.timer = QTimer(self)
		self.connect(self.timer, SIGNAL("timeout()"), self.overlay.rot_compass)
		self.timer.start(1000)


app = QApplication(sys.argv)
m = Main()
m.show()
sys.exit(app.exec_())
Mit freundlichen Grüßen,

Bob
Zuletzt geändert von Anonymous am Samstag 3. August 2013, 12:21, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
bob
User
Beiträge: 8
Registriert: Samstag 3. August 2013, 11:13

Guten Abend liebes Forum,

weiß den keiner Rat, oder konnte ich mein Anliegen nicht genau genug darlegen?
Hat sonst denn jemand eine andere Idee wie ich mein Overlay erstellt bekomme? Ich dachte nur mit dem QGraphicsView ist das am Resourcenschonendsten.

Mfg
bob
lunar

@bob Ein GraphicsView transformiert standardmäßig um das Zentrum der Szene. Das Problem liegt bei Dir eher nicht im GraphicsView selbst, sondern im ziemlich abstrusen Layout Deiner Fenster. Ich nehme mal an, dass der GraphicsView eben nicht genau in der Mitte angezeigt wird, was dann zum Eindruck führt, die Transformation der Szene wäre fehlerhaft.

Nutze doch bitte Layouts statt fester Größenangaben, dehne mithilfe des Layouts den GraphicsView über die gesamte Größe des Overlaywidgets aus, zentriere dann die Szene um das zentrale Item. Konsultiere die Qt-Dokumentation zu den Details, insbesondere die Abschnitte über Layouts, und über die verschiedenen Koordinatensystem in einem QGraphicsView.
bob
User
Beiträge: 8
Registriert: Samstag 3. August 2013, 11:13

Danke für den Hinweis.
Dann werde ich das mal so probieren.

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

Ich halte es zwar für unnötig, in deinem Falle den ganzen View rotieren zu wollen, aber wer weiß, was du damit letztendlich planst. :K

Prinzipiell würde ich eher das Item/die Group rotieren. Damit das Ganze dann auch konzentrisch rotiert, bietet sich die Verwendung von QGraphicsItem.setTransformOriginPoint (qreal x, qreal y) an. Damit kannst du die Rotationsachse einfach ins Zentrum deiner Group setzen und diese dann um sich selbst rotieren lassen. Um das ganze auch wirklich zu verstehen, ist es ratsam, sich (wenigstens!) die Basics über Matrizen und Verwendung von verschiedenen Koordinatensystemen anzueignen.

Falls das Ganze in Richtung "Spiel" gehen sollte, rate ich dir dringend von festen/absoluten Größenangaben und Positionen ab. Wie Lunar schon sagte, für deine UI nutzt du am besten Layouts, die sind sehr mächtig und nehmen dir unglaublich viel ab. Für den GraphicsView gibt es unzählige Beispiele im Netz, vielleicht schaust du dir die an und adaptierst davon.
bob
User
Beiträge: 8
Registriert: Samstag 3. August 2013, 11:13

@Madmartigan Danke für den Tip. Ich rotiere die Group mit setRotation(), was mit QGraphicsItem.setTransformOriginPoint (qreal x, qreal y) wunderbar funktioniert. Warum das mit dem einfachen rotate() nicht funktioniert - wie auch in meinem obigen Versuch - ist mir zwar immer noch nicht klar, vermute aber das liegt an meinem Unvermögen die verschiedenen Koordinatensysteme in einklang zu bringen und den Ursprung zu setzen.

Es soll tatsächlich nur eine Kompassrose werden, die dann als Overlay gesetzt wird, und entsprechend den einfließenden Daten eben ständig rotieren muss. Der Umbau in Layouts erfolgt schon Stück für Stück, nur finde ich es persöhnlich verständlicher, wenn ich beim Aufbau des Widgets zunächst mal absolute Werte habe, bei deren Veränderung ich dann auch den Effekt sehe.
Antworten