QPrinter in QThread produce QPixmap error



  • Simple code example:
    @void MainWindow::on_btnPrint_clicked()
    {
    QThread *thread = new QThread(this);
    ThreadedPrint *print = new ThreadedPrint();
    print->moveToThread(thread);
    thread->start();
    QMetaObject::invokeMethod(print, "print", Qt::QueuedConnection);
    }

    ThreadedPrint::ThreadedPrint(QObject *parent) :
    QObject(parent)
    {
    m_printer = new QPrinter(QPrinter::PrinterResolution);
    m_printer->setPageSize(QPrinter::A4);
    }

    void ThreadedPrint::print()
    {
    QPainter painter(m_printer);
    QRect pageRect = m_printer->pageRect();
    QImage image(pageRect.width(), pageRect.height(), QImage::Format_RGB32);
    image.fill(Qt::black);
    painter.drawImage(0, 0, image);
    }
    @
    And i got:
    QPixmap: It is not safe to use pixmaps outside the GUI thread
    and I got empty page from my printer.
    But when I use printing into PDF all works fine, so bug only appears when I try to print on real printer.

    The documentation states:
    Painting in Threads
    QPainter can be used in a thread to paint onto QImage, QPrinter, and QPicture paint devices.

    So my question is: can i print in non-gui thread?



  • The QPrinter instance allocated on the heap in your ThreadedPrint constructor will be in the main thread (and stay there).

    So either:

    • Make the QPrinter instance a member variable
    • Put the heap allocation in a slot, called init() for example, and have that slot connected to the started() signal of the QThread wrapper object.

    Here is an example Qt 4 program that works without issue here:
    @
    #include <QtGui>
    #include <QDebug>

    class ThreadedPrint: public QObject {
    Q_OBJECT
    QPrinter *m_printer;
    public:
    ThreadedPrint(QObject *p = 0): QObject(p) {
    m_printer = 0;
    }
    ~ThreadedPrint() {
    delete m_printer;
    }

    signals:
    void finished();

    public slots:
    void init() {
    qDebug() << Q_FUNC_INFO;
    m_printer = new QPrinter;
    }
    void doPrint() {
    qDebug() << Q_FUNC_INFO;
    Q_ASSERT(m_printer);
    QPainter painter(m_printer);
    QRect pageRect = m_printer->pageRect();
    QImage image(pageRect.width(), pageRect.height(), QImage::Format_RGB32);
    image.fill(Qt::black);
    painter.drawImage(0, 0, image);

        // wait a while then finish the thread
        QTimer::singleShot(3000, this, SIGNAL(finished()));
    }
    

    };

    int main(int argc, char **argv)
    {
    QApplication app(argc, argv);

    QThread *thread= new QThread(qApp);
    ThreadedPrint *worker = new ThreadedPrint;
    worker->moveToThread(thread);
    QObject::connect(thread, SIGNAL(started()), worker, SLOT(init()));
    QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
    QObject::connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
    QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
    
    QTimer::singleShot(10000, qApp, SLOT(quit()));
    QTimer::singleShot(1000, worker, SLOT(doPrint()));
    return app.exec();
    

    }
    #include "main.moc"
    @



  • Thanks for explanation, but I still have the same error...

    Even when I create QPrinter object in doPrint slot.



  • The example code I posted works fine here. Does it fail for you?



  • Yes. I compile it without changes and get QPixmap error.
    Qt 4.8.4, Windows 7 x32.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.