PDA

View Full Version : QGraphicsView Mouse Events



tomf
23rd July 2008, 18:01
Hi!

I'm having problems with my QGraphicsView and some mouse events. Basically I want to zoom and pan my view and also handle the items events.

I want the following behavior: The graphics view should only receive the events while my space button is pressed. So if you want to pan/zoom you should press space and either the right or left mouse button (left = pan, right = zoom). Otherwise the items should receive the events.

My items don't implement any event handling at the moment so they are using the standard implementation.

The code for my view:



//--------------------------------------------------------------------------------
void GraphicsView::mousePressEvent(QMouseEvent *event)
{
if(_key != Qt::Key_Space)
{
QGraphicsView::mousePressEvent(event);
event->ignore();
return;
}

//save mouse position
_last_position = event->pos();
}

//--------------------------------------------------------------------------------
void GraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
if(_key != Qt::Key_Space)
{
QGraphicsView::mouseReleaseEvent(event);
event->ignore();
return;
}

setCursor(_default_cursor);
}

//--------------------------------------------------------------------------------
void GraphicsView::mouseMoveEvent(QMouseEvent *event)
{
if(_key != Qt::Key_Space)
{
QGraphicsView::mouseMoveEvent(event);
event->ignore();
return;
}

int dx = event->x() - _last_position.x();
int dy = event->y() - _last_position.y();

//save mouse position
_last_position = event->pos();

qDebug() << "pos: " << event->pos().x() << " " << event->pos().y();

if (event->buttons() == Qt::LeftButton)
{
setCursor(_move_cursor);
pan(dx, dy);
}
else if (event->buttons() == Qt::RightButton)
{
zoom(dx);
}
}

//--------------------------------------------------------------------------------
void GraphicsView::keyPressEvent(QKeyEvent *event)
{
_key = event->key();
}

//--------------------------------------------------------------------------------
void GraphicsView::keyReleaseEvent(QKeyEvent *event)
{
_key = 0;
}


Now my main problem is that I receive all events as expected but during my views mousMoveEvent which I handle only while space is pressed my events position isn't correct. It stays always the same. If I don't have space pressed the events position changes depending on the mouse position.

I have no idea what I'm doing wrong. If I uncomment all the QGraphicsView::mouseXEvent(event) it works fine. But if I deliver the events to my items if space is not pressed it doesn't work.

tomf
25th July 2008, 18:48
nobody? :confused:

wysota
25th July 2008, 19:26
I suggest you manipulate with QGraphicsView::ScrollHandDrag a bit. And in your event handlers change modes and let the events flow as usual - simply act depending on the current mode instead of ignoring events, that's not a good way to go.

Panning you'll have for free using aforementioned QGraphicsView::ScrollHandDrag. For zooming you'll have to implement a separate mode which you'll be handling in an event or slot that is called when a specific action you want zooming to be triggered with is performed (for instance wheelEvent is you want zooming to be triggered by the mouse wheel).

tomf
25th July 2008, 19:50
What do you mean with "act depending on the current mode"? What mode? How can I change the "mode"?

Also the problem with the ScrollHandDrag is that it works fine but only if I click and drag on an area where no GraphicItems are. If my mouse is over an item it will click it. Since my scene will be full with items I want to prevent the click while my space button is pressed.

Thx!

wysota
25th July 2008, 20:42
What do you mean with "act depending on the current mode"?
If your "mode" is "pan" then handle panning and ignore everything else. If the mode is "zoom" then handle zooming and ignore everything else, etc.


What mode? How can I change the "mode"?
You have to implement it by reimplementing events, for instance:


void MyView::keyPressEvent(QKeyEvent *ke){
if(ke->key()==Qt::Key_Space)
m_spaceOn = true;
QGraphicsView::keyPressEvent(ke);
}
void MyView::keyReleaseEvent(QKeyEvent *ke){
if(ke->key()==Qt::Key_Space)
m_spaceOn = false;
QGraphicsView::keyReleaseEvent(ke);
}
void MyView::mousePressEvent(QMouseEvent *me){
if(m_spaceOn && me->button()==Qt::RightButton)
m_mode = Zooming;
if(m_spaceOn && me->button()==Qt::LeftButton){
m_mode = Panning;
setDragMode(QGraphicsView::ScrollHandDrag);
}
QGraphicsView::mousePressEvent(me);
}

void MyView::mouseReleaseEvent(QMouseEvent *me){
if(m_spaceOn)
m_mode = None;
setDragMode(QGraphicsView::NoDrag);
}
QGraphicsView::mouseReleaseEvent(me);
}

void MyView::mouseMoveEvent(QMouseEvent *me){
// panning is handled by DragMode
if(m_mode==Zooming){
// handle zooming here
}
QGraphicsView::mouseMoveEvent(me);
}

tomf
29th July 2008, 15:03
Ok so I finally found the solution to my problem.

Since I didn't want to use the ScrollHandDrag mode I always got the problem that my mouse events were a bit "off". Now I discovered why: the function scrollContentsBy in qgraphicsview always re-sends the last mouse move event. Since I always saved my current/last mouse position in the mouse move event and calculated the difference and used that as the amount I got wrong values.

My solution: before calling my zoom or translate function call setInteractive(false). This prevents the scrollContentsBy function of re-sending the event. Afterwards set it back to true.