polygon QGraphicsItem shape



  • i have a QGraphicsItem sublcass where i add some members, call it GraphicsItem.
    then i derive from this class a Polygon class. notice i don't derive from both QGraphicsPolygonItem and GraphicsItem.

    in my Polygon class i reimplemented boundingRect() and paint():

    boundingRect():
        return the bounding rectangle for the polygon
    

    this works. but i also need to be able do things when the item is hovered, clicked, double-clicked.
    i have these in GraphicsItem class:

    	void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
            {
    		prepareGeometryChange();
    		m_hovered = true;
    		QGraphicsItem::hoverEnterEvent(event);
            }
    
    	void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
            {
    		prepareGeometryChange();
    		m_hovered = false;
    		QGraphicsItem::hoverLeaveEvent(event);
            }
    
    	void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
            {
    		qDebug() << "double clicked";
    		QGraphicsItem::hoverLeaveEvent(event);
            }
    

    and in Polygon class i do (for drawing outline when hovered):

    	void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
            {
    		auto pen_outline = QPen(QBrush(QColor(Qt.cyan)), 5);
    		auto pen_line = QPen(QBrush(QColor(Qt.red)), 3);
    
    		if (m_hovered)
                    {
    			painter->setPen(pen_outline);
    			painter->drawPolygon(QPolygonF(m_coords));
                    }
    
    		painter->setPen(pen_line);
    		painter->drawPolygon(QPolygonF(m_coords));
            }
    

    however, the outline isn't drawn and the "double clicked" isn't output.

    should i reimplement shape() too for this to work? and if so, how?



  • @user4592357
    Yes I think you should implement the shape function.
    Can you post all the code for these classes (at least enough to test it anyway)



  • Are you sure the boundingRect() implementation is correct, and uses the right coordinate system?

    The default shape() implementation would use the boundingRect(). So you need to reimplement shape() if you e.g. want to react only to double clicks into the polygon area. However, the default implementation should be sufficient that the doubleClick works in principle.



  • @kenchan here it is and sorry it's in python.

    the base class:

    class Item(QGraphicsItem):
    	def __init__(self, coords, parent=None):
    		super(Item, self).__init__(parent)
    
    		# set the properties
    		self.coords = coords
    		self._hovered = False
    		
    		self.setAcceptHoverEvents(True)
    		self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemClipsToShape)
    
    	def hoverEnterEvent(self, event):
    		self.prepareGeometryChange()
    		self._hovered = True
    		super(Item, self).hoverEnterEvent(event)
    
    	def hoverLeaveEvent(self, event):
    		self.prepareGeometryChange()
    		self._hovered = False
    		super(Item, self).hoverLeaveEvent(event)
    
    	def mouseDoubleClickEvent(self, event):
    		print("dbl click")
    		super(Item, self).mouseDoubleClickEvent(event)
    

    the polygon class:

    class PolygonItem(ErroItem):
    	def __init__(self, coords, parent=None):
    		""" Initialize the polygon item. """
    		super(PolygonItem, self).__init__(coords, parent)
    
    	def boundingRect(self):
    		return bounding_rect(self.coords)
    
    	def paint(self, painter, option, widget):
    		""" Mandatory override of base class. """
    		pen_outline = QPen(QBrush(QColor(Qt.cyan)), 5, join=Qt.MiterJoin)
    		pen_line = QPen(QBrush(QColor(Qt.red)), 3, join=Qt.MiterJoin)
    
    		if self._hovered:
    			painter.setPen(pen_outline)
    			painter.drawPolygon(QPolygonF(self.coords))
    
    		painter.setPen(pen_line)
    		painter.drawPolygon(QPolygonF(self.coords))
    


  • @user4592357
    Thanks for posting the code As you probably guessed I don't use Qt python :-). I am sure there are python experts who can give you advice.
    I can consider its behaviour in terms of C++ though.



  • @kenchan
    yeah i mean there's nothing specific to python here



  • How is the function "bounding_rect(self.coords)" implemented?



  • @Asperamanca

        max_x = max_y = -inf
        min_x = min_y = inf
    
        # calculate min/max x/y values
        for point in points:
            if point.x() > max_x:
                max_x = point.x()
            elif point.x() < min_x:
                min_x = point.x()
            if point.y() > max_y:
                max_y = point.y()
            elif point.y() < min_y:
                min_y = point.y()
    
        # construct a rectangle out of those coordinates        
        return QRectF(QPointF(min_x, max_y), QPointF(max_x, min_y))
    


  • Not sure this is related to your issue, but is there any specific reason you flip the y axis?



  • @Asperamanca
    what do you mean by flip? for bounding rect i take top left and bottom right coordinates of the rect



  • @user4592357
    GraphicItem coordinates are origin at top left and positive axis down to the right. So your Y axis is flipped.
    Unless you changed it somewhere else.



  • @kenchan
    oh right, so i need to take bottom left and top right points?



  • @user4592357
    no, top left and bottom right is probably what you need

    QRectF(QPointF(min_x, min_y), QPointF(max_x, max_y))
    

    http://doc.qt.io/qt-5/qgraphicsitem.html#details



  • @kenchan
    that's what i was saying





  • @user4592357 said in polygon QGraphicsItem shape:

    Not sure that came across:
    The way you posted your code, you actually use bottom/left and top/right to construct the rectangle.

    return QRectF(QPointF(min_x, max_y), QPointF(max_x, min_y))



  • @kenchan
    it's really weird. i set background brush to black of my graphics view, and when i add something like

    item = PolygonItem([QPointF(30, 30), QPointF(50, 50), QPointF(100, 100)])
    

    to the scene, the view becomes white and no item is drawn :(

    here's the scene and view:

    class Scene(QGraphicsScene):
        def __init__(self, parent=None):
            super(Scene, self).__init__(parent)
    
    class View(QGraphicsView):
        def __init__(self, parent=None):
            super(View, self).__init__(parent)
            self.setRenderHint(QPainter.Antialiasing)
            self.setRenderHint(QPainter.TextAntialiasing)
            self.setSceneRect(self.scene().sceneRect())
            self.setBackgroundBrush(QBrush(Qt.black))
    

    this is how i create the scene and view in main window:

    	def __create_scene_and_view(self):
                    self.__scene = Scene(self)
    		self.__view = View(self.__scene)
    		self.__layout_view.show()
    		self.setCentralWidget(self.__view)
    

    some items are drawn correctly, though. for example:

    item = PolygonItem([QPointF(75, -10), QPointF(60, 40), QPointF(110, 10), QPointF(0, 0)])
    

    i noticed, if i add QPointf(0, 0) to the first (non-working) item, it is drawn too


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.