Results 1 to 6 of 6

Thread: QGraphicsView and many QGraphicsPixmapItem items - memory managment

  1. #1
    Join Date
    Nov 2011
    Posts
    5
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default QGraphicsView and many QGraphicsPixmapItem items - memory managment

    Hello!

    I'm working on project focused on map similar to Google Maps. The goal is to display whole map in QGraphicsView widget. To do this I created a QGraphicsScene built of many QGraphicsPixmapItem items. Each item stands for one map tile (A small PNG graphic). Because map is quite large (it's square of about 512x512 tiles and more) I'm trying to load tiles on demand (when they're visible in QGraphicsView widget's viewport area).

    Some parts of code:

    I create all tiles (QGraphicsPixmapItem items) at the beginning and set them with "empty" QPixmap:
    Qt Code:
    1. MapTile::MapTile(int zoomLevel, ...)
    2. {
    3. bool returnStatus (false);
    4.  
    5. returnStatus = QFile::exists(this->tilePath);
    6. if(!returnStatus)
    7. {
    8. qWarning("Faield to locate tile PNG!");
    9. return;
    10. }
    11.  
    12. this->setPixmap(QPixmap (256, 256));
    13. this->setPos (this->pixelsPosition.getX(), this->pixelsPosition.getY());
    14. }
    To copy to clipboard, switch view to plain text mode 

    Then I add each tile to scene.

    I created class based on QGraphicsView named MapView and overloaded resizeEvent() and scrollContentsBy() methods. Code sample below shows only scrollContentsBy(), resizeEvent() is analogous.

    First thing, I map top-left and bottom-right corners of QGraphicsView object into scene coordinates (pointa, pointb). Later in first loop I unload (load "empty" pixmap) all items assigned to scene (I know, it's stupid to unload all tiles, but I will make this part of code smarter later). In next two nested loops I pick only items currently visible in QGraphicsView object and load pixmaps into them.
    Qt Code:
    1. void MapView::scrollContentsBy ( int dx, int dy )
    2. {
    3. this->QGraphicsView::scrollContentsBy(dx,dy);
    4.  
    5. MapScene* currentScene = this->zoomLevelScenes [this->currentZoomLevel];
    6. QPointF pointa (this->mapToScene(0, 0)); // top-left
    7. QPointF pointb (this->mapToScene(this->height(), this->width())); //bottom-right
    8. QList<QGraphicsItem*> list = currentScene->items();
    9.  
    10. foreach(QGraphicsItem* item, list)
    11. {
    12. ((MapTile*)item)->loadPixmap(false);
    13. }
    14.  
    15. for (qreal x = pointa.x() - 300; x < pointb.x() + 300; x += 255)
    16. {
    17. for (qreal y = pointa.y() - 300; y < pointb.y() + 300; y += 255)
    18. {
    19. MapTile* tile ((MapTile*) currentScene->itemAt(x,y));
    20. if (tile!=0)
    21. tile->loadPixmap(true);
    22. }
    23. }
    24. }
    To copy to clipboard, switch view to plain text mode 

    My MapTile::loadPixmap() method:
    Qt Code:
    1. void MapTile::loadPixmap(bool status)
    2. {
    3. QPixmap pixmap (256, 256);
    4. bool returnStatus (false);
    5.  
    6. if (status)
    7. {
    8. returnStatus = pixmap.load(this->tilePath);
    9. if(!returnStatus)
    10. {
    11. qWarning("Faield to load tile PNG!");
    12. return;
    13. }
    14. }
    15.  
    16. this->pixmapLoaded = status;
    17. this->setPixmap(pixmap);
    18. }
    To copy to clipboard, switch view to plain text mode 

    Code seems to work fine, because folder with tiles has about 500 MB and my program after start use only about ~25 MB. I also see correct map in window (there are no blank tiles displayed). The problems is that when I scroll map or resize window program is slowly, but constantly allocating more and more memory (on single resize event it allocates another 0.2 - 0.4 MB of RAM). After some time of working with program it becomes serious.

    Any idea what's wrong? I assume, that I'm doing something wrong, right? Or maybe I'm not aware of some data chaching method used in Qt? I worked a lot with GTK+ and i'm pretty new to Wt...
    Last edited by goofacz; 17th November 2011 at 16:03.

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicsView and many QGraphicsPixmapItem items - memory managment

    Your loadPixmap( false ) isn't really clearing the pixmap, it is simply setting it to a blank pixmap of the same size as the tiles. So, even if you are scrolling tiles out of the view, you really aren't getting rid of the memory they use.

    Change the logic in loadPixmap so that if "status" is false, you call setPixmap( QPixmap() ) so it really is empty.

    By the way, it is never necessary to call member functions with "this->" when you are inside the class. It is also odd that you use constructor syntax when you define a local variable:

    Qt Code:
    1. bool returnStatus( false );
    To copy to clipboard, switch view to plain text mode 

    is very unusual for native types, and I had to stop and think about that. Of course it is correct, just unusual. For native types, you usually see the more common form of declaration and assignment:

    Qt Code:
    1. bool returnStatus = false;
    To copy to clipboard, switch view to plain text mode 

    Is there some reason why you use the first method?

  3. #3
    Join Date
    Nov 2011
    Posts
    5
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsView and many QGraphicsPixmapItem items - memory managment

    Thank you for response, I'll check if it works for me as soon as it's possible

    About variables initialization and using "this->". It's part of coding style, which we worked out with friends at university. It gives us common syntax for variables initialization (so it does not matter if we initialize class object or primitive type variable) and unambiguous statements meaning (for example when we have in class field named "foo" and use "foo" as an argument's name in one of methods in the same class). We don't like to have special name pattern for class fields (e.g. add prefix "m_"). We prefer to write:
    Qt Code:
    1. Foo* bar (0);
    To copy to clipboard, switch view to plain text mode 
    instead of:
    Qt Code:
    1. Foo *bar (0);
    To copy to clipboard, switch view to plain text mode 
    because in our opinion "Foo*" stand for valid name type in C++ etc. We have pertty much other "rules"

    Code you see above is a "working draft" Final version is always much more elegant, it has intuitive variables naming, better intending etc.
    Last edited by goofacz; 18th November 2011 at 00:01.

  4. #4
    Join Date
    Nov 2011
    Posts
    5
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsView and many QGraphicsPixmapItem items - memory managment

    @d_stranz, your idea does'n work for me. When I set item to QPixmap() in result I see... nothing. i does not matter if I try to resize it or not, it's always white. My scene does to not work properly at all, because I don't see scroll bars. I seems that, when I set item with QPixmap() it's being removed from scene at all (my scene should be really huge). Note that I set item's position manually in MapTile constructor.

    Any other idea? Maybe there is any way to get rid of pixmap caching...?

  5. #5
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicsView and many QGraphicsPixmapItem items - memory managment

    Later in first loop I unload (load "empty" pixmap) all items assigned to scene (I know, it's stupid to unload all tiles, but I will make this part of code smarter later). In next two nested loops I pick only items currently visible in QGraphicsView object and load pixmaps into them.
    Maybe there is any way to get rid of pixmap caching...?
    I don't think this has anything to do with pixmap caching, if that even occurs. The problem with memory is that as long as you keep adding more tiles, the memory use will continue to grow. Do you ever -remove- a QGraphicsItem from the scene? From what I can see of your code, you just keep adding them. As the user moves around the map, more and more tiles are added, and memory continues to grow. Your first statement about "unloading" pixmaps simply isn't true - you are -emptying- the pixmap and setting all the pixels to whatever the default value is, but you aren't "unloading" anything from memory. A 256 x 256 pixmap still occupies the same memory, no matter what color the pixels are. Setting it to QPixmap( 256, 256 ) just changes the color but doesn't reduce the size at all.

    Unless you get rid of the QGraphicsItems (or their pixmaps) for tiles that are no longer visible on the screen, these will still use memory. Setting their contents to an empty pixmap (QPixmap()) -will- reduce their memory use, but apparently you are using the actual size of the pixmap when you calculate the bounding rectangle for each item. A pixmap with zero dimensions will screw up the calculations, as you see.

    So, I think that if your tile size is fixed at 256 x 256, then that's what you return for the bounds, whether a pixmap is loaded or not. Then the computation for overall scene size will be correct even if no pixmaps are loaded. Next, you need to get rid of the storage used for pixmaps that are not visible. Either keep the tile item around but set it to an empty pixmap (like I suggested), or actually remove it completely. If you remove it, you need to make sure the scene still returns the correct bounding rect so the scrollbars work properly.

  6. #6
    Join Date
    Nov 2011
    Posts
    5
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsView and many QGraphicsPixmapItem items - memory managment

    Hello!

    Thanks, when I set fixed scene size and set items with QPixmap() it solved problem

    There was a problem however, like you saw I mapped viewport coordinates to scene coordinates:
    Qt Code:
    1. QPointF pointa (this->mapToScene(0, 0)); // top-left
    To copy to clipboard, switch view to plain text mode 
    and then I used QGraphicsScene::itemAt() to find "truly" visible items. The problem is that after setting item's pixmap empty, it's dimensions is 0x0 pixels I added new field to MapTile class, which holds top-left coordinates of tile so I able to calculate it given tile is in visible area or not quite fast.

    Than you for help!

Similar Threads

  1. QGraphicsView + steady Items
    By medved6 in forum Qt Programming
    Replies: 2
    Last Post: 25th August 2010, 19:20
  2. Changing memory allocation managment ( QT 4.4.3 )
    By Link130 in forum Qt for Embedded and Mobile
    Replies: 3
    Last Post: 20th October 2009, 09:44
  3. QGraphicsView properties and performance/memory
    By vkokk in forum Qt Programming
    Replies: 4
    Last Post: 16th July 2009, 18:12
  4. Memory Managment Question
    By tntcoda in forum Qt Programming
    Replies: 4
    Last Post: 25th June 2008, 16:34
  5. QGraphicsView overlapping items
    By juliarg in forum Newbie
    Replies: 1
    Last Post: 5th April 2007, 09:35

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.