PDA

View Full Version : Mouse Events across multiple neighbor widgets, possible?



weevil
10th June 2010, 05:21
I'm making a minesweeper type game. My approach was to create a Board class containing a QGridLayout of rows and columns of mine widgets (think 16x30 like windows minesweeper for example). MouseMoveEvents are easily handled by setting setMouseTracking to true in the mine widget, but I ran into trouble trying to handle mouse presses and releases. For example, if the player clicks and holds on one mine and moves the mouse, that mine object receives a mouse press and move event, but when the mouse moves on to other mines, the event data (edit: and object data) is still relative to the initial mine. I want to somehow end each event as it passes on to a new widget, and propagate the original event to the new widget.

I handled this in a Rube Goldberg-esque fashion by computing the row and column of each widget from the initial object event's global position and the fixed size of each mine widget relative to the parent widget like so:

int boardOriginX = parentWidget()->mapToGlobal( QPoint(0, 0) ).x() + Board::margins;
int boardOriginY = parentWidget()->mapToGlobal( QPoint(0, 0) ).y() + Board::margins;
int currentRow = (event->globalY() - boardOriginY) / Board::mineSize;
int currentCol = (event->globalX() - boardOriginX) / Board::mineSize;

and then setting up a Board public function

Mine* Board::getMine( int row, int column )
to get the current mine under the mouse in each event handler. But this has the sideeffect that I'm doing a lot of higher level game handling inside the mouse event handlers of a single mine widget.

This seems really sloppy allowing public access to private data (lol) and involves a lot of annoying and convoluted bounds checking and behind the scenes tracking of changing margins and sizes and number of mines to get the calculations right. Tell me there's an easier way? I wish there was a QMouseEvent member function that returned the current widget under the mouse, but that'd be too easy amirite?

tbscope
10th June 2010, 05:50
You can check the point where the mouse release event happens. If it's still on the original widget, proceed, if not, do nothing with the original widget, get the one on the new position and handle the release event of the new widget.

However, I think you handle the minefield in the wrong way.
I would use a graphics view and use the mouse events of the scene. This would be easier.

weevil
10th June 2010, 05:58
You can check the point where the mouse release event happens. If it's still on the original widget, proceed, if not, do nothing with the original widget, get the one on the new position and handle the release event of the new widget.

I'm already using the event data to check where mouse moves are during a mouse press as well as mouse releases are happening. The only difference is I'm faking mouse event handling in the neighboring widgets through the current one using parent get and set functions. How would I send a new corresponding mouse event to the next widget once I calculate I've moved outside the originating widget? And by that I mean doing so without having to resort to asking the parent what widget my mouse is looking at, then sending my own hand crafted move/press/release event, which seems just as annoying and troublesome as what I'm doing now.


However, I think you handle the minefield in the wrong way.
I would use a graphics view and use the mouse events of the scene. This would be easier.

I've only briefly looked at the model/view architecture, I'm still pretty new to Qt. Could you briefly expand on how that would make this easier? Appreciate the comment.