8-4 打印(Printing)

翻译 2007年10月08日 22:12:00
 
在Qt中,打印与在QWidget,QPixmap或者QImage绘图很相似,一般步骤如下:
1、创建绘图设备的QPrinter;
2、弹出打印对话框,QPrintDialog,允许用户选择打印机,设置属性等;
3、创建一个QPrinter的QPainter;
4、用QPainter绘制一页;
5、调用QPrinter::newPage(),然后绘制下一页;
6、重复步骤4,5,直到打印完所有页。
在Windows和Mac OS X平台,QPrinter使用系统的打印驱动程序。在Unix上,QPrinter生成脚本并把脚本发送给lp或者lpr(或者发送给程序,打印程序有函数QPrinter::setPrintProgram())。调用QPrinter::setOutputFormat (QPrinter::PdfFormat)QPrinter也可以生成PDF文件。
Figure 8.12. Printing a QImage
 
  
首先看一个简单的例子,打印一个QImage到一页纸上。
void PrintWindow::printImage(const QImage &image)
{
    QPrintDialog printDialog(&printer, this);
    if (printDialog.exec()) {
        QPainter painter(&printer);
        QRect rect = painter.viewport();
        QSize size = image.size();
        size.scale(rect.size(), Qt::KeepAspectRatio);
        painter.setViewport(rect.x(), rect.y(),
                            size.width(), size.height());
        painter.setWindow(image.rect());
        painter.drawImage(0, 0, image);
    }
}
这里,我们假设了在PrintWindow类有一个QPrinter类型的成员变量printer。当然在printImage()函数的堆上我们也可以创建一个QPrinter,但是这样不能记录用户进行打印时的设置
 
创建QPrintDialog,调用exec()显示出来,如果用户点击了OK返回true,否则返回false。调用exec()后,QPrinter对象就可以使用了。(也可以不显示QPrintDialog,直接调用QPrinter的成员函数进行复制也可以)
然后,我们创建QPainter,绘图设备为QPrinter。设置窗口为所显示图形的矩形,视口也同样比例,然后在(0,0)绘制图像。
通常,QPainter的窗口自动进行了初始化,打印机和屏幕有着一致的分辨率(一英寸有72到100个点),使控件的打印代码能够重用。在上面的函数中,我们自己设置来QPainter的窗口。
在一页中进行打印很简单,但是,很多应用程序需要打印多页。这时我们一次打印一页,然后调用newPage()打印另一页。这里需要解决定一个问题是要确定一页打印多少内容。在Qt中有两种方法处理多页的打印文档:
1、我们可以把数据转换为HTML格式,使用QTextDocument描述他们,QTextDocument是Qt的多文本引擎。
2、手动进行分页
下面我们来分别看一下这两种方法。第一个例子,我们想打印一个花卉的指导:一列为花的名字,另一列为文本描述。每一条的文本格式存储为:“名称:描述”。例如:Miltonopsis santanae: A most dangerous orchid species.
由于每一种花卉的数据都可以用一个字符串表示,我们可以用QStringList表示所有花卉的数据。下面的代码为使用Qt的多文本引擎进行打印的例子:
void PrintWindow::printFlowerGuide(const QStringList &entries)
{
    QString html;
    foreach (QString entry, entries) {
        QStringList fields = entry.split(": ");
        QString title = Qt::escape(fields[0]);
        QString body = Qt::escape(fields[1]);
        html += "<table width=/"100%/" border=1 cellspacing=0>/n"
                "<tr><td bgcolor=/"lightgray/"><font size=/"+1/">"
                "<b><i>" + title + "</i></b></font>/n<tr><td>" + body
                + "/n</table>/n<br>/n";
    }
    printHtml(html);
}
首先把QStringList转换为HTML。每一种花卉为HTML表格中的一行,调用Qt::escapte()将特殊字符’&’,’>’,’<’等用相应的HTML字符表示(’amp’,’&gt’,’&lt’),然后调用printHtml()打印文本:
void PrintWindow::printHtml(const QString &html)
{
    QPrintDialog printDialog(&printer, this);
    if (printDialog.exec()) {
        QPainter painter(&printer);
        QTextDocument textDocument;
        textDocument.setHtml(html);
        textDocument.print(&printer);
    }
}
函数printHtml()弹出QPrintDialog对话框,负责打印一个HTML文档。这些代码可以在所有Qt的应用程序中打印任意HTML文档。

Figure 8.13. Printing a flower guide using QTextdocument

  

