PDA

View Full Version : QGraphicsView move item issues.



mrothe
23rd June 2010, 10:47
Hello,

I am new to deveopment with Qt and are currently developing a simple application which let's you create graphical representation of a scene (e.g. a room) with a transmitter and several sensors. I use the QGraphics framework for this task. The "scene edge" is represented by a class derived from QGraphicsRectItem. The transmitter class is derived from QGraphicsEllipseItem and the sensors are derived from QGraphicsPolygonItem. All these objects and the QGraphicsView/QGraphicsScene are part of the UIInputSceneWidget.

I was at a point where I was able to move items separately. I.e. the item under the mouse cursor was moved, when you click, hold and move. But now that I moved a few functions around it doesn't work any more and I cannot figure out why.

There are two possibilities what happens:

1. If I move the scene edge (QGraphicsRectItem) before adding the transmitter or the sensors, then this rectangle is moved wherever I click, hold and move in the QGraphicsView. The rectangle "jumps" under the cursor as soon as I move the mouse. Even if I click outside the rectangle this happens.

2. If I do not move the rectangle before adding the transmitter or the sensors, then I can only move the first item that I added (either the transmitter or the first sensor). This item also "jumps" under the cursor as soon as I click, hold and move on a point in the view.

Here is the code that I suppose is relevant. Please ask for more if this is not sufficient:



class UIInputSceneWidget : public QWidget
{
Q_OBJECT

public:
[...]
signals:
[...]
private slots:
void insertFinished();
void insertSceneEdge(UISceneEdge *newSceneEdge);
void insertSensor(QGraphicsSceneMouseEvent *mouseEvent);
void insertTransmitter(QGraphicsSceneMouseEvent *mouseEvent);
[...]

private:
UIGraphicsScene *scene;
UIGraphicsView *view;

UISceneEdge *sceneEdge;
UITransmitter *transmitter;
QVector<UISensor *> sensors;
[...]
};

void UIInputSceneWidget::insertFinished()
{
if (scene->getMode() == UIGraphicsScene::InsertEdge)
scene->setMode(UIGraphicsScene::MoveItem);
}

void UIInputSceneWidget::insertSceneEdge(UISceneEdge *newSceneEdge)
{
if (sceneEdge == NULL) {
sceneEdge = newSceneEdge;
} else {
delete newSceneEdge;
return;
}
// stuff regarding buttons which is not important here
}

void UIInputSceneWidget::insertSensor(QGraphicsSceneMou seEvent *mouseEvent)
{
if ((sceneEdge == NULL) || !(sceneEdge->pointIsInsideSceneEdge(mouseEvent->scenePos())))
return;

UISensor *newSensor = new UISensor(mouseEvent->scenePos(), sceneEdge);
sensors.push_back(newSensor);

QString str;
str.setNum(sensors.size());
sensorLineEdit->setText(str);
}

void UIInputSceneWidget::insertTransmitter(QGraphicsSce neMouseEvent *mouseEvent)
{
if ((sceneEdge == NULL) || !(sceneEdge->pointIsInsideSceneEdge(mouseEvent->scenePos())))
return;

UITransmitter *newTransmitter = new UITransmitter(mouseEvent->scenePos(), sceneEdge);
transmitter = newTransmitter;

transmitterButton->setChecked(false);
transmitterButton->setEnabled(false);
scene->setMode(UIGraphicsScene::MoveItem);
setTransmitterLocationLabel();
}




class UIGraphicsScene : public QGraphicsScene
{
Q_OBJECT

public:
enum Mode { InsertEdge, InsertTransmitter, InsertSensor, MoveItem };
void setMode(Mode mode);
[...]

signals:
void insertFinished();
void insertSceneEdge(UISceneEdge *sceneEdge);
void insertSensor(QGraphicsSceneMouseEvent *mouseEvent);
void insertTransmitter(QGraphicsSceneMouseEvent *mouseEvent);
[...]

protected:
void drawBackground(QPainter *painter, const QRectF &rect);
void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent);
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent);

