I create a resizable QGraphicsRectItem
, I am able to resize it just fine, but I am not able to update the position of the new resized item in its scene
import typing
import sys
from PyQt5.QtGui import QPen, QBrush, QColor, QResizeEvent
from PyQt5.QtCore import QRectF, QSize
from PyQt5.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsItem, QGraphicsRectItem, QMainWindow, QVBoxLayout, QWidget
class ResizableRect(QGraphicsRectItem):
def __init__(self, *args):
super().__init__(*args)
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setPen(QPen(QBrush(QColor('blue')), 5))
self.selected_edge = None
self.click_pos = self.click_rect = None
def mousePressEvent(self, event):
""" The mouse is pressed, start tracking movement. """
self.click_pos = event.pos()
self.newY = self.pos().y()
rect = self.rect()
if abs(rect.left() - self.click_pos.x()) < 5:
self.selected_edge = 'left'
elif abs(rect.right() - self.click_pos.x()) < 5:
self.selected_edge = 'right'
elif abs(rect.top() - self.click_pos.y()) < 5:
self.selected_edge = 'top'
elif abs(rect.bottom() - self.click_pos.y()) < 5:
self.selected_edge = 'bottom'
else:
self.selected_edge = None
self.click_pos = event.pos()
self.click_rect = rect
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
""" Continue tracking movement while the mouse is pressed. """
# Calculate how much the mouse has moved since the click.
pos = event.pos()
x_diff = pos.x() - self.click_pos.x()
y_diff = pos.y() - self.click_pos.y()
# Start with the rectangle as it was when clicked.
rect = QRectF(self.click_rect)
# Then adjust by the distance the mouse moved.
if self.selected_edge is None:
rect.translate(x_diff, y_diff)
elif self.selected_edge == 'top':
rect.adjust(0, y_diff, 0, 0)
# Test when resize rectangle upward; not working properly for now
if y_diff < 0:
newCenter = (rect.bottom() - pos.y()) / 2
self.newY = self.pos().y() - newCenter
elif self.selected_edge == 'left':
rect.adjust(x_diff, 0, 0, 0)
elif self.selected_edge == 'bottom':
rect.adjust(0, 0, 0, y_diff)
elif self.selected_edge == 'right':
rect.adjust(0, 0, x_diff, 0)
# Also check if the rectangle has been dragged inside out.
if rect.width() < 5:
if self.selected_edge == 'left':
rect.setLeft(rect.right() - 5)
else:
rect.setRight(rect.left() + 5)
if rect.height() < 5:
if self.selected_edge == 'top':
rect.setTop(rect.bottom() - 5)
else:
rect.setBottom(rect.top() + 5)
# Finally, update the rect that is now guaranteed to stay in bounds.
self.setY(self.newY)
self.setRect(rect)
def mouseReleaseEvent(self, event): # for printing only i.e., after resizing
print(f"item.pos(): {self.pos()}")
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
central = QWidget(self)
self.setCentralWidget(central)
self.rect = ResizableRect(-100, -50, 200, 100)
scene = QGraphicsScene(0, 0, 300, 300)
scene.addItem(self.rect)
self.view = QGraphicsView(central)
self.view.setScene(scene)
layout = QVBoxLayout(central)
layout.addWidget(self.view)
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
main()
For now, I am testing updating item.pos()
when resize upward only, It is not working properly and I need advice to correct this implementation. In mouseMoveEvent()
, when self.selected_edge == top
, I calculate the center of the new rectangle. Then I compute the newY
value that I will use to update the item's position in scene later on, i.e., self.setY(self.newY)
. The result is that the item keeps moving upward as I resize. Where did I do wrong?
Thank you for helping!