简体   繁体   中英

Pass formatted text from QML to C++

I have a simple pdf generator in my QML app, which uses C++ to receive a signal and write my PDF document to the device - when using a sample TestHtml.html document in the resources prints as intended, but I'm struggling to be able to send over custom HTML formatted text directly from the QML page.

What I want to do

My reportPage.qml displays varying data/information, when I click the 'download' button, it sends this formatted data to the C++ to print to PDF, (C++ is not my strong point).

What I have tried

  • Using QIODevice to write to the.html file, effectively deleting/re-writing the data as needed
  • Using QString to pass my text from reportPage.qml as a string
  • Using QVariant to store my html as an array and pass as this from reportPage.qml

My only issue is, where c++ is not my strong point, all I get is errors in my pdf.cpp such as undeclared identifiers, no matching member function and so on so fourth

My Question is

What is the best way to pass formatted html text using signals/slots form QML to C++ to print as a pdf using my pdf printer shown in the code below?

At Current a simplified part of my code is:

reportPage.qml

import Felgo 3.0
import com.allbookd.pdf 1.0
import QtQuick.Controls 1.2

Page {
    id: reportPage

    MyPdf {
        id: pdf
    }
    AppButton {
        text: "download"
        var htmlData = "<b>Hello</b> World 
                        <ul>
                            <li>Coffee</li>
                            <li>Tea</li>
                            <li>Milk</li>
                        </ul>"
        onClicked: { pdf.saveInvoice(htmlData); }
    }
}

pdf.h

#ifndef PDF_H
#define PDF_H

#include <QObject>
#include <QDebug>
#include <QPainter>
#include <QTextDocument>
#include <QPdfWriter>
#include <QDate>
#include <QStandardPaths>
#include <QPrinter>
#include <QFile>

class pdf : public QObject
{
    Q_OBJECT
public:
    explicit pdf(QObject *parent = nullptr);

    void setCurrentDate();
    QString getCurrentDate() const;

signals:

    void invoiceSaved(int error);

public slots:
    QString getPdfPath() const;
    void saveInvoice();

private:
    QString currentDate;
    QString pdfPath;
};

#endif // PDF_H

pdf.cpp


pdf::pdf(QObject *parent) : QObject(parent)
{
    setCurrentDate();
    QString path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    pdfPath = path + "/invoice_" + getCurrentDate() + ".pdf";
}

void pdf::setCurrentDate()
{
    QDate date(QDate::currentDate());
    int day = date.day();
    int month = date.month();
    int year =  date.year();

    currentDate = QString::number(day) + "_" + QString::number(month) + "_" + QString::number(year);
}

QString pdf::getCurrentDate() const
{
    return currentDate;
}

QString pdf::getPdfPath() const
{
    return pdfPath;
}


void pdf::saveInvoice(QString htmlData)
{
    int error = 0;
    QPdfWriter pdfWriter(getPdfPath());

    pdfWriter.setPageSize(QPageSize(QPageSize::A4));

    QPainter painter(&pdfWriter);

    painter.scale(15.0, 15.0);

    QFile file(":/htmlcode.html");    //the HTML file from resources

    if(file.open(QIODevice::ReadWrite)) {
        QByteArray temp = file.readAll();   //read it all

        QString html = temp;                //convert it to QString
        QTextDocument doc;
        doc.setHtml(html);                  //set it as HTML

        doc.drawContents(&painter);         

    } else {
        qDebug() << "error: " << file.error();
        error = 1;
    }
    emit invoiceSaved(error);

}

You can expose your pdf class to QML. Make functions Q_INVOKABLE to be able to call them directly from QML or even better use Q_PROPERTY

Docs for Q_INVOKABLE Docs for Q_PROPERTY

Here is an example:

Register/expose your pdf class to qml in main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "pdf.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    qmlRegisterType<pdf>("com.allbookd.pdf", 1, 0, "PdfPrinter");
    QQmlApplicationEngine engine;    
    ............

    return app.exec();
}

Make saveInvoice function invokable in pdf.h :

#include <QObject>

class pdf : public QObject
{
    Q_OBJECT
public:
    explicit pdf(QObject *parent = nullptr);

    void setCurrentDate();
    QString getCurrentDate() const;

    Q_INVOKABLE void saveInvoice(QString htmlData);

    ..............

And save htmlData to pdf using QPdfWriter:

void pdf::saveInvoice(QString htmlData)
{
    int error = 0;
    QPdfWriter pdfWriter(getPdfPath());

    pdfWriter.setPageSize(QPageSize(QPageSize::A4));

    QPainter painter(&pdfWriter);
    painter.scale(15.0, 15.0);

    QTextDocument doc;
    doc.setHtml(htmlData);
    doc.drawContents(&painter);

    emit invoiceSaved(error);
}

Your QML could then look like that:

import Felgo 3.0
import com.allbookd.pdf 1.0
import QtQuick.Controls 1.2

Page {
    id: reportPage
    property PdfPrinter pdf: PdfPrinter{}

    AppButton {
        text: "download"
        var htmlData = "<b>Hello</b> World 
                        <ul>
                            <li>Coffee</li>
                            <li>Tea</li>
                            <li>Milk</li>
                        </ul>"
        onClicked: { pdf.saveInvoice(htmlData); }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM