PDA

View Full Version : [QT4] Printing a dialog



KShots
10th March 2006, 20:48
Looking at the docs, I see that it's relatively easy to print something like a QTextEdit or a QTextBrowser... but what if I want to print a dialog?

Thus far, I'm not seeing anything to accomplish that :(.

Any ideas?

jpn
10th March 2006, 20:57
Never done that and this is just a guess, but it could work ;)

Take a "screenshot" (aka. ask to paint itself on a pixmap) of the dialog:
QPixmap QPixmap::grabWidget ( QWidget * widget, const QRect & rectangle ) [static] (http://doc.trolltech.com/4.1/qpixmap.html#grabWidget)

then just paint the pixmap on the printer, simple huh..?

KShots
11th April 2006, 18:44
Well... trying that, I printed to a postscript file to test with. Ended up with a 1.3M image with just the cancel button of the dialog :confused:

Here's the relevant section of code that I'm currently using:
void formMainApp::menuFilePrint()
{
QPrinter p;
p.setColorMode(QPrinter::GrayScale); //No reason for color in this dialog
p.setCreator("TIRdb");
p.setDocName("TIRdb Printout");
QPrintDialog qp(&p, this);
if(qp.exec() == QDialog::Accepted)
{
QModelIndexList MIL = ui.treeViewSQLList->selectionModel()->selectedIndexes();
QPainter painter;
for(QList<QModelIndex>::iterator i = MIL.begin(); i != MIL.end(); ++i)
{
formTIR * T = TIRTree->findTIR(*i); //TIRTree is my model, findTIR returns the dialog
if(!T) //Some elements in the tree do not have dialogs attached to them
{
continue;
}
QRect rect = painter.viewport();
QPixmap qp = QPixmap::grabWidget(T, rect);
QSize size = qp.size();
size.scale(rect.size(), Qt::KeepAspectRatio);
painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
painter.setWindow(qp.rect());
painter.begin(&p);
painter.drawPixmap(0, 0, qp);
painter.end();
}
}
}

Also, a side note... I'm noticing a decided lack in documentation on just how the print process works (or maybe it's just me). I've looked at QPrinter and I've got to admit that I'm not at all clear on just how it works. Maybe I'm blind; is there a section in the docs that explains this in much greater detail?

KShots
12th April 2006, 17:25
Well... I found one bug in the above code. The QRect was an undefined size. I re-sized it to my screen resolution for now (1440x900). This was causing frequent crashes.

Also caught a childish mistake (surprised the compiler didn't catch it) - qp is both a QPrintDialog and a QPixmap. I have no idea how the compiler was working with that, but I changed the pixmap to qpm...

With that fixed, I'm still getting large pictures of my cancel button. Any idea what can be causing this?

Chicken Blood Machine
12th April 2006, 18:13
Scale your image to fit the printer with QPixmap::scaled(p.pageRect(), Qt::KeepAspectRatio);

Chicken Blood Machine
12th April 2006, 18:16
Also caught a childish mistake (surprised the compiler didn't catch it) - qp is both a QPrintDialog and a QPixmap. I have no idea how the compiler was working with that, but I changed the pixmap to qpm...

The compiler didn't catch it because it is valid code. You declared the variables in different scopes, so there was no real problem there (although it's good practice to use unique variable names).

KShots
12th April 2006, 19:15
I guess that kinda makes sense on the qp and qpm variables.

Scaling the image did just that - scaled the cancel button.

The problem I'm having is that none of the other widgets in the dialog are shown. All I see is the cancel button. I don't even see the frame around the cancel button.

Attached is a picture of what I'm getting, and a picture of what I should be getting.

Chicken Blood Machine
12th April 2006, 19:39
Your call to grabWidget() should be grabWidget(T, T->rect());

Also, drop the setViewport() and setWindow() stuff.

KShots
12th April 2006, 20:06
Your call to grabWidget() should be grabWidget(T, T->rect());Yeah, that makes a lot more sense
Also, drop the setViewport() and setWindow() stuff.Done.

Thus far, nothing is yet changing :(

To re-iterate, this is what I have now:
void formMainApp::menuFilePrint()
{
QPrinter p;
p.setColorMode(QPrinter::GrayScale);
//No reason for color in this dialog
p.setCreator("TIRdb");
p.setDocName("TIRdb Printout");
QPrintDialog qp(&p, this);
if(qp.exec() == QDialog::Accepted)
{
QModelIndexList MIL = ui.treeViewSQLList->selectionModel()->selectedIndexes();
QPainter painter;
for(QList<QModelIndex>::iterator i = MIL.begin(); i != MIL.end(); ++i)
{
formTIR * T = TIRTree->findTIR(*i); //TIRTree is my model, findTIR returns the dialog
if(!T) //Some elements in the tree do not have dialogs attached to them
{
continue;
}

QPixmap qpm = QPixmap::grabWidget(T, T->rect());
if(qpm.isNull())
{
qDebug() << "Failed to capture the dialog for printing";
return;
}

qpm.scaled(p.pageRect().width(), p.pageRect().height(), Qt::KeepAspectRatio);

painter.begin(&p);
painter.drawPixmap(0, 0, qpm);
painter.end();
}
}
}

Chicken Blood Machine
12th April 2006, 21:03
qpm = qpm.scaled(p.pageRect().width(), p.pageRect().height(), Qt::KeepAspectRatio);

KShots
13th April 2006, 18:50
Ah - I'm kinda embarassed I missed that.

Still had the same results, but I solved the problem (partially).

Turns out, you cannot grab a widget that is not being shown. Once I called T->show(), then grabbed the widget, then called T->close(), I got the whole thing.

For some relatively obvious reasons, I really don't want to have to show the widget(s) just to print them. Also, if I'm going to have a separate thread print the widgets, I really don't want to show them (or rather, I really can't show them). Any other ideas? This will at least make the thing functional, but it won't perform well at all.

Chicken Blood Machine
13th April 2006, 18:57
Ah - I'm kinda embarassed I missed that.

Still had the same results, but I solved the problem (partially).

Turns out, you cannot grab a widget that is not being shown. Once I called T->show(), then grabbed the widget, then called T->close(), I got the whole thing.

For some relatively obvious reasons, I really don't want to have to show the widget(s) just to print them. Also, if I'm going to have a separate thread print the widgets, I really don't want to show them (or rather, I really can't show them). Any other ideas? This will at least make the thing functional, but it won't perform well at all.

Hell, I didn't realize you hadn't shown the widget. Yes, that would explain it. A widget isn't fully laid out until it has been shown at least once.

KShots
13th April 2006, 19:03
Is there a way to lay it out without showing it?

KShots
28th April 2006, 13:46
Turns out it's another bug. Apparently it will be fixed in 4.1.4.

In that case, in my app I will work around it (for now) by quickly displaying the dialog, capturing it, and closing it (even if there are hundreds or thousands of them).

If you're curious, here's (http://www.trolltech.com/developer/tasktracker.html?method=entry&id=110121) the entry in the task tracker