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.
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.