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.
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.
Re: make a widget paint itself even thought it is not shown
Quote:
Originally Posted by
wysota
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
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.
Code:
#include <QtGui>
{
Q_OBJECT
public:
virtual void setDuration(int duration) { m_duration = duration; }
virtual int duration() const { return m_duration; }
virtual void setWidget
(QWidget* widget
) { m_widget
= widget;
} virtual QWidget* widget
() const { return m_widget;
}
private:
int m_duration;
};
class TestTransition : public Transition
{
Q_OBJECT
public:
TestTransition
(QWidget* parent
= 0) : Transition
(parent
) { connect(m_timeLine, SIGNAL(valueChanged(qreal)),
this, SLOT(onValueChanged(qreal)));
connect(m_timeLine, SIGNAL(finished()),
this, SLOT(onFinished()));
hide();
}
void setDuration(int duration) {
Transition::setDuration(duration);
m_timeLine->setDuration(this->duration());
}
resize(widget()->size());
// Grab Images
m_beforeImage
= QPixmap::grabWidget(before
).
toImage();
// Set foreground brush
m_afterImage = mp.toImage();
m_finalImage = m_beforeImage;
int side = qMax(width(), height());
m_radius
= (rect
().
center() + QPoint(side
/2, side
/2)).
manhattanLength();
m_timeLine->start();
show();
}
p.drawImage(0, 0, m_finalImage);
}
private:
int m_radius;
private slots:
void onValueChanged(qreal value) {
p.
setRenderHints(QPainter::Antialiasing);
p.setPen(Qt::gray);
p.setBrush(m_fgBrush);
const int r = (int)(m_radius * value);
p.drawEllipse(rect().center(), r, r);
update();
}
void onFinished() {
hide();
}
};
{
Q_OBJECT
public:
// Layout
m_layout->addWidget(w);
m_layout->addWidget(t);
// Central Widget
cw->setLayout(m_layout);
setCentralWidget(cw);
// Transition
m_transition = new TestTransition(this);
m_transition->setWidget(cw);
m_transition->setDuration(400);
act->setShortcut(tr("Ctrl+A"));
connect(act, SIGNAL(triggered()), this, SLOT(changePage()));
addAction(act);
}
private:
TestTransition* m_transition;
private slots:
void changePage() {
int index = m_layout->currentIndex();
index == 1 ? --index : ++index;
// Transition
m_transition->startTransition(m_layout->widget(m_layout->currentIndex()),
m_layout->widget(index));
m_layout->setCurrentIndex(index);
}
};
int main(int argc, char** argv)
{
MainWindow mw;
mw.show();
return app.exec();
}
#include "main.moc"
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
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/
Re: make a widget paint itself even thought it is not shown
Quote:
Originally Posted by
wysota
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
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
[/code]
Exactly :). Thanks for the interesting links.
Thanks a lot
Re: make a widget paint itself even thought it is not shown
Quote:
Originally Posted by
momesana
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.
Re: make a widget paint itself even thought it is not shown
Quote:
Originally Posted by
wysota
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.
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:
Code:
widget->show();
qApp->processEvents();
widget->hide();
qApp->processEvents();