PDA

View Full Version : Print preview of a QWidget



Ponnytail
2nd December 2013, 10:14
Hi,

My goal is to create a print preview function which allows users to see the crossword they've created as it would appear on a piece of paper. Reading the documentation I thought this would be a piece of cake. Here's what I've got so far (taken from the documentation describing how to print a widget):


void MyWindow::filePrintPreview()
{
QPrinter printer;
QPainter painter;
painter.begin(&printer);
double xscale = printer.pageRect().width()/double(cwArea->width());
double yscale = printer.pageRect().height()/double(cwArea->height());
double scale = qMin(xscale, yscale);
painter.translate(printer.paperRect().x() + printer.pageRect().width()/2,
printer.paperRect().y() + printer.pageRect().height()/2);
painter.scale(scale, scale);
painter.translate(-width()/2, -height()/2);
cwArea->render(&painter);
QPrintPreviewDialog preview(&printer, this);
connect(&preview, SIGNAL(paintRequested(QPrinter*)), SLOT(print(QPrinter*)));
preview.exec();
}

MyWindow is my QMainWindow and filePrintPreview() is the slot called when "file->print preview" is triggered.
cwArea is the widget containing the crossword squares.

I read that if I want to render the contents of a widget, these contents have to be children of the widget itself. Since each crossword square is an overridden QTextEdit I added an optional parent parameter to each of the constructors...


Tile::Tile(..., QWidget *parent)
{
(...)
}

...and let the crossword widget be each square's parent. For example:


for(int i = 0; i < rows; i++)
{
for(int j = 0; j < columns; j++)
{
cwlayout->addWidget(new Tile(...,this),i*4,j*4,4,4);
}
}

Unfortunately all I've managed to preview so far is absolutely nothing.
What have I done wrong? Is it a problem when the child widgets of the widget I wish to print are QTextEdits?

Thanks in advance!

Ponnytail
4th December 2013, 13:29
Something strange happened today. I connected myself to a wireless network with a printer and suddenly 3 documents I had forgotten to remove from my print queue got printed out. All 3 of them showed the template crossword I had created for testing purposes, scaled pretty badly though. So my question would rather be, why can I print my widget but not print preview it?

Edit:
I should have provided this earlier. Requesting a print preview actually causes errors which should explain the empty print preview window.


QPainter::begin(): Returned false
QPainter::translate: Painter not active
QPainter::scale: Painter not active
QPainter::translate: Painter not active
QWidget::render: Cannot render with an inactive painter

I can't tell why the begin function returns false. The documentation said I could use a QPainter constructor instead of calling begin() but this produces exactly the same errors. I have searched for clues but so far without success. Any help would be appreciated.

Thanks in advance!

ChrisW67
4th December 2013, 20:10
The code from line 4 to 13 belongs in the slot you connected to the paintRequested() signal from the preview widget. Line 3 need not exist. When the preview widget is exec() it will emit the paintRequested() signal telling you what printer device to paint on: you should paint on it. This printer device will be redirected by the preview widget to the screen. You can use the same slot to service a print immediately function by simply passing a real QPrinter.

Your existing code prints to the system default printer every time it is called and ignores the preview.

Ponnytail
4th December 2013, 21:34
Oh that explains why an empty preview window was shown and a print requested. I got my slots from an example of print preview. They are filePrintPreview(), filePrint() and print(QPrinter *printer). I simply thought the print slot had nothing to do with the preview and ignored its connect. Your answer is perfect. Moving the lines makes it possible to preview the widget. Thanks a lot for the help, Chris!

A last curiosity though. I read that a QPainter is almost always created inside a paintEvent() and I guess this is why I couldn't create one inside my filePrintPreview() slot. Why can I create a QPainter inside the print(...) slot? This is also outside paintEvent() right? I understand I request painting but shouldn't the widget's paintEvent() handle such requests?

ChrisW67
4th December 2013, 22:00
You can create and use a QPainter to paint on any QPaintDevice. All QWidgets are QPaintDevices so by far the majority of painting is done in QWidget::paintEvent() to render your UI. Other QPaintDevices include QPixmap, QImage, and QPrinter can be used outside the painting code for a widget.

Ponnytail
4th December 2013, 22:10
Ah, alright! Thanks for the clarification :)