如何使选定的 qgraphicsitem 的边界矩形自动显示?

How to make the bounding rect of a selected qgraphicsitem show automatically?

我在 SO 中通过 @serge_gubenko 找到了这个例子。 Moving a QGraphicsItem around a central point in PyQt4

然后我做了一些修改以结束:

如果我运行示例 (Moving a QGraphicsItem around a central point in PyQt4) 并单击图形项,它会自动显示一个虚线框,表明它已被选中。我准备了图片来展示效果,但由于我的声誉不高,我还不允许上传这些 ;)

对我来说,虚线框旁的 "is selected indication" 似乎是自动出现的。 在我修改的示例 () 中,这并没有发生,我不明白为什么?

您使用了QtGui.QGraphicsItem,所以您定义了boundingRect 和paint 方法,其中您使用了painter drawEllipse 方法。在您找到的第一个示例中,class 直接使用 QtGui.QGraphicsEllipseItem 并且它做了所有不同的事情,因为那些方法已经定义了。顺便说一句,我没有找到为什么 boundingRect 没有在你的案例中绘制。

这是一个工作示例,它有自己的 drawFocusRect 方法。

焦点有两种表示方式:
1)通过点击Qgraphicsitem,然后绘制边界矩形。
2) 将鼠标悬停在项目上。触发时 hoverEnterEvent the pen style is changed to DotLine converting back to SolidLine when the hoverLeaveEvent 被触发。

#!d:/python27/python -u

import sys
from PyQt4 import QtGui, QtCore

class GraphicsItem(QtGui.QGraphicsItem):
    """
     From the QT docs:
     To write your own graphics item, you first create a subclass
     of QGraphicsItem, and then start by implementing its two pure 
     virtual public functions: boundingRect(), which returns an estimate
     of the area painted by the item, and paint(), 
     which implements the actual painting.
    """
    # call constructor of GraphicsItem
    def __init__(self, rect, pen, brush, tooltip='No tip here', parent=None):
        # call constructor of QGraphicsItem
        super(GraphicsItem, self).__init__()

        self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QtGui.QGraphicsItem.ItemIsFocusable, True)

        self.setAcceptsHoverEvents(True)

        self.pen = pen
        pw = self.pen.widthF()
        self.brush = QtGui.QBrush(QtCore.Qt.blue)
        self.brush = brush
        self.setToolTip(tooltip)
        self.parent = parent

        self.rect = QtCore.QRectF(rect[0], rect[1], rect[2], rect[3])
        self.focusrect = QtCore.QRectF(rect[0]-pw/2, rect[1]-pw/2,
                rect[2]+pw, rect[3]+pw)

    def mouseMoveEvent(self, event):
        # move object
        QtGui.QGraphicsItem.mouseMoveEvent(self, event)

    def mousePressEvent(self, event):
        # select object
        # set item as topmost in stack
        self.setZValue(self.parent.scene.items()[0].zValue() + 1)
        self.setSelected(True)
        QtGui.QGraphicsItem.mousePressEvent(self, event)

    def boundingRect(self):
        return self.rect

    def paint(self, painter, option, widget):
        painter.setBrush(self.brush)
        painter.setPen(self.pen)
        painter.drawEllipse(self.rect)
        if self.isSelected():
            self.drawFocusRect(painter)

    def drawFocusRect(self, painter):
        self.focusbrush = QtGui.QBrush()
        self.focuspen = QtGui.QPen(QtCore.Qt.DotLine)
        self.focuspen.setColor(QtCore.Qt.black)
        self.focuspen.setWidthF(1.5)
        painter.setBrush(self.focusbrush)
        painter.setPen(self.focuspen)
        painter.drawRect(self.focusrect)

    def hoverEnterEvent(self, event):
        self.pen.setStyle(QtCore.Qt.DotLine)
        QtGui.QGraphicsItem.hoverEnterEvent(self, event)

    def hoverLeaveEvent(self, event):
        self.pen.setStyle(QtCore.Qt.SolidLine)
        QtGui.QGraphicsItem.hoverLeaveEvent(self, event)


class MyMainWindow(QtGui.QMainWindow):
    # call constructor of MyMainWindow
    def __init__(self, parent=None):
        # call constructor of QMainWindow
        super(MyMainWindow, self).__init__(parent)

        w = 1000
        h = 800
        self.scene = QtGui.QGraphicsScene(-w/2, -h/2, w, h)

        self.view = QtGui.QGraphicsView()
        # set QGraphicsView attributes
        self.view.setRenderHints(QtGui.QPainter.Antialiasing |
            QtGui.QPainter.HighQualityAntialiasing)
        self.view.setViewportUpdateMode(QtGui.QGraphicsView.FullViewportUpdate)
        self.view.setScene(self.scene)

        # set central widget for the application
        self.setCentralWidget(self.view)

        # add items to the scene
        self.addGraphicsItem((0, 0, 250, 250), 8.0, (255, 0, 0), (0, 0, 255), 'My first item')
        self.addGraphicsItem((-250, -250, 300, 200), 4.0, (0, 0, 0), (255, 0, 100), 'My 2nd item')
        self.addGraphicsItem((200, -200, 200, 200), 10.0, (0, 0, 255), (0, 255, 100), 'My 3rd item')

    def addGraphicsItem(self, rect, pw, pc, bc, tooltip):
        pen = QtGui.QPen(QtCore.Qt.SolidLine)
        pen.setColor(QtGui.QColor(pc[0], pc[1], pc[2], 255))
        pen.setWidth(pw)
        brush = QtGui.QBrush(QtGui.QColor(bc[0], bc[1], bc[2], 255))
        item = GraphicsItem(rect, pen, brush, tooltip, self)
        self.scene.addItem(item)

    def mousePressEvent(self, event):
        #print 'from MainWindow'
        pass

    def keyPressEvent(self, event):
        key = event.key()

        if key == QtCore.Qt.Key_Escape:
            sys.exit(QtGui.qApp.quit())
        else:
            super(GraphicsView, self).keyPressEvent(event)

