在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’,’>’,’<’),然後調用 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()首先繪製一個矩形框,然後在矩形框中繪製文本。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/iamdbl/archive/2007/10/08/1816001.aspx