PDA

View Full Version : Help with QWidget::grab



mikea
17th September 2014, 16:20
In the following code the commented QPixmap::grab works, but is depreciated. I am trying to get QWidget::grab to work. I am wanting to grab the entire dialog so I am supplying no rect argument, wanting to use the default. I get the following error:

**C:\My Libraries\Programming\CppProj\ptest\printtest\main .cpp:16: error: cannot call member function 'QPixmap QWidget::grab(const QRect&)' without object
QPixmap pm = ArticleDialog::grab();
^
but I thought grab was static? If I replace the class "ArticleDialog" with the instance myWidget, I get the error:

**C:\My Libraries\Programming\CppProj\ptest\printtest\main .cpp:15: error: 'myWidget' is not a class or namespace
QPixmap pm = myWidget::grab();
^

What am I doing wrong?


#include "articledialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ArticleDialog myWidget;
myWidget.show();
QPrinter printer;
QPrintDialog printDialog(&printer);
if (printDialog.exec() == QDialog::Accepted) {

QPainter p(&printer);
//QPixmap pm = QPixmap::grabWidget(&myWidget);
QPixmap pm = ArticleDialog::grab();
p.drawPixmap(0, 0, pm);
}

return a.exec();
}

_______________________________

d_stranz
17th September 2014, 19:35
QWidget::grab() is not a static method. (Think about it - if it were a static method, that means it doesn't need a QWidget instance in order to be called. If that were the case, then which QWidget's content would it grab?)


If I replace the class "ArticleDialog" with the instance myWidget: QPixmap pm = myWidget::grab();

That's not what this code is doing. It's saying, call the static method grab() of the class named "myWidget". So, this is basic C++. If you want to call a non-static member function, you need to call it through an instance of the object:


QPixmap pm = myWidget.grab();

But your code, even if you do get it to compile, will not work. Your dialog will not be shown until the Qt event loop starts running, and a.exec() is what does that. You can't grab the dialog's contents until the event loop is running because there's nothing there to grab.

mikea
17th September 2014, 21:45
Thanks d_stranz,
When I replaced the class name by an instance, I forgot to change the :: to . -how dumb! It did however run as written and printed correctly.

d_stranz
18th September 2014, 20:00
It did however run as written and printed correctly.

It did? The same code you posted above after fixing it? I didn't think it should have, but maybe Qt queued up all those events until the event loop was running, and then started executing them. That does make sense, actually - the myWidget.show() call occurs before the loop is running, so the event that it triggers must just sit there in the queue waiting until it can be processed. Learned something here.

anda_skoa
18th September 2014, 21:44
QWidget::grab() might just render the widget into a pixmap buffer instead of the usual backing store buffer, thus be independent of event processing.
Also the show() and respective show event will have likely have been processed by the dialog's nested event loop.

Cheers,
_

d_stranz
19th September 2014, 02:34
Also the show() and respective show event will have likely have been processed by the dialog's nested event loop.

Very good point. Forgot that QDialog runs its own event loop. So it must be independent of the QApplication event loop (which implies not nested, and sharing the same queue) and also not require that the QApplication event loop be running. This is more interesting than I thought - a lot of side-effects happening which just happen to cause the example to work.

wysota
19th September 2014, 09:58
I think a lot depends on the content of the widget being grabbed, as if it has a layout, then the layout is (by default) executed when the widget is first shown. So either grab() would have to force the layout to be processed or you'd need to do it yourself for all this to work without the event loop.

As for the event loop itself, both QCoreApplication::exec() and QDialog::exec() are merely interfaces to QAbstractEventDispatcher which is a kind-of singleton (or actually a per-thread-instance) that does event processing. So to be precise, a dialog does not have its own event loop but rather its own event loop entry point (triggering the same event loop).