QT中的打印

qt中簡單的打印過程
1、新建一個qprintviewdialog對象p。
2、connect對象p的 printrequisition 信號到自己的一個函數如doprint(*printer)
3、實現doprint函數,就是在裏面使用 qpainter(print)新建一個painter後直接在裏面畫就好了。
4、p.exec()
這種方式是顯示qt提供的打印預覽對話框,該對話框需要你提供printrequisition信號的實際實現。當p需要預覽或打印時就會發出該信號,你只要實現好doprint函數即可,別的qt都爲你做好了。
需要注意的是:
1、在第三步中當調用painter.begin後默認就會創建一個空白頁,所以一開始不需要 newpage,直接畫就是了;
2、在一頁畫完以後直接調用print.newpage創建新頁面
3、直到所有頁面畫完後纔可以調用 painter.end().
4、qt提供的qprintviewdialog對話框已經包含了所有有關打印設置的功能,如需定製可以在新建p之前調用printdialog對話框來獲取打印機,將其傳給p的構造函數即可。
5、printer對象的pagerect返回的是去掉頁邊距後的矩形;paperrect返回的是紙張大小(單位可以設置)
6、這種方式不能適合多種打印機,也就是說你設計好了能工作了可能換到針式打印機就不一樣了。因爲不同打印機支持的紙張及打印分辨率不同。
解決方法推薦:
建議首先在A4紙張和300或600分辨率下設計,程序中設置一個變量deltaW=程序運行時打印機中的紙張寬度*程序運行時打印機分辨率/(A4紙寬度*300或600),然後在所有表示座標.x或大小.w的數字上乘以deltaW即可。同樣的也可以設置垂直縮放比例。
注意是所有的,包括字體大小、及繪圖中的各種座標。這樣不管用什麼紙張在什麼打印機下都可以完全顯示了(打出來會是整體放大或縮小)。如果你能預先知道客戶機上的打印環境的話,就不必這一步了。

================================

在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()首先繪製一個矩形框,然後在矩形框中繪製文本。

 

 

 

打印預覽:

void Widget::on_pushButton_6_clicked()

{
    QPrinter printer(QPrinter::HighResolution);
    QPrintPreviewDialog preview(&printer,this);
    connect(&preview,SIGNAL(paintRequested(QPrinter*)),this,SLOT(printView(QPrinter*)));
    preview.exec();
}
void Widget::printView(QPrinter *printer)
{
    ui->textBrowser->print(printer);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章