目前,把文本转换为HTML文档用QTextDocument打印是最方便的一个方法。如果需要更多的设置,就需要我们自己进行页面布局和绘制。下面的方法就是用人工干预的方式打印花卉指南。首先看一下printFlowerGuide()函数:
void PrintWindow::printFlowerGuide(const QStringList &entries)
{
    QPrintDialog printDialog(&printer, this);
    if (printDialog.exec()) {
 
        QPainter painter(&printer);
        QList<QStringList> pages;
        paginate(&painter, &pages, entries);
        printPages(&painter, pages);
    }
}
在创建QPainter,设置好打印机以后,调用函数paginate()确定那些项目在那一页。执行这个函数的结果是得到一个QStringList的列表,每一个QStringList在一页里显示,把这个结果传递给printPages()进行打印。
例如:需要打印的花卉指南有6个条目:A,B,C,D,E,F。其中A和B在第一页,C,D,E打印在第二页,F在第三页打印。
void PrintWindow::paginate(QPainter *painter, QList<QStringList> *pages,
                           const QStringList &entries)
{
    QStringList currentPage;
    int pageHeight = painter->window().height() - 2 * LargeGap;
    int y = 0;
    foreach (QString entry, entries) {
        int height = entryHeight(painter, entry);
        if (y + height > pageHeight && !currentPage.empty()) {
            pages->append(currentPage);
            currentPage.clear();
            y = 0;
        }
        currentPage.append(entry);
        y += height + MediumGap;
    }
    if (!currentPage.empty())
        pages->append(currentPage);
}
函数paginate()把花会指南条目分页。根据entryHeight()计算每一个条目的高度。同时考虑页面顶端和底端的垂直距离LargeGap。
遍历所有的条目,如果这个条目可以放在当前页,就把这个条目放到当前页的列表里面。当前页排满后,把当前页放到页的列表中,开始新的一页。
int PrintWindow::entryHeight(QPainter *painter, const QString &entry)
{
    QStringList fields = entry.split(": ");
    QString title = fields[0];
    QString body = fields[1];
 
    int textWidth = painter->window().width() - 2 * SmallGap;
    int maxHeight = painter->window().height();
    painter->setFont(titleFont);
    QRect titleRect = painter->boundingRect(0, 0, textWidth, maxHeight,
                                            Qt::TextWordWrap, title);
    painter->setFont(bodyFont);
    QRect bodyRect = painter->boundingRect(0, 0, textWidth, maxHeight,
                                           Qt::TextWordWrap, body);
    return titleRect.height() + bodyRect.height() + 4 * SmallGap;
}
函数entryHeight()根据QPainter::boundingRect()计算每一个条目的垂直距离,图8.4表明了条目的布局和SmallGap还MediumGap的含义:
 
The enTRyHeight() function uses QPainter::boundingRect() to compute the vertical space needed by one entry. Figure 8.14 shows the layout of a flower entry and the meaning of the SmallGap and MediumGap constants.
Figure 8.14. A flower entry's layout
 
 

void PrintWindow::printPages(QPainter *painter,

                             const QList<QStringList> &pages)
{
    int firstPage = printer.fromPage() - 1;
    if (firstPage >= pages.size())
        return;
    if (firstPage == -1)
        firstPage = 0;
    int lastPage = printer.toPage() - 1;
    if (lastPage == -1 || lastPage >= pages.size())
        lastPage = pages.size() - 1;
    int numPages = lastPage - firstPage + 1;
    for (int i = 0; i < printer.numCopies(); ++i) {
        for (int j = 0; j < numPages; ++j) {
            if (i != 0 || j != 0)
                printer.newPage();
            int index;
            if (printer.pageOrder() == QPrinter::FirstPageFirst) {
                index = firstPage + j;
            } else {
 
                index = lastPage - j;
            }
            printPage(painter, pages[index], index + 1);
        }
    }
}
函数printPages()的作用是调用printPage()按照顺序和打印份数打印每一页。通过QPrintDialog,用户可能需要打印多份,设置了打印范围,或者要求逆序打印。我们需要在程序中考虑这些需求
首先确定打印范围。QPrinter::fromPage()和toPage()返回用户选择的页面范围。如果没有选择,返回为0。我们进行了减1操作是因为我们的页面索引是从0开始的。如果用户没有选定范围,则打印全部,firstPage和lastPage包含量所有的页面。
然后我们打印每一页。最外层循环为用户设定的打印的份数。对于那些支持多份打印的打印机,QPrinter::numCopies()总是返回1。如果打印机驱动程序不支持多份打印,numCopies()返回到是用户指定的打印份数,有应用程序实现多份打印。(在这一节的QImage例子中,为了简单起见,我们没有考虑多份打印。)
Figure 8.15. Printing a flower guide using QPainter
内层循环遍历打印的页数。如果页数不是第一页,调用newPage()清楚原来的页面开始填充新页面。调用printPage()打印每一页。
void PrintWindow::printPage(QPainter *painter,
                            const QStringList &entries, int pageNumber)
{
    painter->save();
    painter->translate(0, LargeGap);
    foreach (QString entry, entries) {
        QStringList fields = entry.split(": ");
        QString title = fields[0];
        QString body = fields[1];
        printBox(painter, title, titleFont, Qt::lightGray);
        printBox(painter, body, bodyFont, Qt::white);
        painter->translate(0, MediumGap);
    }
    painter->restore();
    painter->setFont(footerFont);
    painter->drawText(painter->window(),
                      Qt::AlignHCenter | Qt::AlignBottom,
                      QString::number(pageNumber));
}
函数printPage()打印页面中的每一个条目。首先用printBox()打印标题,然后用printBox()打印描述。在每一页的底端打印页码。
Figure 8.16. The flower guide's page layout
 
