Results 1 to 5 of 5

Thread: Implementing cached rendering of a widget.

  1. #1
    Join Date
    Feb 2010
    Posts
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Implementing cached rendering of a widget.

    Hello,
    Here is the problem. A Widget takes time to render (this is the short explanation) and upon a paintEvent we want to render it in two stages:
    1/ If not already done, render the Widget into a cache (Pixmap)
    2/ Do the actual painting of the Widget using the cache.

    I tried the naive solution below:
    Qt Code:
    1. template <class WIDGET>
    2. class CachedWidget : public WIDGET
    3. {
    4. public:
    5. CachedWidget(QWidget *parent = 0) : WIDGET(parent), m_paintState(Idle) { }
    6.  
    7. virtual void paintEvent ( QPaintEvent * event ) {
    8. switch(m_paintState) {
    9. case Idle: // paint event occurred when widget was 'idle'
    10. m_paintState = Painting;
    11. if(m_cache.size() != QWidget::size()) {
    12. m_cache = QPixmap(QWidget::size());
    13. }
    14.  
    15. // this will somehow trigger a secondary paint event
    16. // this is out of our control
    17. QWidget::render(&m_cache);
    18.  
    19. { QPainter painter(this);
    20. painter.drawPixmap(event->rect(), m_cache, event->rect()); }
    21. m_paintState = Idle;
    22. break;
    23.  
    24. case Painting: // paint event occurred when widget was already painting
    25. WIDGET::paintEvent(event);
    26. break;
    27. }
    28. }
    29.  
    30. private:
    31. enum PaintState { Idle, Painting };
    32. PaintState m_paintState;
    33. QPixmap m_cache;
    34. };
    35.  
    36. int main(int argc, char *argv[])
    37. {
    38. QApplication a(argc, argv);
    39. CachedWidget<QWidget> w;
    40. w.show();
    41. return a.exec();
    42. }
    To copy to clipboard, switch view to plain text mode 

    This 'solution' does not work because to render the Widget into a cache we have to resort to the QWidget::render() function, and this function happens to somehow trigger another paintEvent, and Qt forbids reentrancy in the paintEvent() method.

    The question is the following. When inside the paintEvent() function, is there a way to perform the painting into a QPaintDevice that is different than the Widget that received the QPaintEvent?
    Or is it possible to otherwise implement a caching system similar to the the intention above?

    Another question: since the render() method manages to render a QWidget in a different QPaintDevice, why does it have to send a QPaintEvent to the QWidget?

    Thanks!

  2. #2
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    4,380
    Thanks
    19
    Thanked 1,005 Times in 913 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows Symbian S60
    Wiki edits
    5

    Default Re: Implementing cached rendering of a widget.

    Is it possible that you do the caching direct in WIDGET? if so, your code should work well. Inside the paint event check if your pixmap is still valid. If not, update it. otherwise just paint it. Like you do in your cached variant.

    Why render is sending an update is probably that it want ensure that the right/updated view is rendered.


    And I see right now: Shouldn't it be: WIDGET::render(&m_cache)?

  3. #3
    Join Date
    Feb 2010
    Posts
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Implementing cached rendering of a widget.

    Thanks for your reply.

    Quote Originally Posted by Lykurg View Post
    Is it possible that you do the caching direct in WIDGET? if so, your code should work well. Inside the paint event check if your pixmap is still valid. If not, update it. otherwise just paint it. Like you do in your cached variant.
    Actually, for in the application I have in mind, WIDGET would be QGraphicsView.
    I cannot modify this widget to introduce some caching, short of making a full copy of its code into a custom widget.

    Quote Originally Posted by Lykurg View Post
    Why render is sending an update is probably that it want ensure that the right/updated view is rendered.
    That makes sense.

    Quote Originally Posted by Lykurg View Post
    And I see right now: Shouldn't it be: WIDGET::render(&m_cache)?
    Actually no. When I try to do that with WIDGET=QGraphicsView, it does not compile because a method named render()
    is also defined in QGraphicsView but with a different signature.

    The original problem was to have a QGraphicsView with more than one QGraphicsScene arranged in layers, so that some
    cache could be placed between some of these layers. There no doubt are solutions to this problem. The challenge is to find
    the smartest one.
    One solution (or hack) that works not too bad is to have an invisible QGraphicsView draw itself into a QPixmap that is used as a
    background brush by the visible QGraphicsView.
    The QGraphicsScene that needs to be cached goes into the invisible QGraphicsView.
    The one that is being manipulated and not cached goes into the visible QGraphicsView.
    But there are some imperfections with this solution.

  4. #4
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    4,380
    Thanks
    19
    Thanked 1,005 Times in 913 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows Symbian S60
    Wiki edits
    5

    Default Re: Implementing cached rendering of a widget.

    Quote Originally Posted by emmanuel View Post
    The original problem was to have a QGraphicsView with more than one QGraphicsScene arranged in layers, so that some
    cache could be placed between some of these layers. There no doubt are solutions to this problem. The challenge is to find
    the smartest one.
    One solution (or hack) that works not too bad is to have an invisible QGraphicsView draw itself into a QPixmap that is used as a
    background brush by the visible QGraphicsView.
    As I understand you right you want to design something like a paint program with layer. For now you want to realize that by using different scenes as layers. But how about using QGraphicsItemGroup as layers. than you only need one scene and Qt will handle all the caching stuff for you.

  5. #5
    Join Date
    Feb 2010
    Posts
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Implementing cached rendering of a widget.

    Quote Originally Posted by Lykurg View Post
    As I understand you right you want to design something like a paint program with layer. For now you want to realize that by using different scenes as layers. But how about using QGraphicsItemGroup as layers. than you only need one scene and Qt will handle all the caching stuff for you.
    Thanks for your advice. That is sure a smart solution that I had not thought about before.
    Unfortunately, as soon as I put transparent items in the layer (which is the reason I wanted some cache in the first place)
    the ItemGroup does not seem to be able to cache them as a whole. Maybe it is not meant to, or I am doing something wrong.
    Perhaps there is a way by reimplementing some functions of ItemGroup as regards opacity and such or some other hack
    with flags or anything. I'll check about it but I'm not too hopeful.

Similar Threads

  1. Qt widget for graph rendering, like GrapViz
    By dennis714 in forum Qt Programming
    Replies: 3
    Last Post: 9th July 2013, 21:35
  2. Replies: 2
    Last Post: 30th July 2009, 04:58
  3. Replies: 1
    Last Post: 25th July 2009, 22:16
  4. Trouble with rendering to the widget
    By dosto.walla in forum Qt Programming
    Replies: 4
    Last Post: 29th September 2008, 15:44
  5. Problem rendering QImage from Phonon Widget
    By JimDaniel in forum Qt Programming
    Replies: 2
    Last Post: 12th July 2008, 15:31

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.