PDA

View Full Version : Problem with qgraphicsitem_Cast



kokeroulis
20th September 2010, 11:18
Hello

I have already search to the forum but i have not found something that it might help me (or at least, this is what i think)....

I have 2 sub-classes....The 1st is for the QGraphicsScene(graph_scene) and the 2nd is for the QGraphicsEllipseItem(piece).... From the graph_scene using the Q_FOREACH i am trying to make some changes into the objects of the sub-class piece....The objects of the sub-class piece has "Zvalue==2".... The problem is that when the program call the qgraphicsitem_cast it crash with the error "Segmentation fault"....I debug the program and i found that it crash on the line "Return Piece_Clicked;"


piece.h


class piece : public QGraphicsEllipseItem
{

public:
piece(graphics *ellipse,int);
int ReturnPieceClicked();
virtual ~piece();
enum { Type = UserType + 1 };

int type() const
{
return Type;
}
protected:
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
private:
QList<QGraphicsEllipseItem *> EllipseList;
int Piece_Clicked;
int Piece_atibue;
};
#endif // piece_H

piece.cpp




.
.
.

void piece::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
if(Piece_Clicked!=0 || Piece_Clicked!=1) {
Piece_Clicked=0;
}
if(event->button()==Qt::LeftButton) {
setBrush(QBrush(Qt::darkMagenta));
qDebug() << "Piece Clicked" <<Piece_Clicked;
Piece_Clicked++;
if(Piece_Clicked!=1) {
Piece_Clicked=0;
qDebug() << "step 2";
}
}
}

int piece::ReturnPieceClicked()
{
return Piece_Clicked;//this is the real place where the program is crashed....
}

graph_scene.cpp


void graph_scene::mousePressEvent(QGraphicsSceneMouseEv ent* event)
{
if(ClickCounter>2 || ClickCounter<0) {
MoveDone=0;
ClickCounter=0;
}
QGraphicsScene::mousePressEvent(event);
if(event->button()==Qt::LeftButton) {
ClickCounter++;

qDebug() << "left click is working";
if(ClickCounter==2) {
Q_FOREACH(QGraphicsItem *item,items()) {
if(item->zValue()==1) {
qDebug() <<qgraphicsitem_cast<piece*>(item) << "koker";
if(qgraphicsitem_cast<piece*>(item)->ReturnPieceClicked()==1)
qDebug() <<"it works";
if(abs(item->pos().x())-abs(event->pos().x())==50)
qDebug() << "x ok";
if(abs(item->pos().y())-abs(event->pos().y())==25)
qDebug() << "y ok";
}

if(item->ReturnPieceClicked==1) {//it crash here...with a first look
qDebug() << MoveDone << "before move";

if(item->zValue()==2 && MoveDone==0) {
qDebug() << event->scenePos() << "scene";
item->setPos(event->scenePos());
MoveDone++;
ClickCounter=0;
}
//}
}
}
}
qDebug() << "step 1";
qDebug() << ClickCounter << "counter";
qDebug() << MoveDone << "after move";

}

Please can you help me?

JohannesMunk
20th September 2010, 12:01
Hi there!

1) What do you want to achieve? I don't get what this Piece_Clicked is supposed to do.

2) The code you provided, wouldn't compile. In your graph_scene item is a QGraphicsItem* and without proper typecasting you try to call ReturnPieceClicked() in line 24. The compiler would complain!

3) Typecasting in general (qobject_cast, dynamic_cast, ...) is done like this:



// item is somehow initialized..
QGraphicsItem* item = ..
// the typecasting is done. if it fails it will return a 0 pointer.
piece* p = qgraphicsitem_cast<piece*>(item);
// here you check if item really was of type piece.
if (p != 0) {
// Here the compiler doesn't complain, because he knows that p is of type piece*.
p->ReturnPieceClicked();
}


HIH

Johannes

wysota
20th September 2010, 13:27
if(qgraphicsitem_cast<piece*>(item)->ReturnPieceClicked()==1)
If the cast fails then you get a null pointer and dereferencing it leads to a crash.

kokeroulis
20th September 2010, 15:03
thank you both.... I will try it and i will let you know...

I am trying to create a scene with pieces...In which with the first click it will be selected the piece which is going to be moved and with the second it will be moved somewhere is the scene....I know that i can do it with the method grub n drop but i want to do it with the method point and click....

wysota
20th September 2010, 15:45
And what do you need qgraphicsitem_cast for?

JohannesMunk
20th September 2010, 17:05
How about subclassing QGraphicsScene.

Reimplement mousePressEvent, mouseMoveEvent, mouseReleaseEvent accordingly.

use scene.itemAt( .. ) with the mouseEvent position.

if you want you can either use the scenes.selectedItems or manage the selection yourself.

HIH

Johannes

kokeroulis
21st September 2010, 09:20
I need the qgraphicsitem_cast because i am using the scene.items() with the Q_FOREACH to create a loop with all the items of the scene....And the qgraphicsitem_cast because i want to use on them some custom functions that i have created....