def main():
    app = QtGui.QApplication(sys.argv)
    form = MyMainWindow()
    form.setGeometry(700, 100, 1050, 850)
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()

针对 PyQt5 更新

import sys
from PyQt5 import QtGui, QtCore, QtWidgets

class GraphicsItem(QtWidgets.QGraphicsItem):
    """
     From the QT docs:
     To write your own graphics item, you first create a subclass
     of QGraphicsItem, and then start by implementing its two pure
     virtual public functions: boundingRect(), which returns an estimate
     of the area painted by the item, and paint(),
     which implements the actual painting.
    """
    # call constructor of GraphicsItem
    def __init__(self, rect, pen, brush, tooltip='No tip here', parent=None):
        # call constructor of QGraphicsItem
        super(GraphicsItem, self).__init__()

        self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsFocusable, True)

        self.setAcceptHoverEvents(True)

        self.pen = pen
        pw = self.pen.widthF()
        self.brush = QtGui.QBrush(QtCore.Qt.blue)
        self.brush = brush
        self.setToolTip(tooltip)
        self.parent = parent

        self.rect = QtCore.QRectF(rect[0], rect[1], rect[2], rect[3])
        self.focusrect = QtCore.QRectF(rect[0]-pw/2, rect[1]-pw/2,
                rect[2]+pw, rect[3]+pw)

    def mouseMoveEvent(self, event):
        # move object
        QtWidgets.QGraphicsItem.mouseMoveEvent(self, event)

    def mousePressEvent(self, event):
        # select object
        # set item as topmost in stack
        self.setZValue(self.parent.scene.items()[0].zValue() + 1)
        self.setSelected(True)
        QtWidgets.QGraphicsItem.mousePressEvent(self, event)

    def boundingRect(self):
        return self.rect

    def paint(self, painter, option, widget=None):
        painter.setBrush(self.brush)
        painter.setPen(self.pen)
        painter.drawEllipse(self.rect)
        if self.isSelected():
            self.drawFocusRect(painter)

    def drawFocusRect(self, painter):
        self.focusbrush = QtGui.QBrush()
        self.focuspen = QtGui.QPen(QtCore.Qt.DotLine)
        self.focuspen.setColor(QtCore.Qt.black)
        self.focuspen.setWidthF(1.5)
        painter.setBrush(self.focusbrush)
        painter.setPen(self.focuspen)
        painter.drawRect(self.focusrect)

    def hoverEnterEvent(self, event):
        self.pen.setStyle(QtCore.Qt.DotLine)
        QtWidgets.QGraphicsItem.hoverEnterEvent(self, event)

    def hoverLeaveEvent(self, event):
        self.pen.setStyle(QtCore.Qt.SolidLine)
        QtWidgets.QGraphicsItem.hoverLeaveEvent(self, event)


class MyMainWindow(QtWidgets.QMainWindow):
    # call constructor of MyMainWindow
    def __init__(self, parent=None):
        # call constructor of QMainWindow
        super(MyMainWindow, self).__init__(parent)

        w = 1000
        h = 800
        self.scene = QtWidgets.QGraphicsScene(-w/2, -h/2, w, h)

        self.view = QtWidgets.QGraphicsView()
        # set QGraphicsView attributes
        self.view.setRenderHints(QtGui.QPainter.Antialiasing |
            QtGui.QPainter.HighQualityAntialiasing)
        self.view.setViewportUpdateMode(QtWidgets.QGraphicsView.FullViewportUpdate)
        self.view.setScene(self.scene)

        # set central widget for the application
        self.setCentralWidget(self.view)

        # add items to the scene
        self.addGraphicsItem((0, 0, 250, 250), 8.0, (255, 0, 0), (0, 0, 255), 'My first item')
        self.addGraphicsItem((-250, -250, 300, 200), 4.0, (0, 0, 0), (255, 0, 100), 'My 2nd item')
        self.addGraphicsItem((200, -200, 200, 200), 10.0, (0, 0, 255), (0, 255, 100), 'My 3rd item')

    def addGraphicsItem(self, rect, pw, pc, bc, tooltip):
        pen = QtGui.QPen(QtCore.Qt.SolidLine)
        pen.setColor(QtGui.QColor(pc[0], pc[1], pc[2], 255))
        pen.setWidth(pw)
        brush = QtGui.QBrush(QtGui.QColor(bc[0], bc[1], bc[2], 255))
        item = GraphicsItem(rect, pen, brush, tooltip, self)
        self.scene.addItem(item)

    def mousePressEvent(self, event):
        #print 'from MainWindow'
        pass


def main():
    app = QtWidgets.QApplication(sys.argv)
    form = MyMainWindow()
    form.setGeometry(700, 100, 1050, 850)
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()