PDA

View Full Version : [GraphicsScene] retrieving click-position



Wirloff
11th April 2007, 08:57
Hallo,

I was wondering: I have a QGraphicsScene with thousands of GraphicsItems on it (placed with a for-lus). No I don't know how to get the position of an item when clicked on one.

I mean, I'm able to ask the position of a specific item from the scene (like:
point = m_ui.graphicsView->mapFromScene(g->mapToScene(g->scenePos()));
But what do I have to make send the Graphics Item a signal or something to the Scene or View when clicked on him??

JonathanForQT4
11th April 2007, 10:23
Hey Wirloff, I was in the same boat as you not too long ago.

It seems you have implemented either graphics view or graphics scene. Either way you will have to do a forward declaration to pass an instance of the graphicsscene or graphicsview to the qgraphicsitem so that the qgraphicsitem can call a method in either the scene or view when the item receives a mousePressEvent(QGraphicsSceneMouseEvent *event).

The qgraphicsitem cannot send signals/or use slots as far as I know since it does not inherit QObject.

Feel free to correct me anyone :)

Forward declaration goes as so in both of the header files (parent and child)

Parent header:
#include "ChildQGraphicsItem.h"

class ChildQGraphicsItem;

Child:
#include "ParentSceneOrView.h"

class ParentSceneOrView;

//edit: so basically it looks like this child receives mouseEvent -> call method in parent pass it the mouse position.

hth,

Jonathan

aamer4yu
11th April 2007, 10:44
jonathan is right... u need to override the mousePressEvent of the graphicsItem...
u will get the position of the item from there...

but in case u want to pass the information of the graphics item to some other class , you can do the following -

1) capture the mousePressEvent in Scene class. u will get the position of the mouse in scene cordinates from the event. From this u can get a list of items present under that position in the scene (using QGraphicsScene::items(QPointF point) ) . Now select the item from the list,,, and from emit a signal from the Scene. In this way u can notify some other class which item was clicked in the scene.

2) try inheriting a class from QGraphicsItem and QObject both... havnt tried myself... but if u can make signal /slot work in graphics item fine... else follow the step 1.


In case u have more doubts, let us know :)

JonathanForQT4
11th April 2007, 13:26
aamer4yu's way would work, but how would you know which item is on top? I guess you could change its colour or something....just seems like a pain to have to go through all the items and somehow distinguish the one you want. All this said, aamer4yu is right this is a viable option.

as for 2) I would be interested to know if this works, but I'm pretty sure the reason for which qgraphicsitems are so much faster to paint, etc. than widgets is because they don't inherit qobject. I'm pretty sure a lot of memory is required each time you create a new instance of a class that inherits it.

so I still would suggest to do a forward declaration and pass the information upwards or is this considered a 'faux pas'?

Wirloff
11th April 2007, 14:52
I managed to do it the second way :) I had to work with multiple inheritance:

class Graphics : public QObject, public QGraphicsItem

I got everything working. But now I have another question (...again :p ):

When pressed on an Item, mousePressEvent calculates the position (using scenePos()) and activates a signal which sends the position. But now i'm trying to release(!) the mouse on an other item, and than again send the position where I released the mouse. I thought I had to recalculate the position in mouseRELEASEEvent, but it seems that he uses theItem where I pressed(!) the mouse. (So scenePos() in mouseReleaseEvent always gives the same position as in MousePressedEvent, although the press & release happen on different items).

Anybody who can think of another way to solve this? Thanx for the help

JonathanForQT4
11th April 2007, 15:33
can you post some sample code pretty please? :)

thanks,

Jonathan

Wirloff
11th April 2007, 15:45
Next two methodes are the mouseEvents from my Graphics class (this is the class which is derived from QGraphicsItem). getStartPosition & getEndPosition are the 2 signals which are sent:


void Graphics::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (brushcolor == Qt::green)
brushcolor = Qt::black;
else
brushcolor= Qt::green;
update();
QPointF point;
point = this->scenePos();
getStartPosition(point);
QGraphicsItem::mousePressEvent(event);

}

void Graphics::mouseReleaseEvent(QGraphicsSceneMouseEve nt *event)
{
if (brushcolor == Qt::green)
brushcolor = Qt::black;
else
brushcolor= Qt::green;
update();
QPointF point;
point = this->scenePos();
getEndPosition(point);
QGraphicsItem::mouseReleaseEvent(event);

}

I've also added a picture, on which you can see that I've place 256 Items nicely on a graphicsScene. But when I click on one, and release on another, the same position is send

JonathanForQT4
11th April 2007, 16:10
maybe you need to set QApplication::doubleClickInterval to a better value or something?

as for getStartPosition & getEndPosition....I'm guessing they are private methods which have the "emit signalName(sendParameterHere)" within them?

the code looks fine to me...:/

sorry I can't be of more help,

Jonathan

aamer4yu
12th April 2007, 05:23
@ Jonathan...

aamer4yu's way would work, but how would you know which item is on top? I guess you could change its colour or something....just seems like a pain to have to go through all the items and somehow distinguish the one you want

well its simple... see the items documentation

Returns all visible items at position pos in the scene. The items are listed in descending Z order (i.e., the first item in the list is the top-most item, and the last item is the bottom-most item). simple, isnt it :)


as for 2) I would be interested to know if this works, but I'm pretty sure the reason for which qgraphicsitems are so much faster to paint, etc. than widgets is because they don't inherit qobject. I'm pretty sure a lot of memory is required each time you create a new instance of a class that inherits it.
i also guess memory wud be required... if the troll guys did it, there must be some reason...







@ Wirloff

Also from ur code, getStartPosition and getEndPosition seems like functions to me. To emit a signal u write the code as "emit signal name" .

Why do u want to capture mouse press on one item , and release event on another item ?? are u trying to drag and drop ??
I would like to know what exactly you want to do.

JonathanForQT4
12th April 2007, 08:26
sorry aamer4yu, I use the same function in my code (yes I read the documentation) except my objects are very transparent and I found it a pain personally. I also thought it would be much easier to simply deal with it in the child class, but as I said before and what you left out in your quote:

All this said, aamer4yu is right this is a viable option.

aamer4yu, as for the signal suggestion, I already mentioned this and to me it does make sense why he defines mouseReleaseEvent in the implemented item class as I would assume that all of his items are an instance of this implemented item class.

aamer4yu
12th April 2007, 10:26
as for ur code,,,, it must be difficult to see the items in near transparent color. but still Z values help a lot... keep the items in higher z value where u expect to get the clicks...

and as for wirloff's code, i am not clear what he is trying to do. I also assume all his items are of the same class.... but the code he gave, i find like changing the color of the item while mouse button is pressed down. The moment u release mouse button, the color changes back to normal. Next say u press on one item A .... move the mouse over other item B , and release mouse on item B.... what do u expect ?? do u expect B to receive the release event ?? if so... it doesnt happens.... i checked it..
i am not sure in this A,B part what he is trying to do....:(