自动调整一个QGraphicsItem实例的大小,并无意中调整所有其他实例的大小

时间:2012-11-16 12:27:58

标签: python resize instance shared qgraphicsitem

我有一个问题,当我调整其中一个“Test_Boxes”时,所有其他现有的Text_Box都会调整大小,之后创建的任何内容都会以调整大小的大小创建。

似乎他们都共享相同的QRect但他们不应该。

请帮忙。

代码:

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_() 

1 个答案:

答案 0 :(得分:2)

是的,他们 共享相同的QRect,因为您在分配到self.rect时没有创建它的副本:

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           = QRectF(Test_Box.RECT)    #use a copy!

        # Settings
        self.setFlags(  self.flags()                    |
                        QGraphicsItem.ItemIsSelectable  |
                        QGraphicsItem.ItemIsMovable     |
                        QGraphicsItem.ItemIsFocusable   )

此外,您正确地在boundingRect()中返回一个新矩形,但在调整大小时修改共享矩形,这就是为什么所有实例都会相应调整大小。

我认为从一开始就使用self.rect的副本就可以解决这个问题。