How to snap to grid a QGraphicsTextItem? How to snap to grid a QGraphicsTextItem? python-3.x python-3.x

How to snap to grid a QGraphicsTextItem?


To set new width and height of QGraphicsTextItem you can overwrite boundingRect(), to setPos() you can use any appropiate event, MouseReleaseEvent or MouseMoveEvent for example, and calculate the next top-left grid-intersection from the last pos():

class CI(QGraphicsTextItem):    def __init__(self, text, pos):        QGraphicsTextItem.__init__(self)        self.content = text        self.setPlainText(text)        self.setPos(pos)        self.setTextInteractionFlags(Qt.TextEditorInteraction)        self.setDefaultTextColor(Qt.black)        self.setFlags(            self.flags() | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)        self.setZValue(-1)    def boundingRect(self):             # get the original width and height of boundingrect        br = QGraphicsTextItem.boundingRect(self)        brw = br.width()        brh = br.height()        # new width and height in "blocks"        wblocks = int(brw/Settings.WIDTH) + 1        hblocks = int(brh/Settings.HEIGHT) + 1        w = wblocks*Settings.WIDTH        h = hblocks*Settings.HEIGHT        return QtCore.QRectF(0, 0, w, h)    def mouseReleaseEvent(self, event):                                 # QGraphicsItem.mouseReleaseEvent(self, event)        QGraphicsTextItem.mouseReleaseEvent(self, event)        self.setGridIntersection(self.pos())    def mouseMoveEvent(self, event):        QGraphicsTextItem.mouseMoveEvent(self, event)        self.setGridIntersection(self.pos())    def setGridIntersection(self, pos):        # get the next grid intersection top left of items top-left corner        grid_x = int(pos.x()/Settings.WIDTH)                                grid_y = int(pos.y()/Settings.HEIGHT)        self.setPos(grid_x*Settings.WIDTH, grid_y*Settings.HEIGHT)    def paint(self, painter, option, widget):        painter.save()        painter.setBrush(QBrush(Qt.white))        painter.drawRect(self.boundingRect())        painter.restore()        super().paint(painter, option, widget)    def keyPressEvent(self, event):        super().keyPressEvent(event)        self.content = self.toPlainText()    def focusInEvent(self, event):        self.scene().writing_comment = True        # self.setPlainText(self.content)        # print("Focusinevent")    def focusOutEvent(self, event):        self.scene().writing_comment = False        # self.setHtml(self.content)        # print("FocusOutevent")    def contextMenuEvent(self, scme):        super().contextMenuEvent(scme)

Edit 01.02.17:the solution above is only suitable for singleselections, for both single- and multiselections use:

class CI(QGraphicsTextItem):    def __init__(self, text, pos):        QGraphicsTextItem.__init__(self)        self.content = text        self.setPlainText(text)        self.setPos(pos)        self.setTextInteractionFlags(Qt.TextEditorInteraction)        self.setDefaultTextColor(Qt.black)        self.setFlags(            self.flags() | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)        self.setZValue(-1)        self.setAcceptDrops(True)    def boundingRect(self):        # get the original width and height of boundingrect        br = QGraphicsTextItem.boundingRect(self)        brw = br.width()        brh = br.height()        # new width and height in "blocks"        wblocks = int(brw / Settings.WIDTH) + 1        hblocks = int(brh / Settings.HEIGHT) + 1        w = wblocks * Settings.WIDTH        h = hblocks * Settings.HEIGHT        return QtCore.QRectF(0, 0, w, h)    def setGridIntersection(self, pos):        # get the next grid intersection top left of items top-left corner        grid_x = int(pos.x() / Settings.WIDTH)        grid_y = int(pos.y() / Settings.HEIGHT)        self.setPos(grid_x * Settings.WIDTH, grid_y * Settings.HEIGHT)    def paint(self, painter, option, widget):        painter.save()        painter.setBrush(QBrush(Qt.white))        painter.drawRect(self.boundingRect())        painter.restore()        super().paint(painter, option, widget)    def keyPressEvent(self, event):        super().keyPressEvent(event)        self.content = self.toPlainText()    def focusInEvent(self, event):        self.scene().writing_comment = True        # self.setPlainText(self.content)        # print("Focusinevent")    def focusOutEvent(self, event):        self.scene().writing_comment = False        # self.setHtml(self.content)        # print("FocusOutevent")    def contextMenuEvent(self, scme):        super().contextMenuEvent(scme)

and in class QS add:

    def mouseMoveEvent(self, event):        QtWidgets.QGraphicsScene.mouseMoveEvent(self, event)        for i in self.selectedItems():            if type(i) == CI:                i.setGridIntersection(i.pos())