View Full Version : Keep Cursor in a widget

24th January 2010, 17:13
Hello dear QT-Community,

i am developing kind of a game and encounter the following problem: I have a GraphicsScene which represents the map of the game. With a GraphicsView I display this map. Now I want to remove the scrollbars (haven't done this yet but can't be that hard) and use the mouse to scroll now. At the right side of the Map there is a Panel which displays details about the current GraphicsItem. I think everyone who ever played a strategy game on PC can imagine what I mean ;)
So scrolling shall occur when the mouse reaches one of the edges of my GraphicsView widget. And of course the Cursor must not be allowed to leave that widget. Unfortunately i was not able to implement this in a elegant way.

When I try something like this, my Cursor is always removed from the View widget when I try to enter it. I set it in the center of the View before. But it gets thrown out immediately.

void MapView::mouseMoveEvent(QMouseEvent *event){
if (event->type() & QEvent::Leave){
QPoint newPos(event->x(), event->y());
QPointF newCenter = currentCenter();
centerOn(newCenter.x() + this->width()/10, newCenter.y() + this->height()/10);

Any ideas are very welcome.


24th January 2010, 19:02
I'm not sure if this will help you but check this function
grabMouse (); (http://doc.trolltech.com/4.6/qwidget.html#grabMouse)

24th January 2010, 19:35
i always get a runtime eror when i include this line in my code like that:

QHBoxLayout* layout = new QHBoxLayout();

scene = new MapScene();

view = new MapView(scene, this);
view->centerOn(1000, 1000);
connect(view, SIGNAL(changeFullScreen()), this, SLOT(changeFullScreen()));
connect(this, SIGNAL(mouseMovedOutOfView(QPoint)), view, SLOT(mouseMovedOutOfWindow(QPoint)));

panel = new MapPanel();

connect(view, SIGNAL(mouseMoved(QPointF,QPointF)), panel, SLOT(newCoordinates(QPointF,QPointF)));

QWidget* widget = new QWidget();


connect(scene, SIGNAL(sendData(int)), panel, SLOT(showID(int)));

If I include the mouseGrap like this i get no Runtime error:

void MapView::keyPressEvent(QKeyEvent* event){
switch (event->key()){
case Qt::Key_B:

But now the MapView won't get any MouseMoveEvent. The MainWindow still gets them but here the track does not work. I i set MainWindow->setTrackingMouse(true) nothing is different.

It would work if my MainWindow AND my view would be able to track the mouse. Unfortunately they seem to be unable :(

Do you have any idea why I always get the runtime error when include grapMouse staticly?

25th January 2010, 04:09
Check this link
and the attach example. This will work partially.
The mouse move event will detect global coordinates and put the mouse inseide the cliente area, if he gets near the margins.
The problems his that if the users moves to quiclly the mouse will move outside anyway. And once outside the client area it will not call
the mouse event function.
A workaround could be a timer to call mousemove event, then the mouse will always be put inside the client area.

I remenber doing this in Visualc MFC, there was function SetCapture() that would capture the mouse inside the cliente area, but I didnt find any Qt similar function.

25th January 2010, 10:58
Thanks for your answers so far. This is basicly what i tried before. Your example works fine for me and I agree with you that one could solve the issue of fast mouse moving with a timer. But if I try to implement this in my program it does not work. I had a look at the debugger and i think my geometry does not work properly. And I think this might be because i did something wrong with the derivation of my classes.

Would it help if I post my whole code here or what informations are required to help me with this issue?

I have the problem that the upper and the left margin are ca. as twice as big as the lower and the right margin. Anyone has an idea why this is the case?

void MapView::mouseMoveEvent(QMouseEvent *event){
int marginThickness = 30;

int globalX = event->globalX();
int globalY = event->globalY();

int geoX = geometry().x();
int geoY = geometry().y();

QPoint globalGeo (this->mapToGlobal(QPoint(geoX, geoY)));

QPoint newPos(globalX, globalY);

if (globalY < globalGeo.y() + marginThickness){
newPos.setY(globalGeo.y() + marginThickness);
} else if (globalY > globalGeo.y() + height() - marginThickness){
newPos.setY(globalGeo.y() + height() - marginThickness);
if (globalX < globalGeo.x() + marginThickness){
newPos.setX(globalGeo.x() + marginThickness);
} else if (globalX > globalGeo.x() + width() - marginThickness){
newPos.setX(globalGeo.x() + width() - marginThickness);

25th January 2010, 20:22
Remove mapToGlobal from line 10, you dont need it sense geometry() is already global. Then check if it works :)

29th January 2010, 19:51
I am afraid this does not work. If I remove the mapToGlobal the following happens:

The area that can't be left by the Cursor stays in the top left corner of the screen. If i move the application a bit down and a bit right the boarder to the bottom and to the right become larger and i can leave the application to the top and the left of the frame because it won't get any mouseEvent then.

If you want i can send you the whole code zipped. I think this makes things much easier.

31st January 2010, 00:03
Can you show me a printscreen of your game, and point the area where the cursor should be grabbed ?

1st February 2010, 13:38
Okay. Here we go:


This is how it looks at the moment. All things painted in red are included by me with photoshop and not part of the program. I want to keep the Cursor within the red rectangular. A and B indicate the width and the height of QGraphicsView. C and D show the actual Position of the Cursor in the QGraphicsView. This works correct so far. I just can't get the correct coordinates to set the Cursor when it is close the edge of the widget.

Thanks for your constant help by the way. I am sure we can manage this ;)


6th February 2010, 19:24
I figured it our myself now. Thanks for your help though.