Keep Sharp

Select PyQt4 rectangle by edge/stroke

This tip is about how to make pyqt4 rectangle selectable by its edge (or you call it stroke), by default it's selectable by inner area. To achieve this, basically you need to subclass QGraphicsRectItem and overwrite its shape() function so that its shape is not an area but a stroke around its bounding path.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from PyQt4 import QtGui, QtCore
import sys

class QStrokeRect(QtGui.QGraphicsRectItem):
    def __init__(self, parent=None):
        super(QStrokeRect, self).__init__(parent)
        self.strokeWidth = 4
        self.setPen(QtGui.QPen(QtGui.QColor(255, 0, 0), 4, QtCore.Qt.SolidLine))
        self.setFlags(QtGui.QGraphicsItem.ItemIsSelectable)

    def setStrokeWidth(self, strokeWidth):
        self.strokeWidth = strokeWidth

    def shape(self):
        path = QtGui.QPainterPath()
        path.addRect(self.boundingRect())
        pStroker = QtGui.QPainterPathStroker()
        pStroker.setWidth(self.strokeWidth)
        return pStroker.createStroke(path)

class QTestView(QtGui.QGraphicsView):
    def __init__(self, parent=None):
        super(QTestView, self).__init__(parent)
        self.scene = QtGui.QGraphicsScene(self)
        self.scene.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.darkGray, QtCore.Qt.SolidPattern))
        self.setScene(self.scene)


class Example(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Example, self).__init__(parent)
        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 500, 500)
        self.setWindowTitle('Select by stroke')
        self.gv = QTestView(self)
        self.gv.setMouseTracking(True)
        self.pen = QtGui.QPen(QtGui.QColor(255, 0, 0), 4, QtCore.Qt.SolidLine)
        self.gv.scene.addRect(QtCore.QRectF(0,0,400,400), self.pen)
        self.gv.scene.addItem(QStrokeRect(QtCore.QRectF(100,100,100,100)))
        self.gv.scene.addItem(QStrokeRect(QtCore.QRectF(150,150,100,100)))

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()

Example: the big outer rectangle QGraphicsRectItem can not select by edge, but the inner two small rectangles QStrokeRect can be slect by edge.

Gist pyqt4RectSelectByStroke.py

Comments