How can I draw a shape area around a polyline? So I can move polyline with mouse.

• The shape function is used to replace boundingRect. Polyline is not an enclosed area, so there is no concept inside or outside as polygon.

The shape should be an area around the polyline, so the shape should be able to detect the mouse cursor when it's around the polyline(for example when distance is 10).

Does anyone have experience on this? I really appreciate any suggestions.

• @helloworld12345
by polyline you mean a list of points right?
I think the easiest would be to draw rectangles for each line segment and merge them each into a QPainterPath. When you are done call QPainterPath::toFillPolygon().
Now the problem is just to calculate the coordinates of the rectangles based on the line-segments and your desired spacing.

• toFillPolygon()

Thanks raven.

1. I didn't use toFillPolygon, but use addPolygon, it works partially, most but not all area can be dragged by mouse.
2. I added eclipses around the points of polyline since rect can't cover the turning area of polyline, but it seems the eclipses didn't response when I use mouse to drag it, you have any idea? Below is the simplified code.
def shape(self):
final_shape = QPainterPath()

##
##here calcuclate the each polygon for each line session, store the points in polygons
##

for k in range(0, len(polygons)):
polygon = QPolygonF([polygons[k], polygons[k],  polygons[k], polygons[k]])

for p in self._polyline:
newpath = QPainterPath()
final_shape = final_shape.united(newpath)

return final_shape

• @raven-worx if you happen to know some example code in which several graphics(rect + ellipse) are combined in shape, that would definitely help a lot.

• @raven-worx
you can see I drew a rect for each line session, an ellipse for each point(rect doesn't cover the point). With all these rects and ellipses, the polyline is covered totally.

But at the left-most, right-most, up-most, bottom-most area of the shape, my mouse can't drag the polyline. And at the intersection area of rect and ellipse, I can't drag either, does any one have idea?

In paint function, I draw my shape area, please see below picture. My polyline is yellow, shape area is red, the area can't be dragged by mouse is pointed out by black lines. I also attached my code here.

def shape(self):

selectionOffset = 15

path = QPainterPath()

pn = [p for p in self._polyline]

for k in range(0, len(pn) -1):
line = QLineF(pn[k], pn[k+1])
radAngle = line.angle()* math.pi / 180

dx = selectionOffset * math.sin(radAngle)
dy = selectionOffset * math.cos(radAngle)

offset1 = QPointF(dx, dy)
offset2 = QPointF(-dx, -dy)

rect_p1 = line.p1() + offset1
rect_p2 = line.p1() + offset2
rect_p3 = line.p2() + offset2
rect_p4 = line.p2() + offset1

polygon_new = QPolygonF([rect_p1, rect_p2, rect_p3, rect_p4])

for m in range(0, len(pn)):

return path

• @helloworld12345
try setting the fillRule of the path to Qt::WindingFill

• I would try this:

• Find out the coordinates of a point which should work for dragging, but doesn't
• Make a debug function that calls yourPolyline->contains(thatPoint)
• Step into the contains method and see where the code decides that the point is not part of your polyline's shape

• @raven-worx

I think I found the root cause, at the beginning I thought shape() function will totally override boundingRect(). But it turns out boundingRect() still functions even I used shape(). When shape() area is out of the area of boundingRect(), the extra part from shape() that if out of the region of boundingRect() will be detected.

Then I enlarge the the area of boundingRect() to make sure it is larger than shape() area, then it seems good now.

Does it make sense to you?

• @Asperamanca

Hi, this is what I replied to raven-worx, does it make sense to you?

I think I found the root cause, at the beginning I thought shape() function will totally override boundingRect(). But it turns out boundingRect() still functions even I used shape(). When shape() area is out of the area of boundingRect(), the extra part from shape() that if out of the region of boundingRect() will be detected.

Then I enlarge the the area of boundingRect() to make sure it is larger than shape() area, then it seems good now.

• The docs nowhere specify that the shape has to be fully contained within the boundingRect. However, it seems like a logical optimization to first make a hit test using the boundingRect, before even checking the much more complex shape.

Do you have any clipping flags set (e.g. ItemClipsToShape, or ItemClipsChildrenToShape for a parent)? This might actually change the behavior, because this code of QGraphicsItem seems relevant:

bool QGraphicsItem::contains(const QPointF &point) const
{
return isClipped() ? clipPath().contains(point) : shape().contains(point);
}

...and the clipPath() starts with the boundingRect()

• @Asperamanca

No, I didn't set these two flags ItemClipsToShape, ItemClipsChildrenToShape.

Then I tried setting only one flag ItemClipsToShape, and both of ItemClipsToShape, ItemClipsChildrenToShape. For each, it still check if the point is in the boundingrect() firstly, and then check the shape() which means if point is not in boundingrect(), it wouldn't bother to check shape().

So now my solution is still enlarging the boundingrect() area.