Results 1 to 8 of 8

Thread: make a widget paint itself even thought it is not shown

  1. #1
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    258
    Thanks
    22
    Thanked 19 Times in 16 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default make a widget paint itself even thought it is not shown

    Resize and paintevents are queued but not executed when a widget is hidden. They are executed just before the widget is shown. The problem that arises from this is that QPixmap::grabWidget() will return a pixmap that corresponds to how the widget looked before it was hidden and provides some extorted images if the widget has not yet been shown. I am just curious, if it is possible to force a widget to paint itself even though it is not yet shown so grabWidget will return the expected results.

    Thanx in advance

    p.s. I've tried QWidget::render() and repaint() with the same results.

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,013 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: make a widget paint itself even thought it is not shown

    What does "widget looked before it was hidden" means? You mean you change the widget's contents when it's hidden and they are not reflected when you call QPixmap::grabWidget() afterwards? This is hardly possible... Are you sure your code is correct? grabWidget() and QWidget::render() effectively make the widget execute its paintEvent() regardless of its current state.

  3. #3
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    258
    Thanks
    22
    Thanked 19 Times in 16 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: make a widget paint itself even thought it is not shown

    Quote Originally Posted by wysota View Post
    What does "widget looked before it was hidden" means?
    You mean you change the widget's contents when it's hidden and they are not reflected when you call QPixmap::grabWidget() afterwards?
    Yes. Exactly. I resize the widget while the widget is still hidden (it is not the active widget on a QStackedLayout) and then grab the widget. the returned pixmap reflects the size it had before I changed the index.

    Quote Originally Posted by wysota View Post
    This is hardly possible... Are you sure your code is correct? grabWidget() and QWidget::render() effectively make the widget execute its paintEvent() regardless of its current state.
    A trolltech employee on the #qt irc channel on freenode checked it and told me this widget must be shown before grabWidget can take the widget because it will only receive the resize and other events when it is shown, so I assume the code is correct.

    Qt Code:
    1. #include <QtGui>
    2.  
    3. class Transition : public QWidget
    4. {
    5. Q_OBJECT
    6. public:
    7. Transition(QWidget* parent = 0) : QWidget(parent){};
    8. virtual void setDuration(int duration) { m_duration = duration; }
    9. virtual int duration() const { return m_duration; }
    10. virtual void setWidget(QWidget* widget) { m_widget = widget; }
    11. virtual QWidget* widget() const { return m_widget; }
    12. virtual void startTransition(QWidget* before, QWidget* after) = 0;
    13.  
    14. private:
    15. QWidget* m_widget;
    16. int m_duration;
    17. };
    18.  
    19. class TestTransition : public Transition
    20. {
    21. Q_OBJECT
    22. public:
    23. TestTransition(QWidget* parent = 0) : Transition(parent) {
    24. m_timeLine = new QTimeLine(333, this);
    25. connect(m_timeLine, SIGNAL(valueChanged(qreal)),
    26. this, SLOT(onValueChanged(qreal)));
    27. connect(m_timeLine, SIGNAL(finished()),
    28. this, SLOT(onFinished()));
    29. hide();
    30. }
    31.  
    32. void setDuration(int duration) {
    33. Transition::setDuration(duration);
    34. m_timeLine->setDuration(this->duration());
    35. }
    36. void startTransition(QWidget* before, QWidget* after) {
    37. resize(widget()->size());
    38. // Grab Images
    39. m_beforeImage = QPixmap::grabWidget(before).toImage();
    40. QPixmap mp = QPixmap::grabWidget(after);
    41.  
    42. // Set foreground brush
    43. m_fgBrush = QBrush(mp);
    44. m_afterImage = mp.toImage();
    45.  
    46. m_finalImage = m_beforeImage;
    47. int side = qMax(width(), height());
    48. m_radius = (rect().center() + QPoint(side/2, side/2)).manhattanLength();
    49. m_timeLine->start();
    50. show();
    51.  
    52. }
    53. void paintEvent(QPaintEvent* event) {
    54. QPainter p(this);
    55. p.drawImage(0, 0, m_finalImage);
    56. }
    57.  
    58. private:
    59. QTimeLine* m_timeLine;
    60. QImage m_beforeImage;
    61. QImage m_afterImage;
    62. QImage m_finalImage;
    63. QBrush m_fgBrush;
    64. int m_radius;
    65.  
    66. private slots:
    67. void onValueChanged(qreal value) {
    68. QPainter p(&m_finalImage);
    69. p.setRenderHints(QPainter::Antialiasing);
    70. p.setPen(Qt::gray);
    71. p.setBrush(m_fgBrush);
    72. const int r = (int)(m_radius * value);
    73. p.drawEllipse(rect().center(), r, r);
    74. update();
    75. }
    76.  
    77. void onFinished() {
    78. hide();
    79. }
    80. };
    81.  
    82. class MainWindow : public QMainWindow
    83. {
    84. Q_OBJECT
    85. public:
    86. MainWindow(QWidget* parent = 0) : QMainWindow(parent) {
    87. QTextEdit* t = new QTextEdit;
    88.  
    89. // Layout
    90. m_layout = new QStackedLayout;
    91. m_layout->addWidget(w);
    92. m_layout->addWidget(t);
    93.  
    94. // Central Widget
    95. QWidget* cw = new QWidget;
    96. cw->setLayout(m_layout);
    97. setCentralWidget(cw);
    98.  
    99. // Transition
    100. m_transition = new TestTransition(this);
    101. m_transition->setWidget(cw);
    102. m_transition->setDuration(400);
    103.  
    104. QAction* act = new QAction(this);
    105. act->setShortcut(tr("Ctrl+A"));
    106. connect(act, SIGNAL(triggered()), this, SLOT(changePage()));
    107. addAction(act);
    108. }
    109. private:
    110. QStackedLayout* m_layout;
    111. TestTransition* m_transition;
    112.  
    113. private slots:
    114. void changePage() {
    115. int index = m_layout->currentIndex();
    116. index == 1 ? --index : ++index;
    117.  
    118. // Transition
    119. m_transition->startTransition(m_layout->widget(m_layout->currentIndex()),
    120. m_layout->widget(index));
    121. m_layout->setCurrentIndex(index);
    122. }
    123. };
    124.  
    125. int main(int argc, char** argv)
    126. {
    127. QApplication app(argc, argv);
    128. MainWindow mw;
    129. mw.show();
    130. return app.exec();
    131. }
    132. #include "main.moc"
    To copy to clipboard, switch view to plain text mode 
    executing the animation by pressing ctrl + A, resizing the widget and starting the animation again will show the problem. It is solved if setCurrentIndex() is called before the animation starts. I don't have access to the fixed version right now (I'll post it tomorrow) but that doesn't change the problem that QPixmap::grabWidget() seems to return a pixmap that reflects the state of the widget before it was hidden and doesn't seem to repaint itself in reponse to render() or grabWidget().

    Any Ideas ?

    Thanx in advance
    Last edited by momesana; 28th April 2008 at 00:56.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,013 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: make a widget paint itself even thought it is not shown

    Your problem is that widget is only resized for the first time when it is first shown. So it's not a matter of painting a hidden widget, but painting a widget that has not been visible before. There are ways to fake visibility of a widget - you need to set some flags for it, grab its contents and clear the flags again. Also calling ensurePolished() and family could be advisable.

    Aren't you trying to do something like this?
    http://doc.trolltech.com/qq/qq16-fader.html
    http://labs.trolltech.com/blogs/2007...from-the-past/

  5. The following user says thank you to wysota for this useful post:

    momesana (28th April 2008)

  6. #5
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    258
    Thanks
    22
    Thanked 19 Times in 16 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: make a widget paint itself even thought it is not shown

    Quote Originally Posted by wysota View Post
    Your problem is that widget is only resized for the first time when it is first shown.
    Well the problem shows up everytime the widget is resized while hidden.

    Quote Originally Posted by wysota View Post
    There are ways to fake visibility of a widget - you need to set some flags for it, grab its contents and clear the flags again. Also calling ensurePolished() and family could be advisable.
    Sounds promising. I'll try that.

    Quote Originally Posted by wysota View Post
    [/code]
    Exactly . Thanks for the interesting links.

    Thanks a lot

  7. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,013 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: make a widget paint itself even thought it is not shown

    Quote Originally Posted by momesana View Post
    Well the problem shows up everytime the widget is resized while hidden.
    The question is why would you want to resize a widget when it's hidden... it'd be a pure waste of cpu cycles.

  8. #7
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    258
    Thanks
    22
    Thanked 19 Times in 16 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: make a widget paint itself even thought it is not shown

    Quote Originally Posted by wysota View Post
    The question is why would you want to resize a widget when it's hidden... it'd be a pure waste of cpu cycles.
    Well, I don't. All I want is to have grabWidget() take this into consideration before taking the screenshot so it doesn't return outdated pixmaps or pixmaps whose size does not correspond to the actual current size of the widget :-). So I don't question Qt's policy of ignoring (rather postponing ...) such events when the widget is hidden, but the way grabWidget works. It should do whatever is necessary to return a pixmap that resembles the way the widget would look like if it was shown.

  9. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,013 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: make a widget paint itself even thought it is not shown

    grabWidget() grabs the widget at its current state. Calling ensurePolished() might help, although it's a long shot. In general I'd try avoiding grabbing an invisible widget, if I were you. Remember that a widget only has a size when it is visible. In all other situations its size should be treated as undetermined. If you want a dirty hack, use this:
    Qt Code:
    1. widget->show();
    2. qApp->processEvents();
    3. QPixmap px = QPixmap::grabWidget(widget);
    4. widget->hide();
    5. qApp->processEvents();
    To copy to clipboard, switch view to plain text mode 

Similar Threads

  1. Drawing a widget in QItemDelegate's paint method
    By darkadept in forum Qt Programming
    Replies: 17
    Last Post: 11th August 2009, 06:15
  2. Compiling with Qmake/Make
    By VireX in forum Newbie
    Replies: 25
    Last Post: 22nd February 2007, 06:57

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.