[Solved] QGraphicsItems not painted if not completely visible



  • Hello,

    I have a problem with my QGraphicsView. As soon as the GraphicsItems on the Scene are not completely visible they are not beeing painted. I want the GraphicsItems to be painted even if they only intersect the SceneRect...
    Is there some kind of flag that needs to be set for the Scene or the GraphicsView in order to fix this?



  • Does your boundingRect() return the correct rectangle?



  • It does, checked that several times...



  • why do you want to paint the area that is not visible? Youre answer might make me suggest a workaround.



  • [quote author="yanbellavance" date="1308177621"]why do you want to paint the area that is not visible? Youre answer might make me suggest a workaround.[/quote]

    As I understand it that is not the problem. The problem is the fact that if an item is/should be partly visible, the part isn't drawn.



  • Drawing a item not in the view is just a waste of time. As already posted, why do you want to do so?Someone can suggest a workaround.



  • In my opinion (partly) drawing an item that is partly visible is not a waste of time.



  • [quote author="Franzk" date="1308203506"]In my opinion (partly) drawing an item that is partly visible is not a waste of time.[/quote]
    It's not partial drawing, EukeSnud says when it is not completely visible

    [quote author="EukeSnud" date="1308203506"]...As soon as the GraphicsItems on the Scene are not completely visible they are not beeing painted....[/quote]



  • "Not completely visible" means to me that there still is (or should be) something visible (but I might have misunderstood it). Obviously for the case of "Completely not visible" I agree. However, it may be wise to write up an example program that show this exact issue, so we all know what we're dealing with.



  • I agree. Without a piece of code to look at we can only speculate as to what is happening and what is required. Perhaps what he is looking for is :

    setAttribute(Qt::WA_OpaquePaintEvent,true);

    bq. Indicates that the widget paints all its pixels when it receives a paint event. Thus, it is not required for operations like updating, resizing, scrolling and focus changes to erase the widget before generating paint events. The use of WA_OpaquePaintEvent provides a small optimization by helping to reduce flicker on systems that do not support double buffering and avoiding computational cycles necessary to erase the background prior to painting.

    Also, I don't know much about QGraphicsItem but if no animations are involved perhaps the use of QPixmap would be usefull.



  • Does this only happen to your custom items, or do the built in items behave in the same way?

    And as I understand it "are not completely visible" != "are completely invisible" so a part of the item should indeed be drawn.



  • [quote author="kkrzewniak" date="1308243451"]And as I understand it "are not completely visible" != "are completely invisible" so a part of the item should indeed be drawn.[/quote]

    You got that right, parts of the items should still be visible. (But they are not :( ) This only happens to my custom items.

    Here's the definition of boundingRect():

    @QRectF MyGraphicsItem::boundingRect() const {
    QPointF pt1 = mapFromScene(QPointF(xmin,ymax));
    QPointF pt2 = mapFromScene(QPointF(xmax,ymin));
    return QRectF(0,0,abs(pt2.x() - pt1.x()), -abs(pt2.y() - pt1.y()));
    }@

    Let me explain the idea of it, if I am mistaken about something feel free to tell me! :)

    The MyGraphicsItem is given in scene-coordinates which are loaded dynamically from a database. Since the boundingRect() method returns a rectangle in item-coordinates, the point (0/0) of the item is in the top-left corner. The scene-coordinates are real world-coordinates so the point (0/0) would be the bottom-left corner and that's why I decided to invert the height of the item's bounding rect.
    xmin,xmax,ymin and ymax give the item's boundings in scene coordinates so the item's (0/0) point in item-coordinates would be (xmin,ymax) in scene coordinates.
    If the whole scene is the current sceneRect() all items are displayed correctly, but if I zoom in so that certain item's would only partly be visible they are not drawn at all. (Sometimes...)



  • I do not understand why you need mapFromScene. The scene coordinates should change and should be the same (in terms of interval not origin) as your item coordinates, while your view coordinates should change when zooming. Shouldn't it be just like this:
    @
    QRectF MyGraphicsItem::boundingRect() const {
    return QRectF(0,0,abs(xmax-xmin), -abs(ymax-ymin));
    }
    @



  • bq. You got that right, parts of the items should still be visible. (But they are not :( ) This only happens to my custom items.

    Since you are sub-classing QGraphicsItem, perhaps the paintEvent function does not always get called. Put a trace or a breakpoint in your paintEvent function and if it does not get called when your item is not completely visible then that is your problem. In this case you should install an event filter and call the your paintEvent function statically from the.



  • [quote author="loladiro" date="1308581073"]I do not understand why you need mapFromScene. The scene coordinates should change and should be the same (in terms of interval not origin) as your item coordinates, while your view coordinates should change when zooming. Shouldn't it be just like this:
    @
    QRectF MyGraphicsItem::boundingRect() const {
    return QRectF(0,0,abs(xmax-xmin), -abs(ymax-ymin));
    }
    @[/quote]

    The API clearly differentiates between scene- and item-coordinates and if I didn't get it completely wrong you have to use mapFromScene because the boundingRect() is given in item-coordinates.

    bq. Items live in a local coordinate system, and like QGraphicsView, it also provides many functions for mapping coordinates between the item and the scene, and from item to item.



  • Am I missing something or is this not okay?

    @ QRectF(0,0,abs(xmax-xmin), -abs(ymax-ymin)); @

    You have a rect with negative height ("-abs(..)")!



  • Have you read this?

    [quote author="EukeSnud" date="1308580346"]The MyGraphicsItem is given in scene-coordinates which are loaded dynamically from a database. Since the boundingRect() method returns a rectangle in item-coordinates, the point (0/0) of the item is in the top-left corner. The scene-coordinates are real world-coordinates so the point (0/0) would be the bottom-left corner and that's why I decided to invert the height of the item's bounding rect.[/quote]



  • Item coordinates have the same scale as scene coordinates. The origin oft the coordinate systems can be different however. That's why there's mapFromScene. I your item is centered at (100,100) (i.e your item (0,0) is at (100,100), then mapFromScene(0,0) will return (-100,-100). Hope that explanation helps.



  • @Euke: Yes, i had read that.

    What I meant is.. the constructor you have used is ambiguous. Why not pass 2 QPointF 's to specify your topLeft and bottomRight, instead of bottomLeft and positive width and negative height? I don't know how the QRectF works internally but you would be better off eliminating such ambiguity.



  • So if my item shall have boundings from xmin to xmax and ymin to ymax ( y growing upwards!) how should I put my boundingRect() and position of the item?

    edit I use the following transformation to invert y-axis
    @QMatrix mirr(1,0,0,-1,0,0);
    QTransform spieg(mirr);@



  • I meant something like.. referring to your original code..

    @
    QRectF MyGraphicsItem::boundingRect() const {
    QPointF pt1 = mapFromScene(QPointF(xmin,ymax));
    QPointF pt2 = mapFromScene(QPointF(xmax,ymin));
    return QRectF(QPointF(0, -abs(pt2.y() - pt1.y())), QPointF(abs(pt2.x() - pt1.x()), 0));
    }
    @

    I don't know if that will solve your problem.. but that is more clear by passing the topLeft and bottomRight.



  • I knew what you meant jim and now my problem seems to be fixed.

    I did the following:
    @node->setPos( (node->getXMax() - node->getXMin()) / 2.0 + node->getXMin(), (node->getYMax() - node->getYMin()) / 2.0 + node->getYMin() );
    scene()->addItem( node );@

    so the the item's center is half between xmin and xmax and half between ymin and ymax.
    The bounding rect is now implemented as follows:
    @QRectF MyGraphicsItem::boundingRect() const {
    QPointF pt1 = mapFromScene(QPointF(xmin,ymin));
    QPointF pt2 = mapFromScene(QPointF(xmax,ymax));
    return QRectF(pt1,pt2);
    }@

    So the boundingRect() lies correctly around the center. The item's are now drawn correctly, even if only partly visible.

    Many thanks to everyone who helped me out of this!

    :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.