Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 2

Qt-interest Archive, June 2007
Printing child widgets


Message 1 in thread

I have been implementing printing lately. I have no problem printing my main
widget, but I cannot get the child widgets on top of the main widget to
print. In fact, the child widgets display on the screen instead of going to
the printer during the print cycle.

I tried using QPainter::setRedirected(subWidget, qprinter); and
QPixmap::grabWidget(subWidget). Neither one worked.

The widgets are not in a QLayout (and cannot be due to ported code), they
are simply child widgets at specified locations. They work fine on screen.
The layout process creates new, temporary widgets just for the printer. The
main widget is already directed to the printer before the child widgets are
created.

I've looked for examples, but everything seems to assume only one widget is
intended to go to the printer. How do I print multiple widgets on a page? In
particular, I may have QTextEdit widgets, scrolled to a specific location,
that need to render as they appear on the screen (but with better font
resolution).

Keith
**Please do not reply to me, reply to the list.**


Message 2 in thread

Keith Esau wrote:

> I have been implementing printing lately. I have no problem printing my
> main widget, but I cannot get the child widgets on top of the main widget
> to print. In fact, the child widgets display on the screen instead of
> going to the printer during the print cycle.

[...]

> I've looked for examples, but everything seems to assume only one widget
> is intended to go to the printer. How do I print multiple widgets on a
> page?

If you are dealing with nested widgets, you may well need to traverse the
object tree and ask each widget to paint its contents while you redirect its
output to the printer.

For widgets that can paint their contents without redirection (see Printing
with Qt in the documentation), this task is made easier, but the others may
also require you to make sure they receive all the events they need to
perform this task, perhaps by calling qApp::sendPostedEvents().

Then you can redirect the widget's paint events to the printer, construct a
QPaintEvent, and send it to the widget using qApp::sendEvent(). You need to
restore the redirection afterwards.

It's been a while since I've done this, so maybe there's an easier way to
do it.

> In particular, I may have QTextEdit widgets, scrolled to a specific 
> location, that need to render as they appear on the screen (but with
> better font resolution).

Getting QTextEdit widgets to display text like that could well be difficult.
You can redirect paint events to a QPicture, or perhaps even a
QSvgGenerator, and render that to the printer.

Remember that you may need to set autoFillBackground to true for some
widgets if you want them to be rendered as you expect, and be prepared to
do a certain amount of fine-tuning.

Good luck!

David
-- 
 [ signature omitted ] 

Message 3 in thread

On 06-06-2007 1:41 PM, "David Boddie" wrote:

> Keith Esau wrote:
> 
>> I have been implementing printing lately. I have no problem printing my
>> main widget, but I cannot get the child widgets on top of the main widget
>> to print. In fact, the child widgets display on the screen instead of
>> going to the printer during the print cycle.
> 
> [...]
> 
>> I've looked for examples, but everything seems to assume only one widget
>> is intended to go to the printer. How do I print multiple widgets on a
>> page?
> 
> If you are dealing with nested widgets, you may well need to traverse the
> object tree and ask each widget to paint its contents while you redirect its
> output to the printer.
> 
> For widgets that can paint their contents without redirection (see Printing
> with Qt in the documentation), this task is made easier, but the others may
> also require you to make sure they receive all the events they need to
> perform this task, perhaps by calling qApp::sendPostedEvents().
> 
> Then you can redirect the widget's paint events to the printer, construct a
> QPaintEvent, and send it to the widget using qApp::sendEvent(). You need to
> restore the redirection afterwards.

I tried this:

    QPainter::setRedirected(pWidget, paintDevice);
    QPaintEvent evt(pWidget->rect());
    qApp->sendPostedEvents(pWidget, 0);
    qApp->sendEvent(pWidget, &evt);
    qApp->sendPostedEvents(pWidget, 0);
    QPainter::restoreRedirected(pWidget);

But the paintEvent() for pWidget never gets called. I suspect the same
problem happens when I tried using QPixmap ::grabWidget(). The QPixmap was
the right size, but it was transparent. (I saved it to disk to see if it got
created properly.)

So, how do I get this to correctly call the widget's paint event?

Keith
**Please do not reply to me, reply to the list.**


--
 [ signature omitted ] 

Message 4 in thread

On 06-06-2007 4:28 PM, "Keith Esau" wrote:

