[Solved] How to take a Print in QML?



  • Hello ;
    I need to take a print in Qt Quick, So I Can't find any way to do this.
    Of course I checked this link : http://doc.qt.io/qt-5/qtprintsupport-index.html , but this work on widgets only not QML.

    So if anyone need to take print a page in QML how can do this ?
    for example I need take print from WebView content , TableView , Rectangle or other objects in QML.


  • Moderators

    Hi @IT-MAN-2015,
    QML doesnot have any such mechanism of printing. You will need to make use of Qt's C++ API's for actual printing. First you can grab image of any Item using grabToImage the result will be delegated to a callback. Inside it you can get the grabbed image data which is actually a QImage. Later you can send it to C++ side using signal/slot or by calling a Q_INVOKABLE function. Then use QPrinter to print that image.



  • @p3c0 said:

    Hi @IT-MAN-2015,
    QML doesnot have any such mechanism of printing. You will need to make use of Qt's C++ API's for actual printing. First you can grab image of any Item using grabToImage the result will be delegated to a callback. Inside it you can get the grabbed image data which is actually a QImage. Later you can send it to C++ side using signal/slot or by calling a Q_INVOKABLE function. Then use QPrinter to print that image.

    Well , for example I wrote this codes for webView but I can't get webView source for send to C++ function to print it.

    C++ Invokable function
    .h file

    #ifndef PR_H
    #define PR_H
    
    #include <QObject>
    
    
    class pr : public QObject
    {
        Q_OBJECT
    
    public:
        pr();
    
    public:
    
    Q_INVOKABLE  void print(QString url);
    
    
    };
    
    #endif // PR_H
    

    .cpp :

    void pr::print(QString url)
    
    {
    
        QString fileName = QFileDialog::getOpenFileName(0,"Open File",QString(),"PNG File(*.png)");
        QPrinter printer;
              QPrintDialog *dlg = new QPrintDialog(&printer,0);
              if(dlg->exec() == QDialog::Accepted) {
                      QImage img(fileName);
                      QPainter painter(&printer);
                      painter.drawImage(QPoint(0,0),img);
                      painter.end();
              }
    
    
    }
    

    main file :

    //For QML
    pr  print;
    
        engine.rootContext()->setContextProperty("PRINT", &print);
    

    QMl file :

                WebView {
                    id: result_view
                    x: 154
                    y: 22
                    url:"https://forum.qt.io/logo.png"
    
                }
    
            Button {
                id: button1
                x: 437
                y: 137
                width: 150
                height: 36
                text: qsTr("Print")
                onClicked: {
                    PRINT.print(/*My WebView Content*/);
                }
            }
    

  • Moderators

    @IT-MAN-2015 As said earlier use grabToImage to grab a snapshot of the Item i.e in your case WebView. Then its result will give you QImage and then send it to C++. So instead of (QString url) as argument use QVariant and convert it to QImage. Following should work as per your code:

    WebView {
        id: webview
        anchors.fill: parent
        url: "https://forum.qt.io/logo.png"
    }
    
    Button {
        anchors.bottom: parent.bottom
        onClicked: {
            var stat = result_view.grabToImage(function(result) {
                //result.saveToFile("/home/user/someimage.png"); //saves to a file
                PRINT.print(result.image); //result.image holds the QVariant
            });
            console.log("Success: ", stat);
        }
    }
    


  • @p3c0 said:

    @IT-MAN-2015 As said earlier use grabToImage to grab a snapshot of the Item i.e in your case WebView. Then its result will give you QImage and then send it to C++. So instead of (QString url) as argument use QVariant and convert it to QImage. Following should work as per your code:

    WebView {
        id: webview
        anchors.fill: parent
        url: "https://forum.qt.io/logo.png"
    }
    
    Button {
        anchors.bottom: parent.bottom
        onClicked: {
            var stat = result_view.grabToImage(function(result) {
                //result.saveToFile("/home/user/someimage.png"); //saves to a file
                PRINT.print(result.image); //result.image holds the QVariant
            });
            console.log("Success: ", stat);
        }
    }
    

    Thank you p3c0 for your helping.
    But I can't convert QVariant to QImage
    I think my function is wrong! QPrintDialog not work when I write custom path.

    void pr::print(QVariant *url)
    
    {
        //QString fileName = QFileDialog::getOpenFileName(0,"Open File",QString(),"PNG File(*.png)");
        QPrinter printer;
              QPrintDialog *dlg = new QPrintDialog(&printer,0);
              if(dlg->exec() == QDialog::Accepted) {
                 
                      //Convert my QVariant to image file
                      url->toImage ?!!? how convert to image :(
                  
                      QImage img(fileName);
                      QPainter painter(&printer);
                      painter.drawImage(QPoint(0,0),img);
                      painter.end();
              }
    }
    

  • Moderators

    @IT-MAN-2015 Not need of QVariant pointer. It is implicily shared. Afterwards use qvariant_cast to cast it to QImage and then as usual of printing. So

    void pr::print(QVariant data) { //note: it sends a complete image and not just url
         QImage img = qvariant_cast<QImage>(data);
    }
    


  • @p3c0 said:

    @IT-MAN-2015 Not need of QVariant pointer. It is implicily shared. Afterwards use qvariant_cast to cast it to QImage and then as usual of printing. So

    void pr::print(QVariant data) { //note: it sends a complete image and not just url
         QImage img = qvariant_cast<QImage>(data);
    }
    

    Well... I understand about QVariant but now i get error !

    error: C2664: 'void pr::print(QVariant)' : cannot convert argument 1 from 'QVariant' to 'QVariant'
    Source or target has incomplete type

    .h file :

    #ifndef PR_H
    #define PR_H
    #include <QObject>
    class pr : public QObject
    {
        Q_OBJECT
    public:
        pr();
    public:
    Q_INVOKABLE void print(QVariant data);
    };
    #endif // PR_H
    

    and .cpp file :

    pr::pr()
    {
    }
    void pr::print(QVariant data)
    {
       QImage img = qvariant_cast<QImage>(data);
       QPrinter printer;
              QPrintDialog *dlg = new QPrintDialog(&printer,0);
              if(dlg->exec() == QDialog::Accepted) {
                      QPainter painter(&printer);
                      painter.drawImage(QPoint(0,0),img);
                      painter.end();
              }
    }
    


  • It's worth mentioning this is one of the few things the old Qt4.8-era QDeclarativeView could do better, due to being QPainter based instead of OpenGL; see http://stackoverflow.com/questions/20825233/how-to-print-a-qquickviews-contents-to-pdf . (Well in theory; in practice the PDFs seemed to have some flaws.)

    The possibility of using the new (commerical license) QtQuick software rendering tech for improving print capabilities gets a brief mention in the thread under https://blog.qt.io/blog/2015/01/22/introducing-the-qt-quick-2d-renderer/ too.


  • Moderators

    @IT-MAN-2015 do #include <QVariant>



  • @p3c0

    Thank you p30c0 :-) I understand and I can take a print in QML right now.
    Thank you for your helping my friend.


  • Moderators

    @IT-MAN-2015 You're Welcome :) Also please surround you code with ``` (3 backticks) while posting here so that it gets formatted nicely and is more readable.


  • Moderators

    @timday

    It's worth mentioning this is one of the few things the old Qt4.8-era QDeclarativeView could do better, due to being QPainter based instead of OpenGL; see http://stackoverflow.com/questions/20825233/how-to-print-a-qquickviews-contents-to-pdf . (Well in theory; in practice the PDFs seemed to have some flaws.)

    Yes indeed. Miss them for these features including WebView. I guess in future we may have a direct print function in QtQuick 2.x too.



  • @p3c0 said:

    @IT-MAN-2015 You're Welcome :) Also please surround you code with ``` (3 backticks) while posting here so that it gets formatted nicely and is more readable.

    Here you are :

    .h file

    #ifndef PR_H
    #define PR_H
    
    #include <QObject>
    #include <QVariant>
    
    class pr : public QObject
    {
        Q_OBJECT
    
    public:
        pr();
    
    public:
    
    Q_INVOKABLE void print(QVariant data);
    
    
    };
    
    #endif // PR_H
    

    .cpp file :

    #include "pr.h"
    #include <QPrinter>
    #include <QPainter>
    #include <QPrintDialog>
    #include <QPixmap>
    #include <QImage>
    #include <qDebug>
    
    pr::pr()
    {
    
    }
    
    void pr::print(QVariant data)
    
    {
    
    
        QImage img = qvariant_cast<QImage>(data);
        QPrinter printer;
              QPrintDialog *dlg = new QPrintDialog(&printer,0);
              if(dlg->exec() == QDialog::Accepted) {
                      QPainter painter(&printer);
                      painter.drawImage(QPoint(0,0),img);
                      painter.end();
              }
    
    
    }
    
    

    QML file :

                WebView {
                    id: result_view
                    x: 154
                    y: 22
                    url:"http://forum.qt.io/logo.png"
                    enabled: false
                    antialiasing: true
    
                }
    
    
            Button {
                id: button1
                x: 437
                y: 137
                width: 150
                height: 36
                text: qsTr("Print")
                onClicked: {
                        var stat = result_view.grabToImage(function(result) {
                            //result.saveToFile("/home/user/someimage.png"); //saves to a file
                            PRINT.print(result.image); //result.image holds the QVariant
                        });
                        console.log("Success: ", stat);
                    }
            }
    
    

    main.cpp

    #include <QApplication>
    #include <QQmlApplicationEngine>
    #include <QtWebEngine/QtWebEngine>
    #include <pr.h>
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        QtWebEngine::initialize();
    
        //For QML
        pr  print;
        engine.rootContext()->setContextProperty("PRINT", &print);
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        return app.exec();
    }
    

  • Moderators

    @IT-MAN-2015 Thanks for sharing :)



  • @p3c0 said:

    @IT-MAN-2015 Thanks for sharing :)

    You're welcome :)
    Have a nice time.


Log in to reply
 

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