Solved QGraphicsScene left click selects an item AND drags a rubberband.
-
I'm trying to implement MS Excel-like selection style in my QGraphicsScene. The items are selectable by left click, but if I want to select them via rubberband, I have to start the selection outside of the item's bounds. Is there any way to select the item and drag a rubber band in the same time if the left mouse button is still not released?
My scene is custom. I tried overriding the mousePressed event but with very little luck. Then I tried selecting the items via overriding mouseReleased (so that mousePressed can be reserved for the rubber band), but due to the nature of the rest of the UI (some other widgets are updated upon selection/deselection) it produces annoying flickering, because the Pressed event deselects, and the Released one selects the item again. Any ideas?
Edit: This is the closest I got:
void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() != Qt::LeftButton) { event->accept(); return; } QGraphicsItem* item = itemAt(event->scenePos(), QTransform()); if (item != nullptr && item->isSelected()) return; else QGraphicsScene::mousePressEvent(event); }
Now I get the rubberband as long as the item is selected, but I have to select it first with a click, and then drag the selectionbox.
-
Exactly 8 months later, I finally managed to make it work the way that I want, so I'm posting the answer.
Subclass both QGraphicsView and QGraphicsScene. For both of them mousePressEvent has to be reimplemented as follows:
QGraphicsView subclass:
void CustomView::mousePressEvent(QMouseEvent* event) { QGraphicsView::mousePressEvent(event); QGraphicsView::mousePressEvent(event); //yes, just call it twice // we're gonna lie to the view that the event is not handled >:) }
QGraphicsScene subclass:
void CustomScene::mousePressEvent(QGraphicsSceneMouseEvent* event) { if (event->button() != Qt::LeftButton) { event->accept(); return; } QGraphicsItem* item = itemAt(event->scenePos(), QTransform()); if (item != nullptr && !item->isSelected()) { item->setSelected(1); } }
Debugging the code, I noticed, the last line - item->setSelected(1) is called on each of the two calls in the CustomView. However on the first call, the item is immediately deselected, since the event is not handled and the GraphicsView starts the rubberband selection, deselecting the item. The second call is where the item is permently selected, since the rubberband already exists. Not a very elegant solution, but it works like a charm. If anyone knows a better way, feel free to share it.