private:
Mode myMode;
QPointF firstPointOfSceneEdge;
};

void UIGraphicsScene::mouseMoveEvent(QGraphicsSceneMous eEvent *mouseEvent)
{
if (myMode == InsertEdge) {
qreal x1 = firstPointOfSceneEdge.x();
qreal x2 = mouseEvent->scenePos().x();
qreal y1 = firstPointOfSceneEdge.y();
qreal y2 = mouseEvent->scenePos().y();
QPointF topLeft;
QPointF bottomRight;

if (x1 < x2) {
topLeft.setX(x1);
bottomRight.setX(x2);
} else {
topLeft.setX(x2);
bottomRight.setX(x1);
}

if (y1 < y2) {
topLeft.setY(y1);
bottomRight.setY(y2);
} else {
topLeft.setY(y2);
bottomRight.setY(y1);
}

emit setSceneSize(QRectF(topLeft, bottomRight));
} else if (myMode == MoveItem) {
QGraphicsScene::mouseMoveEvent(mouseEvent);
emit moveEvent(); /* for updating labels and stuff */
}
}

void UIGraphicsScene::mousePressEvent(QGraphicsSceneMou seEvent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton)
return;

switch (myMode) {
case InsertEdge: {
firstPointOfSceneEdge = mouseEvent->scenePos();
UISceneEdge *sceneEdge = new UISceneEdge(QRectF(firstPointOfSceneEdge,
firstPointOfSceneEdge));
addItem(sceneEdge);
emit insertSceneEdge(sceneEdge);
emit setSceneSize(QRectF(firstPointOfSceneEdge,
firstPointOfSceneEdge));
break;
}
case InsertSensor: {
/* The sensor cannot be inserted directly because the pointer to
* the sceneEdge is not stored in this object, but in
* UIInputWidget. Let that object create and add the sensor. */
emit insertSensor(mouseEvent);
break;
}
case InsertTransmitter: {
/* Same reason as above! */
emit insertTransmitter(mouseEvent);
break;
}
default:
;
}
QGraphicsScene::mousePressEvent(mouseEvent);
}

void UIGraphicsScene::mouseReleaseEvent(QGraphicsSceneM ouseEvent *mouseEvent)
{
emit insertFinished();
}


UIGraphicsView is derived from QGraphicsView and just reimplements keyPressEvent(), wheelEvent() and scaleView(). Nothing special there...

A screenshot showing the application is attached. This might help you understand the situation.

I really don't know what happens... Please help me. :(

Regards,

Markus

EDIT: It might not be clear enough what I want: I want that the item under the mouse cursor moves. If it is the transmitter, then the transmitter should move. If it is a sensor then the sensor should move. If the rectangle is below the cursor then, the rectangle and it's children should move.

tbscope
23rd June 2010, 11:15
Use the following flags on your items:
QGraphicsItem::ItemIsMovable
QGraphicsItem::ItemIsSelectable (if needed)
QGraphicsItem::ItemSendsGeometryChanges

More flags:
http://doc.qt.nokia.com/4.6/qgraphicsitem.html#GraphicsItemFlag-enum

QGraphicsView lets you move items out of the box, you don't need to add code for that. You only need to add code to handle the items in detail, like what to do when selecting an item or what happens if you move the item.

mrothe
23rd June 2010, 12:30
Thank you for the answer. Unfortunately it does not solve my problem. ItemIsMovable was already set to true.

Setting ItemIsSelectable and ItemSendsGeometryChanges to true does not change much: It is only shown that the item I can move (the same items I could move before) are now selected. I cannot "unselect" this item or select another one.

mrothe
28th June 2010, 17:23
I found the reason for the behaviour: In UIGraphicsScene::mouseReleaseEvent I forgot to pass the mouseEvent on to QGraphicsScene::mouseReleaseEvent:



void UIGraphicsScene::mouseReleaseEvent(QGraphicsSceneM ouseEvent *mouseEvent)
{
emit insertFinished();
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}