> I tried this:
> 
>     QPainter::setRedirected(pWidget, paintDevice);
>     QPaintEvent evt(pWidget->rect());
>     qApp->sendPostedEvents(pWidget, 0);
>     qApp->sendEvent(pWidget, &evt);
>     qApp->sendPostedEvents(pWidget, 0);
>     QPainter::restoreRedirected(pWidget);
> 
> But the paintEvent() for pWidget never gets called. I suspect the same
> problem happens when I tried using QPixmap ::grabWidget(). The QPixmap was
> the right size, but it was transparent. (I saved it to disk to see if it got
> created properly.)
> 
> So, how do I get this to correctly call the widget's paint event?

I verified that QPixmap::grabWidget(pWidget) does NOT call the paintEvent
for the widget. How in the world does it grab and image of the widget then?!

Keith
**Please do not reply to me, reply to the list.**


--
 [ signature omitted ] 

Message 5 in thread

Thanks for reading the continuing saga....

I found out why the paintEvent never gets called. pWidget->isVisible()
returns false in QCoreApplication::sendEvent(). I added a call to show()
before calling sendEvent but that didn't help. The widget is definitely
within both the pixmap area and the main (parent) widget's area, so I can't
figure out why isVisible() returns false.

This is beginning to look like a Qt bug. Has anyone else gotten multiple
widgets to image into a QPixmap or print on a page?

Keith
**Please do not reply to me, reply to the list.**


On 06-06-2007 5:50 PM, "Keith Esau" wrote:

> On 06-06-2007 4:28 PM, "Keith Esau" wrote:
> 
>> I tried this:
>> 
>>     QPainter::setRedirected(pWidget, paintDevice);
>>     QPaintEvent evt(pWidget->rect());
>>     qApp->sendPostedEvents(pWidget, 0);
>>     qApp->sendEvent(pWidget, &evt);
>>     qApp->sendPostedEvents(pWidget, 0);
>>     QPainter::restoreRedirected(pWidget);
>> 
>> But the paintEvent() for pWidget never gets called. I suspect the same
>> problem happens when I tried using QPixmap ::grabWidget(). The QPixmap was
>> the right size, but it was transparent. (I saved it to disk to see if it got
>> created properly.)
>> 
>> So, how do I get this to correctly call the widget's paint event?
> 
> I verified that QPixmap::grabWidget(pWidget) does NOT call the paintEvent
> for the widget. How in the world does it grab and image of the widget then?!
> 
> Keith
> **Please do not reply to me, reply to the list.**


--
 [ signature omitted ] 

Message 6 in thread

I have definitely gotten it to work onto an image, but I did it in a
complete different way..

I created the image, created a painter with the device being the image,
and just painted as normal.

Scott

> -----Original Message-----
> From: Keith Esau [mailto:keith.esau@xxxxxxx]
> Sent: Wednesday, June 06, 2007 8:21 PM
> To: Qt Interest
> Subject: Re: Printing child widgets
> 
> Thanks for reading the continuing saga....
> 
> I found out why the paintEvent never gets called. pWidget->isVisible()
> returns false in QCoreApplication::sendEvent(). I added a call to
show()
> before calling sendEvent but that didn't help. The widget is
definitely
> within both the pixmap area and the main (parent) widget's area, so I
> can't
> figure out why isVisible() returns false.
> 
> This is beginning to look like a Qt bug. Has anyone else gotten
multiple
> widgets to image into a QPixmap or print on a page?
> 
> Keith
> **Please do not reply to me, reply to the list.**
> 
> 
> On 06-06-2007 5:50 PM, "Keith Esau" wrote:
> 
> > On 06-06-2007 4:28 PM, "Keith Esau" wrote:
> >
> >> I tried this:
> >>
> >>     QPainter::setRedirected(pWidget, paintDevice);
> >>     QPaintEvent evt(pWidget->rect());
> >>     qApp->sendPostedEvents(pWidget, 0);
> >>     qApp->sendEvent(pWidget, &evt);
> >>     qApp->sendPostedEvents(pWidget, 0);
> >>     QPainter::restoreRedirected(pWidget);
> >>
> >> But the paintEvent() for pWidget never gets called. I suspect the
same
> >> problem happens when I tried using QPixmap ::grabWidget(). The
QPixmap
> was
> >> the right size, but it was transparent. (I saved it to disk to see
if
> it got
> >> created properly.)
> >>
> >> So, how do I get this to correctly call the widget's paint event?
> >
> > I verified that QPixmap::grabWidget(pWidget) does NOT call the
> paintEvent
> > for the widget. How in the world does it grab and image of the
widget
> then?!
> >
> > Keith
> > **Please do not reply to me, reply to the list.**
> 
> 
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with
> "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/

--
 [ signature omitted ] 

Message 7 in thread

