简体   繁体   中英

QGraphicsEllipseItem paint event being clipped

I have two issues here.

  1. When i paint the ellipse it appears the edges of the ellipse are not being painted white during the hover event. How can i fix this both when the dot is it's regular size and when it's being hovered over?
  2. When the user hovers over the dot I want the dot's radius to increase by 2, however when i do that, it currently does not scale from the center of the dot. How can i adjust so it increases it's size based on the center point of the dot?

在此处输入图片说明

import sys
from PySide.QtGui import *
from PySide.QtCore import *
import random


class MyGraphicsView(QGraphicsView):
    def __init__(self):
        super(MyGraphicsView, self).__init__()
        self.setDragMode(QGraphicsView.RubberBandDrag)
        self._isPanning = False
        self._mousePressed = False
        # self.setBackgroundBrush(QImage("C:/Users/jmartini/Desktop/Temp/images/flag_0140.jpg"))
        self.setCacheMode(QGraphicsView.CacheBackground)
        self.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff )
        self.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff )


    def mousePressEvent(self,  event):
        if event.button() == Qt.LeftButton:
            self._mousePressed = True
            if self._isPanning:
                self.setCursor(Qt.ClosedHandCursor)
                self._dragPos = event.pos()
                event.accept()
            else:
                super(MyGraphicsView, self).mousePressEvent(event)
        elif event.button() == Qt.MiddleButton:
            self._mousePressed = True
            self._isPanning = True
            self.setCursor(Qt.ClosedHandCursor)
            self._dragPos = event.pos()
            event.accept()


    def mouseMoveEvent(self, event):
        if self._mousePressed and self._isPanning:
            newPos = event.pos()
            diff = newPos - self._dragPos
            self._dragPos = newPos
            self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - diff.x())
            self.verticalScrollBar().setValue(self.verticalScrollBar().value() - diff.y())
            event.accept()
        else:
            super(MyGraphicsView, self).mouseMoveEvent(event)


    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            if self._isPanning:
                self.setCursor(Qt.OpenHandCursor)
            else:
                self._isPanning = False
                self.setCursor(Qt.ArrowCursor)
            self._mousePressed = False
        elif event.button() == Qt.MiddleButton:
            self._isPanning = False
            self.setCursor(Qt.ArrowCursor)
            self._mousePressed = False
        super(MyGraphicsView, self).mouseReleaseEvent(event)


    def mouseDoubleClickEvent(self, event): 
        self.fitInView(self.sceneRect(), Qt.KeepAspectRatio)
        pass


    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Space and not self._mousePressed:
            self._isPanning = True
            self.setCursor(Qt.OpenHandCursor)
        else:
            super(MyGraphicsView, self).keyPressEvent(event)


    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Space:
            if not self._mousePressed:
                self._isPanning = False
                self.setCursor(Qt.ArrowCursor)
        else:
            super(MyGraphicsView, self).keyPressEvent(event)


    def wheelEvent(self,  event):
        # zoom factor
        factor = 1.25

        # Set Anchors
        self.setTransformationAnchor(QGraphicsView.NoAnchor)
        self.setResizeAnchor(QGraphicsView.NoAnchor)

        # Save the scene pos
        oldPos = self.mapToScene(event.pos())

        # Zoom
        if event.delta() < 0:
            factor = 1.0 / factor
        self.scale(factor, factor)

        # Get the new position
        newPos = self.mapToScene(event.pos())

        # Move scene to old position
        delta = newPos - oldPos
        self.translate(delta.x(), delta.y())


class MyGraphicsScene(QGraphicsScene):
    def __init__(self,  parent):
        super(MyGraphicsScene,  self).__init__()
        self.setBackgroundBrush(QBrush(QColor(50,50,50)))


class EllipseItem(QGraphicsEllipseItem):
    def __init__(self):
        super(EllipseItem,  self).__init__()
        self.setAcceptHoverEvents(True)
        self.hover = False

    def paint(self, painter, option, widget):
        painter.setRenderHints( QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform | QPainter.HighQualityAntialiasing, True )
        painter.setBrush(QBrush(QColor(170,170,170,255)))

        if self.isSelected():
            painter.setPen(QPen(QColor(255,255,255), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        else:
            painter.setPen(QPen(QColor(30,30,30), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))

        self.setRect(-16, -16, 16, 16)

        if self.hover:
            painter.setPen(QPen(QColor(255,255,255), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
            self.setRect(-18, -18, 18, 18)

        painter.drawEllipse(self.rect())


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

    def hoverLeaveEvent(self, event):
        self.hover = False
        self.update()
        super(self.__class__, self).hoverEnterEvent(event)


class MyMainWindow(QMainWindow):
    def __init__(self):
        super(MyMainWindow, self).__init__()
        self.setWindowTitle("Test")
        self.resize(800,600)

        self.gv = MyGraphicsView()
        self.gv.setScene(MyGraphicsScene(self))

        lay_main = QVBoxLayout()
        lay_main.addWidget(self.gv)
        widget_main = QWidget()
        widget_main.setLayout(lay_main)
        self.setCentralWidget(widget_main)

        self.populate()


    def populate(self):
        scene = self.gv.scene()
        item = EllipseItem()
        item.setFlag( QGraphicsItem.ItemIsSelectable )
        scene.addItem(item)


def main():
    app = QApplication(sys.argv)
    ex = MyMainWindow()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

I'm not quite sure of what you exactly want (maybe it's my english). From running your code I see that on hover the edges get cut from the boxes and that the two circles are not centered on the same point.

Well, the centering problem is due to the use of the setRect method on the paint overload of your EllipseItem class. For the hovering case (I'm disregarding the selected item logic of your code), you are setting rectangles that actually have different centers. For solving this issue you could use QPainter.drawEllipse(center, rx, ry) , docs .

The edges issue could be fixed noting that painted edges are not considered on the rectangle setted by setRect as posted here . To be honest I'm not quite sure why the smaller ellipse fits the rectangle and the larger one doesnt.

Anyway, you can try doing something like this:

def paint(self, painter, option, widget):
    painter.setRenderHints( QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform | QPainter.HighQualityAntialiasing, True )
    painter.setBrush(QBrush(QColor(170,170,170,255)))

    # if self.isSelected():
    #     painter.setPen(QPen(QColor(255,255,255), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
    # else:
    #     painter.setPen(QPen(QColor(30,30,30), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))

    #self.setRect(-16, -16, 16, 16)
    center = QPointF(0,0)
    if self.hover:
        painter.setPen(QPen(QColor(255,255,255), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        # self.setRect(-10,-10, 20, 20) # this one wont fit the ellipse
        self.setRect(-11, -11, 22, 22)
        # plus 2 
        painter.drawEllipse(center, 10, 10)
    else:
        painter.setPen(QPen(QColor(30,30,30), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))  
        self.setRect(-8, -8, 16, 16)  # but this one does
        painter.drawEllipse(center, 8, 8)

Clearly you can center your ellipses in multiple ways, the code above is just one way of doing it.

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM