PDA

View Full Version : Non-rectangle rubber band implementation [Solved]



d_stranz
30th June 2011, 01:53
I'm trying to implement a "lasso" type rubber band to allow users to select things from a QGraphicsView. A rectangle won't work, because the items don't always fall into a neat rectangular area free from other items.

I have tried subclassing QRubberBand and adding a new Shape (Lasso) with custom paintEvent code and a QPainterPath to accumulate the mouse event points, but that is not working well. I can draw the "lasso", but there are also artifacts (one or more lines drawn from the window top left to the starting mouse point) which somehow seem to get inserted into the path.

I've checked the mouse positions (as best one can do that in mouse event handlers) and they look OK, and I don't see any (0,0) points being inserted.

I have looked through many of the previous posts here on rubber bands, and none of them seem to apply; they all deal with customizing the stock QRubberBand, not implementing a new one from scratch.

So, can anyone point me to code which provides an example of a QPainterPath or polygon / polyline - based rubber band? Any drawing packages for example?

norobro
30th June 2011, 02:44
Qwt implements several different styles of rubberbands: link (http://qwt.sourceforge.net/class_qwt_picker.html). I don't know how well they work as I've only used RectRubberBand, but maybe you can glean something from the source.

HTH

d_stranz
30th June 2011, 03:28
Yes, I've looked at Qwt and have even implemented my own rubber band styles within the Qwt framework. The Qwt implementation is very complex, since it depends on a state machine and interactions with the rest of the Qwt system. It isn't easy to reuse in a non-Qwt framework. But I'll take another look. There is a polygon picker style, but I think it is implemented using a series of clicks rather than a continuous click and drag.

d_stranz
30th June 2011, 06:21
OK, I've implemented a custom rubber band class (derived from QWidget) that supports horizontal line, vertical line, rectangle, ellipse, and lasso click-drag styles. It works as desired on a plain old QWidget in a QMainWindow, so now I need to make whatever changes are needed to make it work on top of a QGraphicsView with the ability to select QGraphicsItem instances within the area defined by the path.

Rachol
30th June 2011, 09:08
one or more lines drawn from the window top left to the starting mouse point

I don't know how do you create the QPainterPath, but it seems like you are not inserting moveTo element to the first point of the path.

d_stranz
1st July 2011, 19:38
I don't know how do you create the QPainterPath, but it seems like you are not inserting moveTo element to the first point of the path.

Actually, I -was- inserting a moveTo element as the first point in the path, that is why I could not understand where the artifacts were coming from. What I believe was happening was that the last element was not a "closeSubpath", and that was the cause of the spurious lines. After I added that call, the artifacts went away.

So, my lasso rubberband consists of a moveTo call, followed by a series of lineTo calls that track the mouse position. I then use QPainterPath::toFillPolygon() to create a polygon, add this to a new path and append a closeSubpath() to that. I draw this new closed polygon (as a path) in the paint event. Works perfectly.

Using the QPainterPath as a way to track mouse movement lets me implement the rubber band as a horizontal or vertical line, rectangle, ellipse, or lasso (free-form polygon). The start point is captured on mousePressEvent, and the correct path is created (or appended to) in the mouseMoveEvent.

One curious thing: in the mouseMoveEvent, the event->button() is always Qt::NoButton, even though a click-drag is in progress with the left mouse button pressed (at least on Windows).

totem
2nd July 2011, 16:10
now I need to make whatever changes are needed to make it work on top of a QGraphicsView with the ability to select QGraphicsItem instances within the area defined by the path.

I did that once, be aware you'll have to deal with zoom in graphics scene if your app supports this feature.
Do you plan to draw the lasso on graphicsView foreground ?

d_stranz
5th July 2011, 21:30
I did that once, be aware you'll have to deal with zoom in graphics scene if your app supports this feature.

It is worse than that. I will have to restrict the allowed area for selection to a sub-area within the scene. Fortunately, the location of this sub-area is more-or-less fixed, so I can determine on mouse press whether the mouse is within the allowed area or not.


Do you plan to draw the lasso on graphicsView foreground ?

No, it will be drawn in an independent QWidget that is a child of the QGraphicsView, much the same way that QRubberBand itself works. The rubber band class will emit a signal containing the closed QPainterPath defined by the lasso. The view will be responsible for converting this into appropriate scene coordinates and then selecting items within the path bounds.

In principle, any widget could serve as the parent for the rubber band widget, but my current intent is to use it with a graphics view. Hmmm, using a lasso to select a non-rectangular section of a table....

This is all still under development, so I am sure something will bite me before it is all over. One of those might be if the view has scroll bars - what will happen if the scene scrolls as the user enlarges the selection area? I think my allowed selection area could become invalid.