I have a problem where when I resize one of the “Test_Boxes”, all the other existing Text_Boxes resize too and any that get created afterwards get created with the resized size.
It seems like they are all sharing the same QRect but they shouldn’t be.
Please help.
Code:
import sys, sip, random
from PyQt4.QtCore import *
from PyQt4.QtGui import *
PAGESIZE_LST = [612, 792]
POINT_SIZE = 10
CURSOR_SIZE = 2 * POINT_SIZE
BORDER_WIDTH = 0.5 * POINT_SIZE
def Cursor_Pos(item):
# Get mouse position relative to this item
cursor_pos = item.scene().parent().mapFromGlobal(QCursor.pos())
cursor_pos = item.scene().views()[0].mapToScene(cursor_pos)
cursor_pos = item.mapFromScene(cursor_pos)
return cursor_pos
class Test_Box(QGraphicsItem):
""" Group box that groups the various stages """
# Constants
WIDTH = 70 * POINT_SIZE
HEIGHT = 100 * POINT_SIZE
RECT = QRectF(0, 0, WIDTH, HEIGHT)
CORNER_RADIUS = 1.5 * POINT_SIZE
FONT_SIZE = 4 * POINT_SIZE
BORDERRECT_PAD = 4 * POINT_SIZE
def __init__(self, position, parent=None):
super(Test_Box, self).__init__(parent)
# Vars
self.resize_sections= None
self.resize_pos = None
self.rect = Test_Box.RECT
# Settings
self.setFlags( self.flags() |
QGraphicsItem.ItemIsSelectable |
QGraphicsItem.ItemIsMovable |
QGraphicsItem.ItemIsFocusable )
def boundingRect(self):
return self.rect.adjusted(-BORDER_WIDTH/2,-BORDER_WIDTH/2,BORDER_WIDTH/2,BORDER_WIDTH/2)
def paint(self, painter, option, widget):
# Draw Box
# Inner and outer rect to display drag-expand's clickable area
outer_rect = self.boundingRect().adjusted(-Test_Box.BORDERRECT_PAD,-Test_Box.BORDERRECT_PAD,CURSOR_SIZE+Test_Box.BORDERRECT_PAD,CURSOR_SIZE+Test_Box.BORDERRECT_PAD)
inner_bound = (BORDER_WIDTH/2 + (Test_Box.CORNER_RADIUS/2)) # Get corner offset due to rounded corners
inner_rect = self.boundingRect().adjusted((CURSOR_SIZE+inner_bound)+Test_Box.BORDERRECT_PAD, (CURSOR_SIZE+inner_bound)+Test_Box.BORDERRECT_PAD, -inner_bound-Test_Box.BORDERRECT_PAD, -inner_bound-Test_Box.BORDERRECT_PAD)
painter.drawRect(outer_rect)
painter.drawRect(inner_rect)
brush = QBrush(QColor(100, 100, 100, 100))
painter.setBrush(brush)
painter.drawRoundedRect(self.rect, Test_Box.CORNER_RADIUS, Test_Box.CORNER_RADIUS)
def Cursor_OnEdge(self):
outer_rect = self.boundingRect().adjusted(-Test_Box.BORDERRECT_PAD,-Test_Box.BORDERRECT_PAD,CURSOR_SIZE+Test_Box.BORDERRECT_PAD,CURSOR_SIZE+Test_Box.BORDERRECT_PAD)
inner_bound = (BORDER_WIDTH/2 + (Test_Box.CORNER_RADIUS/2)) # Get corner offset due to rounded corners
inner_rect = self.boundingRect().adjusted((CURSOR_SIZE+inner_bound)+Test_Box.BORDERRECT_PAD, (CURSOR_SIZE+inner_bound)+Test_Box.BORDERRECT_PAD, -inner_bound-Test_Box.BORDERRECT_PAD, -inner_bound-Test_Box.BORDERRECT_PAD)
cursor_pos = Cursor_Pos(self)
on_edge = False
if outer_rect.contains(cursor_pos) and not inner_rect.contains(cursor_pos):
on_edge = True
return on_edge
def mousePressEvent(self, event):
# check if user has clicked this object's border
if self.Cursor_OnEdge():
self.Setup_Resize()
super(Test_Box, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.resize_pos != None:
self.Resize()
else:
super(Test_Box, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if self.resize_pos != None:
self.Done_Resize()
super(Test_Box, self).mouseReleaseEvent(event)
def Setup_Resize(self):
self.resize_sections= []
self.setCursor(Qt.ClosedHandCursor)
cursor_pos = Cursor_Pos(self)
self.resize_pos = cursor_pos
# Determine drag from sections
if cursor_pos.y() > self.boundingRect().height()/2:
# If on bottom half
self.resize_sections.append('BOTTOM')
else:
self.resize_sections.append('TOP')
if cursor_pos.x() < self.boundingRect().width()/2:
# If on left half
self.resize_sections.append('LEFT')
else:
self.resize_sections.append('RIGHT')
def Resize(self):
updated = False
# From cursor_pos to resize_pos
cursor_pos = Cursor_Pos(self)
move_x = cursor_pos.x() - self.resize_pos.x()
move_y = cursor_pos.y() - self.resize_pos.y()
child_rect = self.childrenBoundingRect()
# If y not within child items rect
if not child_rect.contains(child_rect.left()+1, cursor_pos.y()):
if self.resize_sections[0] == 'TOP':
self.rect.setTop(self.rect.top() + move_y)
else:
self.rect.setBottom(self.rect.bottom() + move_y)
updated = True
# If x not within child items rect
if not child_rect.contains(cursor_pos.x(), child_rect.top()+1):
if self.resize_sections[1] == 'LEFT':
self.rect.setLeft(self.rect.left() + move_x)
else:
self.rect.setRight(self.rect.right() + move_x)
updated = True
# Check if updated
if updated:
self.scene().update()
self.resize_pos = cursor_pos
def Done_Resize(self):
self.resize_pos = None
self.setCursor(Qt.ArrowCursor)
class GraphicsView(QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
self.setDragMode(QGraphicsView.RubberBandDrag)
self.setRenderHint(QPainter.Antialiasing)
self.setRenderHint(QPainter.TextAntialiasing)
def wheelEvent(self, event):
factor = 1.41 ** (event.delta() / 240.0)
self.scale(factor, factor)
class Main_Dlg(QDialog):
OFFSET = 5
def __init__(self, parent=None):
super(Main_Dlg, self).__init__(parent)
self.from_linkPnt= None
self.prev_pnt = QPoint()
self.add_offset = Main_Dlg.OFFSET
self.prntr = QPrinter(QPrinter.HighResolution)
self.prntr.setPageSize(QPrinter.Letter)
self.view = GraphicsView()
self.scene = QGraphicsScene(self)
self.scene.setSceneRect(0, 0, PAGESIZE_LST[0], PAGESIZE_LST[1])
self.view.setScene(self.scene)
linkPnt_btn = QPushButton("Add Stage Box")
linkPnt_btn.clicked.connect(self.Add_Item)
layout = QVBoxLayout()
layout.addWidget(self.view)
layout.addWidget(linkPnt_btn)
self.setLayout(layout)
self.Add_Item()
def position(self):
point = self.mapFromGlobal(QCursor.pos())
if not self.view.geometry().contains(point):
coord_x = random.randint(int(PAGESIZE_LST[0]*0.25), int(PAGESIZE_LST[0]*0.75))
coord_y = random.randint(int(PAGESIZE_LST[1]*0.25), int(PAGESIZE_LST[1]*0.75))
point = QPoint(coord_x, coord_y)
else:
if point == self.prev_pnt:
point += QPoint(self.add_offset, self.add_offset)
self.add_offset += 5
else:
self.add_offset = Main_Dlg.OFFSET
self.prev_pnt = point
return self.view.mapToScene(point)
def Add_Item(self):
item = Test_Box(self.position())
self.scene.addItem(item)
app = QApplication(sys.argv)
form = Main_Dlg()
rect = QApplication.desktop().availableGeometry()
form.resize(int(rect.width() * 0.6), int(rect.height() * 0.9))
form.show()
app.exec_()
Yes, they are sharing the same
QRect, because you do not create copies of it when assigned toself.rect:Also, you correctly return a new rectangle in
boundingRect()but in resize you modify the shared rectangle, so that’s why all the instances are resized accordingly.I think using a copy for
self.rectfrom the start should solve this.