[Solved] Get coordinates from mousPressEvent
I’m implementing a simple “window” that should display a bitmap picture with Qt 4.7 / 4.6 (I’ve got a Fedora 14 32 bits machine and a Mandriva 2010.2 64 bits machine). I’ve created a class called BlackBoard that inhertits from QWidget, that has at the moment a “Close” button and another QWidget class called Screen. Screen is just a pixel field that displays a QImage.
I need a method BlackBoard::waitForClick() that waits for the user to click on the picture (i.e on the Screen widget), and then send the (x-y) coordinates (i.e. the clicked pixel from the picture).
I implemented Screen::mousePressEvent, that allows me to get the coordinates in the Screen class. I emit a signal from Screen::mousePressEvent, which is “caught” by a dedicated slot in my BlackBoard class.
The way BlackBoard::waitForClick is implemented is this :
- void BlackBoard::waitForClick( unsigned & x, unsigned & y )
- qApp -> exec()
- // Get the coordinates from the dedicated Screen method
- child -> coordinates( x, y );
- while ( /* ! child was clicked, detected by Screen sending a signal to a BlackBoard slot */ );
and the 2 coordinates are retrieved.
My main.cpp looks like this :
- BlackBoard board( 800, 600, 0xFFFFFF );
- unsigned coordX, coordY;
- board.waitForClick( coordX, coordY );
- cout << coordX << coordY << endl;
The problem I have is that I can click as many time as I want, is always waits for me to close the widget to quit waitForClick. Is there a way to quit the method and get the coordinates as soon as a click on the Screen widget is made?
I may agree on basically any changes in the core implementation, however the interface should be
- create the BlackBoard object
- access / modify pixels of the Screen owned by the Blackboard object
- use waitForClick to select a pixel
and the window should always be on seen and be prone to be real-time modified. I want it to disappear only when the application is closed, not the other way around.
I tried to look for this in various forums, in Qt documentation, but didn’t find anything. I’m thus wondering if there is a way to do this…
Can anybody help?
Why do you need to block while waiting for your click? It sound utterly wrong to block your application to wait for a user interaction like this. Why not just react on a signal that indicates the mouse click?
I think the main problem you run into, is that your waiting actually blocks the mouse handling that you are waiting for.
OK, thanks, I’ll remove the waiting loop. But now I have another problem : from the Screen widget I emit a “clicked( QMouseEvent* )” signal, which is processed by a dedicated slot in BlackBoard, let’s call it BlackBoard::test, implemented like this :
- void BlackBoard::test( QMouseEvent * evt )
- unsigned x1( evt -> x() ), x2( evt -> y() );
- cout << "Clicked at : " << x1 << x2 << endl;
This dummy method nicely print in my terminal the coordinates of every click I do on the picture, which is fine. How can I extract the position from this slot? I need a way to give the x1 and x2 values to waitForClick… how do I do that?
I don’t understand the question. You have successfully printed out the coordinates to the terminal, and now you are wondering how to get the coordinates?
What your main problem (still) is, is that the way your program is structured is off, I think. It looks from your code, that the goal of your app is to output the coordinates of the click on the terminal, and then exit. Right?
So, why not output those coordinates at the place where you actually get them? You can then just exit the application by invoking qApp->quit().
Other tips, based on the code you pasted so far:
- it is probably not a good idea to pass the actual mouse event object along. Just define a signal that emits the x and y, and connect() to that.
- it is more conventional to have your app.exec() and the show() call in your main function.
Well, sorry I wasn’t precise enough in the first place.
The main.cpp snippet actually comes from the earliest test I’ve ever made. At the moment the program is meant to show the coordinates and quit, that’s right. However the goal is to have a semi-interactive picture display, i.e. a picture is shown on the widget, and depending on the coordinate where the user clicks, some processing is performed out of the two presented classes during which the picture is updated pixel by pixel.
My main problem is that I’d like to get the coordinates of the first click (and only the first click), that’s why my method is called waitForClick. Then the processing continues, but the app doesn’t quit till I don’t press the “Close” button. One could imagine a code like this :
- // Create a white BlackBoard
- BlackBoard board( 800, 600, 0xFFFFFF );
- // Select one pixel
- unsigned x, y;
- board.waitForClick( x, y );
- // Let's paint the selected pixel red
- board.setPixel( x, y, 0xFF0000 );
- while ( /* Close button is not clicked */ );
The processing cannot be done within the class : the BlackBoard & co are meant to be a library, which will be used to display pictures created from fractal using genetic algorithms. That’s why I have so strong requirement about the interface of BlackBoard. What I would need is a way to have a “passive” window, that becomes active only when waitForClick is called.
No, no… you are still thinking in terms of running your own program loop. Don’t do that. Let Qt run the event loop, and just respond to events and signals when they happen.
If you want to handle only one mouse click, then just make sure you either only get one by disabling or otherwise blocking the widget after you received the first click, or simply ignore the next mouse clicks at the place where you handle them.
Well, running my own program loop would make my life much easier…
I guess a possibility would be to write a wrapper, that would do the interface between the BlackBoard and the other part of the software, which I already have. This would “solve” the problem of getting only one mouse click, since the mouse click from BlackBoard would be connected to the corresponding action in the “processing code”.
What do you think?