我正在尝试在Windows下使用Qt5生成pdf。我的文档包含文本,图像和图表。正如我对Qt和Qwt所熟悉的那样,我相信最好的策略是使用我的文档布局创建QWidget并简单地打印它。但是我遇到了问题,最终无法取得令人满意的结果。

这是我的MCVE,一个简单的页面文档,其中包含:

  • 标题和图像的头
  • 一段文字
  • 一个简单的图表

  • 基于Qt documentHow can I print a QWidget in Qt?,我得到了以下代码:

    main.cpp:
    #include <QApplication>
    #include <QIcon>
    #include <QDesktopServices>
    #include <QWidget>
    #include <QPrinter>
    #include <QPainter>
    #include <QPagedPaintDevice>
    #include <QUrl>
    #include "ui_report.h"
    
    #include "qwt_plot.h"
    #include "qwt_plot_curve.h"
    #include "qwt_plot_canvas.h"
    #include "qwt_point_data.h"
    #include "qwt_legend.h"
    
    #include <sstream>
    #include <memory>
    
    bool printWidget( QWidget& widget, bool highResolution, const std::string& fileName )
    {
        QPrinter printer( highResolution ? QPrinter::HighResolution : QPrinter::ScreenResolution );
    
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOrientation(QPrinter::Portrait);
        printer.setPaperSize(QPrinter::A4);
        printer.setPageMargins(15,15,15,15,QPrinter::Millimeter);
        printer.setFullPage(true);
        printer.setOutputFileName(fromSDEString(fileName.c_str()));
    
        QPainter painter(&printer);
    
        double xscale = printer.pageRect().width()/double(widget.width());
        double yscale = printer.pageRect().height()/double(widget.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(-widget.width()/2, -widget.height()/2);
    
        widget.render(&painter, QPoint(), QRegion(), QWidget::DrawChildren);
    
        return painter.end();
    }
    
    bool generateReport( bool drawWithPrinterResolution, bool printHighResolution, const std::string& fileName )
    {
        QWidget widget;
        Ui::Report ui;
        ui.setupUi( &widget );
    
        if ( drawWithPrinterResolution )
        {
            QPrinter printer( printHighResolution ? QPrinter::HighResolution : QPrinter::ScreenResolution );
    
            printer.setOrientation(QPrinter::Portrait);
            printer.setPaperSize(QPrinter::A4);
            printer.setPageMargins(15,15,15,15,QPrinter::Millimeter);
            printer.setFullPage(true);
    
            // force printer page size to be used:
            QSize pageSize = printer.pageRect().size();
            widget.resize( pageSize );
        }
    
        ui.header->setFrameShape( QFrame::Shape::Box );
    
        QHBoxLayout* headerLayout = new QHBoxLayout(ui.header);
    
        QLabel* icon = new QLabel(ui.header);
        QSize size = ui.header->size();
        icon->setPixmap( QPixmap( ":/gui_test/mainframe.png" ).scaledToHeight( size.height() ) );
    
        headerLayout->addWidget( icon );
        headerLayout->addWidget( new QLabel("Document title",ui.header) );
    
        headerLayout->setStretch( 0, 0 );
        headerLayout->setStretch( 1, 1 );
    
        ui.inputs->setText( "<b>Info</b>: Information" );
    
        QwtPlot* plot = new QwtPlot( &widget );
    
        QwtPlotCurve* curve = new QwtPlotCurve("Plots");
        curve->setStyle( QwtPlotCurve::Lines );
    
        QVector<QPointF> samples;
        for ( size_t i = 0; i != 100; ++i )
        {
            samples.push_back(QPointF(i,20*i+10));
        }
        curve->setData(new QwtPointSeriesData(samples));
    
        curve->attach(plot);
        plot->setTitle( "Result" );
        plot->setAxisScale( QwtPlot::xBottom, samples.front().rx(), samples.back().rx() );
    
        plot->replot();
    
        ui.graphLayout->addWidget( plot );
    
        if ( printWidget( widget, printHighResolution, fileName ) )
        {
            QDesktopServices::openUrl(QUrl::fromLocalFile(fileName.c_str()));
            return true;
        }
        else
        {
            return false;
        }
    }
    
    int main( int argc, char* argv[] )
    {
        QApplication app( argc, argv );
        app.setWindowIcon( QIcon( ":/gui_test/mainframe.png" ) );
    
        generateReport( false, false, "report_small_widget_to_screen.pdf" );
        generateReport( false, true, "report_small_widget_to_high.pdf" );
        generateReport( true, false, "report_big_widget_to_screen.pdf" );
        generateReport( true, true, "report_big_widget_to_high.pdf" );
    
        return 0;
    }
    

    report.ui:
    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>Report</class>
     <widget class="QWidget" name="Report">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>525</width>
        <height>742</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>Form</string>
      </property>
      <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,100,0">
       <item>
        <widget class="QFrame" name="header"/>
       </item>
       <item>
        <widget class="QLabel" name="inputs">
         <property name="text">
          <string>TextLabel</string>
         </property>
        </widget>
       </item>
       <item>
        <spacer name="verticalSpacer">
         <property name="orientation">
          <enum>Qt::Vertical</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>20</width>
           <height>40</height>
          </size>
         </property>
        </spacer>
       </item>
       <item>
        <layout class="QVBoxLayout" name="graphLayout"/>
       </item>
       <item>
        <widget class="QWidget" name="footer" native="true"/>
       </item>
      </layout>
     </widget>
     <resources/>
     <connections/>
    </ui>
    

    mainframe.png: 256x256像素的Qt图标:http://icons.iconarchive.com/icons/alecive/flatwoken/256/Apps-Qt-icon.png

    如您所见,这将生成4个文件:
  • report_small_widget_to_screen.pdf:从ui文件(252x742)以小A4比例创建小部件,然后使用QPrinter::ScreenResolution
  • 打印
  • report_small_widget_to_high.pdf:从ui文件(252x742)以小A4比例创建小部件,然后使用QPrinter::HighResolution
  • 打印
  • report_big_widget_to_screen.pdf:将小部件缩放到打印机的页面大小(793x1123),然后使用QPrinter::ScreenResolution
  • 打印
  • report_big_widget_to_high.pdf:将小部件缩放到打印机的页面大小(9917x14033),然后使用QPrinter::HighResolution
  • 打印

    没有一个给我可以接受的结果:
  • report_small_widget_to_screen.pdf:文本,Qt图标和Qwt图表是像素化的
  • report_small_widget_to_high.pdf:文本还可以,但Qt图标和Qwt图表是像素化的
  • report_big_widget_to_screen.pdf:文本,Qt图标和Qwt图表是像素化的
  • report_big_widget_to_high.pdf:文本,Qt图标和Qwt图表太小,难以读取。但是现在Qwt图不再像素化了

  • 我应该怎样改变才能获得不错的输出?
  • 如report_small_widget_to_high.pdf中以高分辨率(未像素化)绘制的文本
  • 以高分辨率(未像素化)绘制图标
  • 高分辨率绘制图表(未像素化)


  • 看起来像(所有像素化):

    c&#43;&#43; - 使用Qt无法生成具有可接受输出质量的pdf-LMLPHP

    report_small_widget_to_high.pdf看起来像(仅文本未像素化):

    c&#43;&#43; - 使用Qt无法生成具有可接受输出质量的pdf-LMLPHP

    report_big_widget_to_high.pdf看起来像(一切都太小了):

    c&#43;&#43; - 使用Qt无法生成具有可接受输出质量的pdf-LMLPHP

    注意:我只是使用更大的.ui资源(2100x2970)运行了相同的测试,因此图像分辨率看起来更好,但是文本看起来很小。我想知道QWidget打印是这里合适的解决方案,因为它看起来像文本大小取决于ui大小,因此您无法控制文本的大小(就像在Word这样的文档中使用字体大小一样... )

    最佳答案

    我个人会强烈考虑将内容创建为QTextDocument,然后进行打印。您可以(IIRC,已经有一段时间没有使用QwtPlot了)将图表渲染为图像。这样就很容易将add the image链接到文档中的任何位置。当然,与您的静态图片相同。您可以在文档中使用HTML / CSS(尽管在类名中使用“文本”),但也可以使用许多其他选项。

    根据要求添加了示例:

    这将是非常简化的并且尚未完全形成,但是希望它能对您有所帮助。

    QTextDocument qtdoc;  // start with a QTextDocument
    
    // prepare standard html with embedded image
    QString html = "<html><body>" \
        "<h1>Hello World!</h1>" \
        "<img src='mydata://myimg.png' border='0' />" \
    "</body></html>";
    
    QImage image = getChartImage();  // theoretical function
    
    // here we add the actual image data to the document
    qtdoc.addResource(QTextDocument::ImageResource, QUrl("mydata://myimg.png"), image);
    
    qtdoc.setHtml(html);
    // document is now fully formed and ready for display/print
    

    要打印为PDF或HTML文件:
    void printToFile(const QTextDocument & qtdoc)
    {
      QString fn = QFileDialog::getSaveFileName(this, tr("Select output file"), QString(), tr("PDF Files(*.pdf);;HTML-Files (*.htm *.html)"));
      if (fn.isEmpty())
        return;
      if (fn.endsWith(".pdf", Qt::CaseInsensitive)) {
        QPrinter printer;
        printer.setPageMargins(10.0,10.0,10.0,10.0,printer.Millimeter);
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setColorMode(QPrinter::Color);
        printer.setOutputFileName(fn);
        qtdoc.print(&printer);
      }
      else {  // HTML
        QTextDocumentWriter writer(fn);
        writer.write(qtdoc);
      }
    }
    

    输出到打印机:
    void print(const QTextDocument & qtdoc)
    {
      QPrinter printer;
      printer.setPageMargins(10.0,10.0,10.0,10.0,printer.Millimeter);
      QPrintDialog *dialog = new QPrintDialog(&printer, this);
      dialog->setWindowTitle(tr("Print Document"));
      if (dialog->exec() != QDialog::Accepted)
        return;
      qtdoc.print(&printer);
    }
    

    工作版本的实际屏幕截图(其代码以here开头,但有点麻烦):

    c&#43;&#43; - 使用Qt无法生成具有可接受输出质量的pdf-LMLPHP

    和PDF导出:http://max.wdg.us/docs/so/SO-47879329.pdf

    07-28 01:26
    查看更多