I'm writing a simple gui with a QGraphicsScene
. Inside this scene i have 2 simple XY axis and I have a function to retrieve the position of my mouse click on the scene.
I added a simple movable ellipse to my scene and I'm retrieving it's position (at the moment it's only an on click detection, later I will implement a signal for its movement)
Here's the code:
View.py:
import math
import sys
from PySide2.QtCore import Signal, QPointF
from PySide2 import QtCore
from PySide2.QtGui import QColor, QPainterPath
from PySide2.QtWidgets import (QGraphicsItem,
QApplication,
QGraphicsScene,
QGraphicsView,
QHBoxLayout,
QMainWindow,
QPushButton,
QWidget,
QSizeGrip
)
from PySide2 import QtGui
from PySide2.QtGui import QIcon
class GraphicsScene(QGraphicsScene): # Used to indicate inheritance from parent class
clicked = Signal(QPointF)
def drawBackground(self, painter, rect):
l = min(rect.width(), rect.height()) / 30
x_left = QPointF(rect.left(), 0)
x_right = QPointF(rect.right(), 0)
painter.drawLine(x_left, x_right)
right_triangle = QPainterPath()
right_triangle.lineTo(-0.5 * math.sqrt(3) * l, 0.5 * l)
right_triangle.lineTo(-0.5 * math.sqrt(3) * l, -0.5 * l)
right_triangle.closeSubpath()
right_triangle.translate(x_right)
painter.setBrush(QColor("black"))
painter.drawPath(right_triangle)
y_top = QPointF(0, rect.top())
y_bottom = QPointF(0, rect.bottom())
painter.drawLine(y_top, y_bottom)
top_triangle = QPainterPath()
top_triangle.lineTo(.5*l, -0.5 * math.sqrt(3) * l)
top_triangle.lineTo(-.5*l, -0.5 * math.sqrt(3) * l)
top_triangle.closeSubpath()
top_triangle.translate(y_bottom)
painter.setBrush(QColor("black"))
painter.drawPath(top_triangle)
def mousePressEvent(self, event):
sp = event.scenePos()
self.clicked.emit(sp)
super().mousePressEvent(event)
class MyView(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("8D.me")
self.setFixedSize(800, 500)
self.btn = QPushButton("test2")
self.btn.setStyleSheet( "color: white; border-radius: 4px; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); background: rgb(66, 184, 221); min-width:100px;min-height:30px")
self.view = QGraphicsView()
print(self.view.size())
self.view.scale(1, -1)
self.scene = GraphicsScene()
self.view.setScene(self.scene)
self.setIcon()
self.ellipse=self.scene.addEllipse(10,10,10,10)
self.ellipse.setFlag(QGraphicsItem.ItemIsMovable)
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QHBoxLayout(central_widget)
layout.addWidget(self.btn)
layout.addWidget(self.view)
#flags = QtCore.Qt.WindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
#self.setWindowFlags(flags)
self.scene.clicked.connect(self.handle_clicked)
def handle_clicked(self, p):
print("position",self.ellipse.pos())
print("clicked", p.x(), p.y())
print(self.view.size())
# Insert methods for creating/adding elements to the default view.
# Mehods....
def setIcon(self):
appIcon = QIcon('logo')
self.setWindowIcon(appIcon)
#Insert here the public methods called by the Controller to update the view
main.py:
import View
#import Model
#import Controller
#Useful example: https://realpython.com/python-pyqt-gui-calculator/
def main():
"""Main function."""
# Create an instance of QApplication
app = QApplication([])
# Show the GUI
mainwindow =View.MyView()
mainwindow.show()
# Create instances of model and controller
#model = Model.myModel()
#Controller.myController(view=mainwindow,model=model)
return app.exec_()
if __name__ == '__main__':
main()
EDIT: I added also the main
code. I have the View in a separate file since I am using a MVC design pattern.
My GUI looks like this:
And it works so far.
The problem is if I move the ellipse (which moves correctly) my XY axis moves too, and I can't figure out why.
For example this is how my GUI changes if I move the ellipse toward the upper right angle:
What's the problem? How do I "fix" the XY axis? I would like to keep my axis still and move only the ellipse inside the scene region.
I solved the problem following this: https://forum.qt.io/topic/48564/force-qgraphicsview-size-to-match-qgraphicsscene-size/7
Basically i added the following lines to my code:
self.view.setFixedSize(600,480)
self.view.setSceneRect(-300,-220,600,480)
self.view.fitInView(0,0,600,480, Qt.KeepAspectRatio)
So the new View.py is:
import math
import sys
from PySide2.QtCore import Signal, QPointF, Qt
from PySide2 import QtCore
from PySide2.QtGui import QColor, QPainterPath
from PySide2.QtWidgets import (QGraphicsItem,
QApplication,
QGraphicsScene,
QGraphicsView,
QHBoxLayout,
QMainWindow,
QPushButton,
QWidget,
QSizeGrip
)
from PySide2 import QtGui
from PySide2.QtGui import QIcon
class GraphicsScene(QGraphicsScene): # Used to indicate inheritance from parent class
clicked = Signal(QPointF)
def drawBackground(self, painter, rect):
#print('Pinto rect',rect.width(),rect.height())
l = min(rect.width(), rect.height()) / 30
#print('printo l',l)
#Qui c'è il bug. La funzione drawbackground viene chiamata a ogni modifica della scene.
#Lo starting point del drawing della line cambia nel tempo, ecco perchè mi si spostano gli assi
x_left = QPointF(rect.left(), 0)
x_right = QPointF(rect.right(), 0)
print('printo gli x',rect.left(),rect.height())
painter.drawLine(x_left, x_right)
right_triangle = QPainterPath()
right_triangle.lineTo(-0.5 * math.sqrt(3) * l, 0.5 * l)
right_triangle.lineTo(-0.5 * math.sqrt(3) * l, -0.5 * l)
right_triangle.closeSubpath()
right_triangle.translate(x_right)
painter.setBrush(QColor("black"))
painter.drawPath(right_triangle)
y_top = QPointF(0, rect.top())
y_bottom = QPointF(0, rect.bottom())
painter.drawLine(y_top, y_bottom)
top_triangle = QPainterPath()
top_triangle.lineTo(.5*l, -0.5 * math.sqrt(3) * l)
top_triangle.lineTo(-.5*l, -0.5 * math.sqrt(3) * l)
top_triangle.closeSubpath()
top_triangle.translate(y_bottom)
painter.setBrush(QColor("black"))
painter.drawPath(top_triangle)
def mousePressEvent(self, event):
sp = event.scenePos()
self.clicked.emit(sp)
super().mousePressEvent(event)
class MyView(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("8D.me")
self.setFixedSize(800, 500)
self.btn = QPushButton("test2")
self.btn.setStyleSheet( "color: white; border-radius: 4px; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); background: rgb(66, 184, 221); min-width:100px;min-height:30px")
self.view = QGraphicsView()
print(self.view.size())
self.view.setFixedSize(600,480)
self.view.setSceneRect(-300,-220,590,470)
self.view.fitInView(0,0,600,480, Qt.KeepAspectRatio)
self.view.scale(1, -1)
self.scene = GraphicsScene()
self.view.setScene(self.scene)
self.setIcon()
self.ellipse=self.scene.addEllipse(-5,-5,10,10)
self.ellipse.setFlag(QGraphicsItem.ItemIsMovable)
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QHBoxLayout(central_widget)
layout.addWidget(self.btn)
layout.addWidget(self.view)
#flags = QtCore.Qt.WindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
#self.setWindowFlags(flags)
self.scene.clicked.connect(self.handle_clicked)
def handle_clicked(self, p):
print("position",self.ellipse.pos())
print("clicked", p.x(), p.y())
print(self.view.size())
# Insert methods for creating/adding elements to the default view.
# Mehods....
def setIcon(self):
appIcon = QIcon('logo')
self.setWindowIcon(appIcon)
#Insert here the public methods called by the Controller to update the view