2

I'm trying to create my own QGraphicsPixmapItem where I can active on hover mode and I want to paint a black border when I hover over the rect of the item, and go back to normal when I leave the rect space.

I started this code, but don't know what to do next. Also wanted to do a paintEvent, but QGraphicsPixmapItems doesn't have that. So am even more confused as don't think the paint method would be the same.

class PixmapItem(QGraphicsPixmapItem):
    def __init__(self, pixmap, rect, parent=None):
        super().__init__(parent)
        self.pixmap = pixmap
        self.setPixmap(self.pixmap)
        self.rect = rect
        self.setAcceptHoverEvents(True)

    def hoverEnterEvent(self, *args, **kwargs):
        pass

I could make the hover print 'hello' but can't do anything else, even with some examples, because those are with paintEvent and other type of items.

I would like to maintain the type of item if possible and paint the border as i said. But also don't know if it would be a better approach that's also simple.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Black Mage
  • 47
  • 4

1 Answers1

1

The QGraphicsItem do not have the paintEvent method but the paint() method:

from PyQt5 import QtCore, QtGui, QtWidgets


class PixmapItem(QtWidgets.QGraphicsPixmapItem):
    def __init__(self, pixmap, parent=None):
        super().__init__(pixmap, parent)
        self.setAcceptHoverEvents(True)
        self._is_hovered = False

    def hoverEnterEvent(self, event):
        self._is_hovered = True
        self.update()
        super().hoverEnterEvent(event)

    def hoverLeaveEvent(self, event):
        self._is_hovered = False
        self.update()
        super().hoverLeaveEvent(event)

    def paint(self, painter, option, widget=None):
        super().paint(painter, option, widget)
        if self._is_hovered:
            painter.save()
            pen = QtGui.QPen(QtGui.QColor("black"))
            pen.setWidth(4)
            painter.setPen(pen)
            painter.drawRect(self.boundingRect())
            painter.restore()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    scene = QtWidgets.QGraphicsScene()
    view = QtWidgets.QGraphicsView(scene)
    item = PixmapItem(QtGui.QPixmap("image.png"))
    scene.addItem(item)
    view.resize(640, 480)
    view.show()
    sys.exit(app.exec_())

Update:

def paint(self, painter, option, widget=None):
    super().paint(painter, option, widget)
    if self._is_hovered:
        painter.save()
        pen = QtGui.QPen(QtGui.QColor("black"))
        pen.setWidth(4)
        painter.setPen(pen)
        r = self.boundingRect()
        r.adjust(0, 0, -pen.width()/2, -pen.width()/2)
        painter.drawRect(r)
        painter.restore()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • how does the paint method know where the bounding rect is if there is no QRect defined? Doesn't make sense to me. I've been programming with PyQt within just this week, so all this is really new to me. – Black Mage May 23 '19 at 00:00
  • @BlackMage All QGraphicsItem has boundingRect defined, in the case of QGraphicsPixmapItem is the rectangle that occupies the pixmap. I recommend you read https://doc.qt.io/qt-5/graphicsview.html – eyllanesc May 23 '19 at 00:01
  • Alright, thanks! But one more thing is that the width in my image are different in the right and down borders, they are more thin. That would be because of my base code/pixmap? – Black Mage May 23 '19 at 00:04
  • @BlackMage How big is your image? – eyllanesc May 23 '19 at 00:06
  • it is a 16x16 png image and scaled to 32x32 in my program. – Black Mage May 23 '19 at 00:07
  • Try with my update, what happens is that the QPen takes the inner edge on the top-left sides and the outer edge of the botton-right – eyllanesc May 23 '19 at 00:08
  • Sorry for extending this comment, but how would I also paint an arbitrary QRect in the same code? I tried painting the bounding rect with the code, but also another rect and couldn't. Even replacing r for any QRect wouldn't paint anything. So it just works for the bounding rect for me. – Black Mage May 23 '19 at 02:25
  • @BlackMage The QRectf that could be painted should have an intersection with the boundingRect, because if there is not, it will not be painted, the boundingRect is like a painter's canvas. I recommend reading the link I have provided in one of my comments since QGraphicsView and QGraphicsView handle many coordinate systems. Read the documentation, and review the examples of Qt, or the examples that abound on the internet because otherwise you will complicate too much, this is not learned from one day to the next. – eyllanesc May 23 '19 at 02:46