PDA

View Full Version : Handle mouse events in widgets from scene



whiteShadow
6th November 2015, 20:58
Hello,

I'm trying to design an interface, and I encounter an issue. I'm trying to create a scene, where I can move a menu inside (with buttons).
Here is an image of what I have:
11504

What I want to achieve, is, when I click somewhere on the scene I move the all menu around the location clicked.
I was able to do that, but the problem was when I tried to click on one of the button form the menu, it was moving the menu (like if I clicked on the scene).
I want the scene to ignore the click (do not move the menu) when I click on one button. I kind of managed to do that too, but then when I click somewhere in the QWidget that contains my buttons, the menu doesn't move.

The big white box on the image containing my button is suppose to be transparent (I just put it white for explanations).

What I would need would be to have the containing QWidget transparent on click events, but not the buttons inside it.

Is it possible to do that ?

Thank you very much.

Edit: I tried to tweak all mouse events in all combinations possible, but it doesn't work. Is it an implementation problem ? Should I replace my QWidget by a QGraphicsGroupItem ? Would it make a difference ?

whiteShadow
10th November 2015, 21:57
Thanks to anda_skoa, I finally find a way to do it.

I don't think it's the best way but it works.

For those having the same issue here is what I did:

I changed my menu buttons from QPushButton to QGraphicsObject. In my buttons constructor, I set setAcceptHoverEvents(true) to be able to change button color when mouse hover them (I check in the paint() if option.state has the QStyle::State_MouseOver flag on and change Brush if it has).
I also set the flag ItemIgnoresTransformation because I don't want my buttons to be zoomed in or move when the scene is transformed (but still I can move then programmatically if I want to position them somewhere else on my scene).
Then I defined boundingRect(), paint() and mousePressEvent(). mousePressEvent accept the event (e->accept()) and emit a signal in my case, because I want to connect my button to slots (which is why I subclassed a QGraphicsObject and not a QGraphicsItem. It's not as good performance wise, but I have a small scene, so it should be fine).

Then I created a container for these buttons. This class subclass QObject (I wanted some signals/slots here too) AND QGraphicsItemGroup.
In this constructor I set setHandlesChildEvents(false) because this is just a container, and I want my buttons inside to receive the actual event.

Finally in my scene, I create a new container, add it to the scene, and created+added buttons in the container. Then I overloaded mousePressEvent in my scene to detect if a click happened on a QGraphicsItem or not. If it's not the case, I accept the event to avoid propagation to other widget, and I do what I have to do when a click on my scene happen.
If a QGraphicsItem has been clicked, then I just call the QGraphicsScene::mousePressEvent to propagate the events to children (then my container will ignore it because I asked him not to handle child events, and finally the buttons will accept it and react by emit a signal).

Here is my customScene::mousePressEvent (it's probably not the best way to implement it, so if anyone has some suggestions to improve it, I'll take'em !!! :D):


void customScene::mousePressEvent(QGraphicsSceneMouseEv ent *event)
{
if (event->button() == Qt::LeftButton)
{
QGraphicsItem* item = this->itemAt(event->scenePos(), QTransform());

if (!item)
{
// No graphics item has been clicked. The scene handle the event then.
event->accept();

// Move probes center
this->centerCrosshair->setPos(event->scenePos());
this->centerCrosshair->show();

// Move menu
this->menu->setMenuCenter(event->scenePos().x(), event->scenePos().y());
this->menu->show();

// Move pattern
for (int i = 0; i < this->pat.size(); ++i)
{
this->pat[i]->setCenter(event->scenePos().x(), event->scenePos().y());
}
}
}

QGraphicsScene::mousePressEvent(event);
}

I hope this could help some people trying to do the same thing. I spent a couple of days trying to figure this out. Now I read it, it seems trivial, but when you don't know, it's not.

If anyone has comments or suggestions to improve it, I'd be happy to ear them.

Thank you.