I am new to PyQt5 and I am programming a small Logo-Editor for generating simple Logos. I use PyQt5 Version: 5.15.7 in Python 3.10 all together in PyCharm PyCharm 2022.1.3 (Community Edition) on Windows 11.
I am using the QGraphicsScene to draw all my lines and then I can customize length, color, zValue, etc of the created logo. I use MouseEvents to click on one QGraphicsItem and so I am able to change the color and zValue. That's just for the introduction.
The Problem I have is on creating a diagonal line. Then the resulting default boundingRect() of the QGraphicsItem is much too big, and this makes problems when I have several lines on my Scene, which I would like to select with the mouse. Then the clicking on one Item results in the selection of a nearby diagonal line item.
Here is a screenshot of what I mean: Diagonal line with selection box (black), the red line shows the boundingRect or shape I would like to use)
I made a small QtApp to demonstrate my problem:
from PyQt5.QtWidgets import (
QApplication,
QWidget,
QGraphicsView,
QGraphicsScene,
QGraphicsSceneMouseEvent,
QGraphicsItem,
QTextEdit,
)
from PyQt5.QtGui import QPolygonF, QPen, QTransform
from PyQt5.QtCore import Qt, QPointF, QLineF
import sys
# Own QGraphicsScene Subclass with some drawings and points as example
class MyScene( QGraphicsScene ):
def __init__( self ):
super().__init__( -300, -300, 600, 600 )
# Set QPen for drawings
self.my_pen = QPen( Qt.darkBlue )
self.my_pen.setWidthF( 15 )
self.my_pen.setCapStyle( Qt.RoundCap )
# Set Start- & End-Points for my line
self.start = QPointF( 0, 0 )
self.end = QPointF( 200, 200 )
# Draw a line (boundingRect is created automatically)
self.lin = self.addLine( QLineF( self.start, self.end ), self.my_pen )
self.lin.setFlags( QGraphicsItem.ItemIsSelectable )
# Change Pen-Setttings for new Item
self.my_pen.setWidthF( 2 )
self.my_pen.setColor( Qt.darkRed )
self.my_pen.setStyle( Qt.DotLine )
# Draw polygon, which I would like to apply on my line as a bounding rect
self.poly = self.addPolygon(
QPolygonF(
[
QPointF( 20, -30 ),
QPointF( -30, 20 ),
QPointF( 180, 230 ),
QPointF( 230, 180 ),
] ),
self.my_pen
)
# Reimplementing the mousePressEvent for catching some information
def mousePressEvent( self, sceneEvent: QGraphicsSceneMouseEvent ):
# Get position and item at the position of the event
#### EDIT after Comments from musicamente
#### FIRST pass the event to the original implementation of the mousePressEvent
super().mousePressEvent( sceneEvent )
#### and THEN get the position of the item at the event-scenePosition
pp = sceneEvent.scenePos()
current_item = self.itemAt( pp, QTransform() )
# So if there is an item at the clicked position, then write some information
if current_item is not None:
text = f"scenePos() = {pp} \n"\
f"screenPos() = {sceneEvent.screenPos()}\n"\
f"current_item.boundingRect() = "\
f"{current_item.boundingRect()}\n"\
f"current_item.shape() = {current_item.shape()}\n"\
f"current_item.shape().boundingRect() = "\
f"{current_item.shape().boundingRect()}\n"\
f"current_item.shape().controlPointRect() = "\
f"{current_item.shape().controlPointRect()}\n"\
f""
my_gui.my_textedit.setText( text )
current_item.mousePressEvent( sceneEvent )
# The Class/Widget for placing the view and a QTextEdit
class MyGui( QWidget ):
def __init__( self ):
super().__init__()
self.setGeometry( 50, 50, 800, 800 )
self.my_scene = MyScene()
self.my_view = QGraphicsView( self )
self.my_view.setScene( self.my_scene )
# QTextEdit for displaying some stuff for debuggin
self.my_textedit = QTextEdit( self )
self.my_textedit.setGeometry( 0, 610, 600, 150 )
# Starting the App
my_app = QApplication( sys.argv )
my_gui = MyGui()
my_gui.show()
sys.exit( my_app.exec() )
In the textEdit I see roughly, what I have to do:
current_item.shape() = <PyQt5.QtGui.QPainterPath object at 0x00000213C8DD9A10>
current_item.shape().boundingRect() = PyQt5.QtCore.QRectF(-30.707106781186553, -30.999999999983665, 261.70710678117024, 261.70710678117024)
current_item.shape().controlPointRect() = PyQt5.QtCore.QRectF(-30.707106781186553, -31.09763107291604, 261.8047378541026, 261.8047378541026)
I found some questions here addressing the same problem, but they are in C++
- How to minimize Bounding Rect in qt?
- Customizing shape of bounding rect
- And also one in Python Drawing shapes using PYQT5 but honestly I don't know how to transfer this to my "smaller" problem I have.
I understand that I have to reimplement the shape() of my line... BUT I don't have a clue how to do this in my example...
Can somebody give me a hint, how to solve this?
I haven't found some information on the internet regarding problems like this. If you know any Websites with tutorials on these topics, I would be very pleased to know them. Or a book dealing with Graphics in PyQt5 would be also great.
Thanks in advance :-)