void PrintWindow::printBox(QPainter *painter, const QString &str,
                           const QFont &font, const QBrush &brush)
{
    painter->setFont(font);
    int boxWidth = painter->window().width();
    int textWidth = boxWidth - 2 * SmallGap;
    int maxHeight = painter->window().height();
    QRect textRect = painter->boundingRect(SmallGap, SmallGap,
                                           textWidth, maxHeight,
                                           Qt::TextWordWrap, str);
    int boxHeight = textRect.height() + 2 * SmallGap;
    painter->setPen(QPen(Qt::black, 2, Qt::SolidLine));
    painter->setBrush(brush);
    painter->drawRect(0, 0, boxWidth, boxHeight);
    painter->drawText(textRect, Qt::TextWordWrap, str);
    painter->translate(0, boxHeight);
}
printBox()首先绘制一个矩形框,然后在矩形框中绘制文本。
 

QPrinter和QPrintDialog的使用举例

#ifndef QT_NO_PRINTER QPrinter printer(QPrinter::HighResolution); qDebug()true "PDF-XChange ...
  • u013639526
  • u013639526
  • 2015年01月15日 22:33
  • 3014

QT 打印的简单实现

作为第一次使用QT打印功能我确实被吓到了,在别人鼓吹QPainter强大的时候我不得不考虑工程里大量的图表及曲线图现在都需要一条一条线来画,我似乎看到了我被老板炒鱿鱼并踢出办公室的情景。   图表费...
  • fouder_li
  • fouder_li
  • 2011年08月20日 23:23
  • 16566

Android系统打印服务插件printservice开发

一 简介从Android4.4开始,系统加入了打印相关的API,可以通过系统打印服务实现打印。对于需要使用打印功能的APP可参考官方教程接入打印服务。 Printing Content https...
  • bboxhe
  • bboxhe
  • 2016年03月28日 22:01
  • 7487

android连接打印机打印

Android用户经常只在自己的设备上查看内容,但有时显示某人的屏幕不是一种充分的方式来共享信息。 您可以从Android应用程式列印资讯,让使用者可以透过应用程式查看更大版本的内容,或与未使用您应用...
  • dengpeng_
  • dengpeng_
  • 2017年03月08日 11:38
  • 7251

剑指offer面试题:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字

题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。 输入一个矩阵如下:  1     2     3    4  5     6     7    8  9    10   ...
  • yanxiaolx
  • yanxiaolx
  • 2016年08月19日 22:22
  • 2283

Simplifying printing in Windows 8-简化Windows8( win8) 打印驱动开发

Simplifying printing in Windows 8   Thursday, July 26, 2012 1:30 AM Comments 102 ...
  • kingmax54212008
  • kingmax54212008
  • 2014年08月23日 00:13
  • 976

Printing tools 自定义模板打印的实现

安装完arcgis server 在站点的utilities 目录下有printing tools的gp服务,其下面有个export web map操作,通过这个gp服务可以实现对web 地图的打印。...
  • myyouthlife
  • myyouthlife
  • 2014年01月06日 15:36
  • 680

基于半色调技术的图像打印程序(Image Printing Program Based on Halftoning)

摘 要:本实验采用半色调技术对图像进行打印和显示。使用实验后面所给出了用点模式近似表示的0到9,10个灰度级来表示一张图片。每一个灰度级用一个3*3的黑白点模式表示。用3*3全黑点近似表示灰度级...
  • liyuefeilong
  • liyuefeilong
  • 2015年01月25日 17:47
  • 4367

打印各种形状三角形(Triangle Printing Program)

现在发现,打印各种图形还真是要动脑筋的: 1. 发现图形的规律 2. 确定循环语句的控制变量的初始值、增量和循环条件 调试成功的一瞬间,感觉还是挺有成就感的。 另外发现,在本例中,使用...
  • hpdlzu80100
  • hpdlzu80100
  • 2016年06月21日 16:58
  • 798

JavaApplet打印的时候报错:Error printing report.See the console for details

西安机保很多客户端程序在使用Jasper打印的时候,客户端Applet都报 Error printing report.See the console for details。   点击右下角的咖...
  • ziwen00
  • ziwen00
  • 2012年06月19日 16:59
  • 15956
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:8-4 打印(Printing)
举报原因:
原因补充:

(最多只允许输入30个字)