How about subclassing QGraphicsScene.

Reimplement mousePressEvent, mouseMoveEvent, mouseReleaseEvent accordingly.

use scene.itemAt( .. ) with the mouseEvent position.

if you want you can either use the scenes.selectedItems or manage the selection yourself.

HIH

Johannes


I did something like that but i have a small problem.... As regards my code everything works fine but when i am choosing a "piece" and i am clicking somewhere in the scene, then it moves but not in the place in which i have click but near to it....I have tried to move it with the following ways....But none of them doesn't work right....


setPos(event->screenPos());
setPos(event->pos());
setPos(event->scenePos());

JohannesMunk
21st September 2010, 09:45
The problem is that you somehow need to save the relative position of the mousecursor and the item when you start moving. If you just set the position of the item to the mouseCursors position you will move the items origin (0,0) to that position and not the center or wherever you might have clicked.

There are several ways to do that:

1) only use deltas:
item->setPos(item->pos() + event->scenePos() - event->lastScenePos() );

2) store everything:
Wherever you start your move action, store in member variables 1) the item-scenePos (startItemPos) and 2) the event-scenePos (startMousePos). If you want to support moving multiple items, store a list of their startPositions. In mouseMove set the item-position to: item->setPos( startItemPos + event->scenePos() - startMousePos);

HIH

Joh

kokeroulis
21st September 2010, 10:11
The problem is that you somehow need to save the relative position of the mousecursor and the item when you start moving. If you just set the position of the item to the mouseCursors position you will move the items origin (0,0) to that position and not the center or wherever you might have clicked.

There are several ways to do that:

1) only use deltas:
item->setPos(item->pos() + event->scenePos() - event->lastScenePos() );

2) store everything:
Wherever you start your move action, store in member variables 1) the item-scenePos (startItemPos) and 2) the event-scenePos (startMousePos). If you want to support moving multiple items, store a list of their startPositions. In mouseMove set the item-position to: item->setPos( startItemPos + event->scenePos() - startMousePos);

HIH

Joh

I am not using the method drug 'n drop but the point 'n click (i select the "piece" and then i click there which i wanted to be moved....) I tried the 1) but the piece doesn't do nothing...because it is moving in the same position....

JohannesMunk
21st September 2010, 10:20
I understand your point'n'click well.. that just changes where you start stuff.

The piece does nothing? What do you mean same position?

kokeroulis
21st September 2010, 10:40
I understand your point'n'click well.. that just changes where you start stuff.

The piece does nothing? What do you mean same position?

i use the 1) method....I mean that it moves but it goes to the same place....(It is something wrong with the "item->pos() + event->scenePos() - event->lastScenePos() ") because the piece is moving into the current position....E.X. if it is into the (210,150) before the click, after it will be into the (210,150)....So it moves but it goes-reach into the same place....

JohannesMunk
21st September 2010, 10:42
The code is fine, but you need to enable Mousetracking and hoverEvents:



class Scene : public QGraphicsScene
{
public:
Scene() {underMouse = 0;}
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent )
{
if (underMouse != 0)
{
underMouse->setPos(underMouse->pos() + mouseEvent->scenePos() - mouseEvent->lastScenePos());
qDebug() << mouseEvent->scenePos() - mouseEvent->lastScenePos();
}
QGraphicsScene::mouseMoveEvent(mouseEvent);
}

void mouseReleaseEvent ( QGraphicsSceneMouseEvent * mouseEvent )
{
if (underMouse == 0)
underMouse = itemAt(mouseEvent->scenePos());
else
underMouse = 0;
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}

private:
QGraphicsItem* underMouse;
};

class Piece : public QGraphicsItem
{
public:
Piece() {
setAcceptHoverEvents(true);
}
QRectF boundingRect() const{ return QRectF(0, 0, 50, 50); }

void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget)
{
painter->drawRect(boundingRect());
}
};


MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
scene = new Scene();

Piece* piece = new Piece();
scene->addItem(piece);

graphicsView = new QGraphicsView(this);
graphicsView->setMouseTracking(true);

graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
graphicsView->setScene(scene);
graphicsView->show();

graphicsView->setGeometry(QRect(50, 50, 500, 300));

this->setCentralWidget(graphicsView);

}


Joh

wysota
21st September 2010, 12:11
I need the qgraphicsitem_cast because i am using the scene.items() with the Q_FOREACH to create a loop with all the items of the scene....And the qgraphicsitem_cast because i want to use on them some custom functions that i have created....
You don't need this cast for that. Have all the items inherit a common (custom) subclass of QGraphicsItem and place all the methods in the common subclass as virtual methods and them reimplement them in the final classes. Then you'll be able to call them directly. Alternatively implement the methods in your scene and make overloads for them for each of your item classes.

kokeroulis
21st September 2010, 16:55
Hello

i have manage to do it...Thank you for your help....All of you...