PDA

View Full Version : How to move my own QCanvasItem?



yuhong
13th March 2006, 12:19
Hi, everyone,

I have a CircleItem class which inherits QCanvasEllipse. I reimplement areaPoints() and drawShape(). When I'm trying to move CircleItem, it doesn't work.

Why? what else should I do?



/////////////////////////////////////////////////////////////////////////
class CircleItem : public QCanvasEllipse
{
public:
CircleItem( int cx, int cy, int r, QCanvas *c ) : QCanvasEllipse( c )
{
this->cx = cx;
this->cy = cy;
this->r = r;
}

~CircleItem()
{
hide();
}

QPointArray areaPoints() const
{
QPointArray res(4);
res.setPoint( 0, QPoint( cx-r, cy-r ) );
res.setPoint( 1, QPoint( cx-r, cy+r ) );
res.setPoint( 2, QPoint( cx+r, cy+r ) );
res.setPoint( 3, QPoint( cx+r, cy-r ) );
return res;
}


protected:
void drawShape( QPainter &p )
{
p.drawEllipse( cx-r, cy-r, 2*r, 2*r );
}

private:
int cx;
int cy;
int r;
};

/////////////////////////////////////////////////////////////////////////




Here are two methods that draw a circle on MyCanvasView. The first one uses QCanvasEllipse, it works fine. The second uses my CircleItem, it doesn't work.



void MyCanvasView::drawCircle-1()
{
QPoint p0 = inverseWorldMatrix().map(points[0]);
QPoint p1 = inverseWorldMatrix().map(points[1]);

int r = (int) sqrt( pow(p0.x()-p1.x(),2)+pow(p0.y()-p1.y(),2) );

QCanvasPolygonalItem* i = new QCanvasEllipse(2*r, 2*r, canvas());;
i->move(p0.x(), p0.y());
i->setBrush( Qt::red ); ***********
i->show();

}


void MyCanvasView::drawCircle-2()
{
QPoint p0 = inverseWorldMatrix().map(points[0]);
QPoint p1 = inverseWorldMatrix().map(points[1]);

int r = (int) sqrt( pow(p0.x()-p1.x(),2)+pow(p0.y()-p1.y(),2) );

QCanvasPolygonalItem* i = new CircleItem(p0.x(), p0.y(), r, canvas());;
i->setPen(ROIPEN); ***********
i->show();

}




The Doc says:
Note: QCanvasEllipse does not use the pen.

In my subclass, I used setPen(), because I need to draw the outline of the circle instead of filling it.

Maybe this is the cause?

Can anyone help?

Thanks!

wysota
13th March 2006, 12:34
How do you try to move that item? Make sure boundingRect() returns a correct rectangle, because that's what is used to check for collisions.

yuhong
13th March 2006, 12:49
Thank you, wysota,

Do you mean that I have to reimplement boundingRect() method?

I think the area of areaPoints() is big enough.

Here are two other methods:



void MyCanvasView::contentsMousePressEvent( QMouseEvent * e )
{
// moving
QPoint p = inverseWorldMatrix().map(e->pos());
QCanvasItemList l=canvas()->collisions(p);
for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) {
if ( (*it)->rtti() == QCanvasItem::Rtti_Ellipse ) {
moving = (QCanvasEllipse*) (*it);
moving_start = p;
break;
} else {
continue;
}
}

}

void MyCanvasView::contentsMouseMoveEvent( QMouseEvent *e )
{
// moving
if ( moving ) {
QPoint p = inverseWorldMatrix().map(e->pos());
moving->moveBy(p.x() - moving_start.x(),
p.y() - moving_start.y());
moving_start = p;
canvas()->update();
}

}

wysota
13th March 2006, 12:55
And if you use QCanvasEllipse objects does the move work? And when you substitute them with your subclass they're not collided? Make a check in that for loop to list all the colliding objects to the console.

yuhong
13th March 2006, 13:32
And if you use QCanvasEllipse objects does the move work? And when you substitute them with your subclass they're not collided? Make a check in that for loop to list all the colliding objects to the console.

If I use QCanvasEllipse, I can move the circle (filling with QBrush);

If I use the subclass, I cann't move the circle (only outline). But, the object is really in the QCanvasItemList. (I tried to delete the circle within the for loop, it succeeds).




void MyCanvasView::contentsMousePressEvent( QMouseEvent * e )
{
// moving
QPoint p = inverseWorldMatrix().map(e->pos());
QCanvasItemList l=canvas()->collisions(p);
for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) {
if ( (*it)->rtti() == QCanvasItem::Rtti_Ellipse ) {
delete (*it); /////////////////// it works
break;
} else {
continue;
}
}
}

wysota
13th March 2006, 13:44
If I use the subclass, I cann't move the circle (only outline).

Could you explain that? What outline? Could you post a screenshot?

yuhong
13th March 2006, 13:54
Sorry, I don't know how to post a picture.

The outline is only the circle created by drawShape() in class CircleItem.

yuhong
13th March 2006, 14:05
Here are screenshots.

http://spaces.msn.com/huangyuhong1967/photos/?_c02_owner=1


http://spaces.msn.com/huangyuhong1967/PersonalSpace.aspx?_c11_PhotoAlbum_spaHandler=TWlj cm9zb2Z0LlNwYWNlcy5XZWIuUGFydHMuUGhvdG9BbGJ1bS5Eb3 dubGV2ZWxGdWxsTW9kZUhhbmRsZXI%24&_c11_PhotoAlbum_spaFolderID=cns!5079354E46A67F3F!1 08&_c11_PhotoAlbum_spaNumPhotos=2&_c11_PhotoAlbum_spaPreviousImageID=cns!5079354E46A 67F3F!109&_c11_PhotoAlbum_spaPreviousImageIndex=0&_c11_PhotoAlbum_spaMoveForward=1&_c11_PhotoAlbum_spaPlayState=0&_c=PhotoAlbum&_c02_owner=1

wysota
13th March 2006, 14:16
Can you move() the item manually? Check it please... my guess is that it'll not be possible because you don't change values of cx, cy and r anywhere. You should probably reimplement moveBy() or better yet change your drawShape (and probably other methods too) to use x() and y() values. More or less like so:


void CircleItem::drawShape( QPainter &p ){
p.drawEllipse( x()-r, y()-r, 2*r, 2*r );
}

Use setX() and setY() in your constructor to initialise those values with cx and cy. Of course areaPoints() will need to be changed to use x() and y() too.

yuhong
13th March 2006, 14:37
Finally, it worked!!



Use setX() and setY() in your constructor to initialise those values with cx and cy. Of course areaPoints() will need to be changed to use x() and y() too.


You are absolutely right!

Thank you so much indeed!

Have a nice day!