PDA

View Full Version : Increase margin for detecting tooltip events of QGraphicsLineItem?



dobedidoo
30th May 2012, 13:37
Hi,

I have a QGraphicsView/QGraphicsScene setup with several QGraphicsLineItem:s. Now I would like to increase the margin for detecting tooltip events (QEvent::ToolTip) of these line items.

I was able to affect the margin for detecting mousePressEvent:s by returning a "wider line" from the shape(), like this:

QPainterPath MyLineGraphicsItem::shape() const
{
QPainterPath path;
QPainterPathStroker stroker;
stroker.setWidth(qMax(4, pen().width() + 3));
path.moveTo(line().p1());
path.lineTo(line().p2());
return stroker.createStroke(path);
}However, this does not seem to affect the detection of tooltip events. Anyone knows what determines that event if shape() does not?

Many thanks in advance.
/U

Spitfire
31st May 2012, 15:48
Reimplement boundingRect() and return rectangle as big as you want the tooltip to trigger.

d_stranz
31st May 2012, 21:19
That's probably not going to give very good results if the line goes diagonally from one corner to another. That would give a bounds as big as the whole window, which means the tooltip would be triggered no matter where the user clicked.

norobro
1st June 2012, 02:18
Try returning your reimplemented shape() as the boundingRect of your item.
QRectF MyLineGraphicsItem::boundingRect() const{
return shape().boundingRect();
}

d_stranz
1st June 2012, 05:27
I think that will end up doing the same thing as Spitfire's suggestion when the line is a diagonal. The bounding rect for a line shape that goes from corner to corner will still be the entire window.

The good news is that it is QGraphicsItem::shape() that is called when the mouse hovers over the item (in response to a QGraphicsScene::helpEvent() - that's what will eventually invoke the tooltip). So, you can implement shape() for your line to return a path containing a "fat" line (a QPolygon probably would work) that is as wide as it needs to be to give a good margin for the tooltip detection.

Be careful, though - this will have side effects if you also are relying on collision detection. The more "fat" you make the shape. the bigger it becomes for collision detection. It will collide with another item as soon as the other item overlaps with the fat shape, even though it isn't actually touching the line itself.

If you don't care about collisions, then you can do some interesting things. For example, if you only want the tooltip to appear when the mouse is at the ends of the line, then I'm guessing you could define the QPainterPath returned by shape() to simply be two ellipses of appropriate dimensions centered on the two endpoints.

norobro
1st June 2012, 14:15
. . . So, you can implement shape() for your line to return a path containing a "fat" line (a QPolygon probably would work) that is as wide as it needs to be to give a good margin for the tooltip detection.
If I'm not mistaken that's what the OP is saying doesn't work. Returning shape() as the bounding rect seems to work:
#include <QtGui>

class LineItem : public QGraphicsLineItem
{
public:
LineItem(qreal x, qreal y, qreal w, qreal h): QGraphicsLineItem(x,y,w,h){}
QPainterPath shape() const{
QPainterPath path;
QPainterPathStroker stroker;
path.moveTo(line().p1());
path.lineTo(line().p2());
stroker.setWidth(50);
return stroker.createStroke(path);
}
QRectF boundingRect() const{
return shape().boundingRect();
}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
painter->fillPath(shape(),QBrush(QColor(0,0,0,10)));
QGraphicsLineItem::paint(painter, option, widget);
}
};

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsView view;
QGraphicsScene scene;
LineItem horizontalLine(0,0,200,0);
horizontalLine.setToolTip("horizontal line tool tip");
scene.addItem(&horizontalLine);
LineItem diagonalLine(0,100,200,300);
diagonalLine.setToolTip("diagonal line tool tip");
diagonalLine.setFlag(QGraphicsItem::ItemIsMovable) ;
scene.addItem(&diagonalLine);
view.setScene(&scene);
view.setMinimumSize(300,400);
view.show();
return a.exec();
}
Note: I just threw the paint function in there to show the area where the tool tip will be shown. It is not necessary.

d_stranz
1st June 2012, 15:49
Returning shape() as the bounding rect seems to work

I guess my point is that because the bounding rect is always aligned with the horizontal and vertical, the further you tilt the line away from horizontal or vertical, the bigger the bounding rect becomes. If a line goes diagonally from topLeft to bottomRight of a window, then the bounding rect covers the entire window, which means the tooltip will be triggered from anywhere in the whole window, not just near the line.

I am not sure why the stroker didn't work in the OP. Perhaps the stroker doesn't have any "real" width (i.e. doesn't actually describe an enclosed area in terms of a path). That's why I suggested using a QPolygon instead, or maybe a path described by two half-circles at each end of the line, connected by two parallel lines to create a closed area.