Solved polygon QGraphicsItem shape
-
@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?
-
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 needQRectF(QPointF(min_x, min_y), QPointF(max_x, max_y))
-
@kenchan
that's what i was saying -
@user4592357
:-) -
@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 likeitem = 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 -
@kenchan
hi,i fixed the above issue (related to bounding box)
this is the bound rect now:
bb = brect(self.coords) if self._hovered: bb.setX(bb.x() - 4) bb.setY(bb.y() - 4) bb.setWidth(bb.width() + 4) bb.setHeight(bb.height() + 4) return bb
and this is paint():
def paint(self, painter, option, widget): 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))
and these are the results when normal:
and when hovering:
as you can see, the red rectangle has become a lot thicker. why is that?
i think one reason may be that i'm using coordinates for both normal and highlighted drawing?
by the way, if i remove the
if
in bounding rect, i get the "outline" drawn, only within the rect but i need outside it. -
@user4592357 Hello again,
I can't see why the red box should get thicker with that code.
You should probably only offset your bounding box position by -2 if you increase the width and height by 4 (4/2=2 extra pixels on each side). -
@kenchan
i have played with numbers. setting that to -2 looks worseif i remove the if in bounding rect, i get the "outline" drawn, only within the rect but i need outside it.
-
@user4592357
since you have a width of 3 and 5. assuming the thicker red line in the lower image is width 3 the cyan line looks correct at width 5 having 1 pixel on each side. So, I am thinking that the upper thinner rectangle is incorrectly drawn. It does not look like it has a width of 3 to me. I cannot see why that is though.
BTW it made a similar one with C++ and it looks fine.