> I tried this:
> 
>     QPainter::setRedirected(pWidget, paintDevice);
>     QPaintEvent evt(pWidget->rect());
>     qApp->sendPostedEvents(pWidget, 0);
>     qApp->sendEvent(pWidget, &evt);
>     qApp->sendPostedEvents(pWidget, 0);
>     QPainter::restoreRedirected(pWidget);

What you instead should do (with Qt 4.3) is:

pWidget->render(paintDevice);

Then you'll render pWidget into paintDevice.

Redirection is used internally in our backing store, so it won't work as 
expected with QWidgets. That's exactly the reason why we added 
QWidget::render in 4.3 :-)

-- 
 [ signature omitted ] 

Message 8 in thread

On 06-07-2007 5:09 AM, "Bjoern Erik Nilsen" wrote:

>> I tried this:
>> 
>>     QPainter::setRedirected(pWidget, paintDevice);
>>     QPaintEvent evt(pWidget->rect());
>>     qApp->sendPostedEvents(pWidget, 0);
>>     qApp->sendEvent(pWidget, &evt);
>>     qApp->sendPostedEvents(pWidget, 0);
>>     QPainter::restoreRedirected(pWidget);
> 
> What you instead should do (with Qt 4.3) is:
> 
> pWidget->render(paintDevice);
> 
> Then you'll render pWidget into paintDevice.
> 
> Redirection is used internally in our backing store, so it won't work as
> expected with QWidgets. That's exactly the reason why we added
> QWidget::render in 4.3 :-)

Well, this sounded well and good, but it doesn't work either because I am
currently painting in a QPainter (onto the print page in the case of the
printer). I can't end the QPainter until I am done printing all pages! The
child widgets are created when each page is laid out for the main widget and
destroyed when I go to the next page.

How do I get the child widgets to render using the current QPainter?

Keith
**Please do not reply to me, reply to the list.**


--
 [ signature omitted ] 

Message 9 in thread

Keith Esau wrote:

> On 06-07-2007 5:09 AM, "Bjoern Erik Nilsen" wrote:

>> Redirection is used internally in our backing store, so it won't work as
>> expected with QWidgets. That's exactly the reason why we added
>> QWidget::render in 4.3 :-)
> 
> Well, this sounded well and good, but it doesn't work either because I am
> currently painting in a QPainter (onto the print page in the case of the
> printer). I can't end the QPainter until I am done printing all pages! The
> child widgets are created when each page is laid out for the main widget
> and destroyed when I go to the next page.
> 
> How do I get the child widgets to render using the current QPainter?

Maybe render each widget to an image then use the painter's drawImage()
function to paint it onto the page.

-- 
 [ signature omitted ] 

Message 10 in thread

I am trying that, but the image rendered is always blank, even if I create
them before creating my QPainter.

Keith
**Please do not reply to me, reply to the list.**


On 06-12-2007 2:28 PM, "David Boddie" wrote:

> Keith Esau wrote:
> 
>> On 06-07-2007 5:09 AM, "Bjoern Erik Nilsen" wrote:
> 
>>> Redirection is used internally in our backing store, so it won't work as
>>> expected with QWidgets. That's exactly the reason why we added
>>> QWidget::render in 4.3 :-)
>> 
>> Well, this sounded well and good, but it doesn't work either because I am
>> currently painting in a QPainter (onto the print page in the case of the
>> printer). I can't end the QPainter until I am done printing all pages! The
>> child widgets are created when each page is laid out for the main widget
>> and destroyed when I go to the next page.
>> 
>> How do I get the child widgets to render using the current QPainter?
> 
> Maybe render each widget to an image then use the painter's drawImage()
> function to paint it onto the page.


--
 [ signature omitted ] 

Message 11 in thread

Keith Esau wrote:
> On 06-12-2007 2:28 PM, "David Boddie" wrote:
>> Keith Esau wrote:
>> 
>>> How do I get the child widgets to render using the current QPainter?
>> 
>> Maybe render each widget to an image then use the painter's drawImage()
>> function to paint it onto the page.
> 
> I am trying that, but the image rendered is always blank, even if I create
> them before creating my QPainter.

A quick test of this feature worked for me. I wrote a quick test program
to create a simple user interface, passed a pointer to the top-level widget
to a helper class, then connected a zero-time, single-shot timer to this
slot in the helper:

    void Helper::print()
    {
        QPrinter printer;
        QPrintDialog dialog(&printer);
        if (dialog.exec() != QPrintDialog::Accepted)
            return;
        QPainter painter;
        painter.begin(&printer);
        QPixmap pixmap(widget->size());
        widget->render(&pixmap);
        painter.drawPixmap(0, 0, pixmap);
        painter.end();
    }

Can you post some code that shows what you are doing?

-- 
 [ signature omitted ]