python3+PyQt5实现文档打印功能


Posted in Python onApril 24, 2018

本文通过Python3+PyQt5实现《python Qt Gui 快速编程》这本书13章文档打印功能。本文共通过三种方式:

1、使用HTML和QTextDOcument打印文档
2、使用QTextCusor和QTextDocument打印文档
3、使用QPainter打印文档

使用Qpainter打印文档比QTextDocument需要更操心和复杂的计算,但是QPainter确实能够对输出赋予完全控制。

#!/usr/bin/env python3
import math
import sys
import html
from PyQt5.QtPrintSupport import QPrinter,QPrintDialog
from PyQt5.QtCore import (QDate, QRectF, Qt)
from PyQt5.QtWidgets import (QApplication,QDialog, 
 QHBoxLayout,QPushButton, QTableWidget, QTableWidgetItem,QVBoxLayout)
from PyQt5.QtGui import (QFont,QFontMetrics,QPainter,QTextCharFormat,
  QTextCursor, QTextDocument, QTextFormat,
  QTextOption, QTextTableFormat,
  QPixmap,QTextBlockFormat)
import qrc_resources


from PyQt5.QtPrintSupport import QPrinter,QPrintDialog
from PyQt5.QtCore import (QDate, QRectF, Qt)
from PyQt5.QtWidgets import (QApplication,QDialog, 
 QHBoxLayout,QPushButton, QTableWidget, QTableWidgetItem,QVBoxLayout)
from PyQt5.QtGui import (QFont,QFontMetrics,QPainter,QTextCharFormat,
  QTextCursor, QTextDocument, QTextFormat,
  QTextOption, QTextTableFormat,
  QPixmap,QTextBlockFormat)
import qrc_resources
DATE_FORMAT = "MMM d, yyyy"


class Statement(object):

 def __init__(self, company, contact, address):
 self.company = company
 self.contact = contact
 self.address = address
 self.transactions = [] # List of (QDate, float) two-tuples


 def balance(self):
 return sum([amount for date, amount in self.transactions])


class Form(QDialog):

 def __init__(self, parent=None):
 super(Form, self).__init__(parent)

 self.printer = QPrinter()
 self.printer.setPageSize(QPrinter.Letter)
 self.generateFakeStatements()
 self.table = QTableWidget()
 self.populateTable()

 cursorButton = QPushButton("Print via Q&Cursor")
 htmlButton = QPushButton("Print via &HTML")
 painterButton = QPushButton("Print via Q&Painter")
 quitButton = QPushButton("&Quit")

 buttonLayout = QHBoxLayout()
 buttonLayout.addWidget(cursorButton)
 buttonLayout.addWidget(htmlButton)
 buttonLayout.addWidget(painterButton)
 buttonLayout.addStretch()
 buttonLayout.addWidget(quitButton)
 layout = QVBoxLayout()
 layout.addWidget(self.table)
 layout.addLayout(buttonLayout)
 self.setLayout(layout)

 cursorButton.clicked.connect(self.printViaQCursor)
 htmlButton.clicked.connect(self.printViaHtml)
 painterButton.clicked.connect(self.printViaQPainter)
 quitButton.clicked.connect(self.accept)

 self.setWindowTitle("Printing")


 def generateFakeStatements(self):
 self.statements = []
 statement = Statement("Consality", "Ms S. Royal",
 "234 Rue Saint Hyacinthe, 750201, Paris")
 statement.transactions.append((QDate(2007, 8, 11), 2342))
 statement.transactions.append((QDate(2007, 9, 10), 2342))
 statement.transactions.append((QDate(2007, 10, 9), 2352))
 statement.transactions.append((QDate(2007, 10, 17), -1500))
 statement.transactions.append((QDate(2007, 11, 12), 2352))
 statement.transactions.append((QDate(2007, 12, 10), 2352))
 statement.transactions.append((QDate(2007, 12, 20), -7500))
 statement.transactions.append((QDate(2007, 12, 20), 250))
 statement.transactions.append((QDate(2008, 1, 10), 2362))
 self.statements.append(statement)

 statement = Statement("Demamitur Plc", "Mr G. Brown",
 "14 Tall Towers, Tower Hamlets, London, WC1 3BX")
 statement.transactions.append((QDate(2007, 5, 21), 871))
 statement.transactions.append((QDate(2007, 6, 20), 542))
 statement.transactions.append((QDate(2007, 7, 20), 1123))
 statement.transactions.append((QDate(2007, 7, 20), -1928))
 statement.transactions.append((QDate(2007, 8, 13), -214))
 statement.transactions.append((QDate(2007, 9, 15), -3924))
 statement.transactions.append((QDate(2007, 9, 15), 2712))
 statement.transactions.append((QDate(2007, 9, 15), -273))
 #statement.transactions.append((QDate(2007, 11, 8), -728))
 #statement.transactions.append((QDate(2008, 2, 7), 228))
 #statement.transactions.append((QDate(2008, 3, 13), -508))
 #statement.transactions.append((QDate(2008, 3, 22), -2481))
 #statement.transactions.append((QDate(2008, 4, 5), 195))
 self.statements.append(statement)


 def populateTable(self):
 headers = ["Company", "Contact", "Address", "Balance"]
 self.table.setColumnCount(len(headers))
 self.table.setHorizontalHeaderLabels(headers)
 self.table.setRowCount(len(self.statements))
 for row, statement in enumerate(self.statements):
 self.table.setItem(row, 0, QTableWidgetItem(statement.company))
 self.table.setItem(row, 1, QTableWidgetItem(statement.contact))
 self.table.setItem(row, 2, QTableWidgetItem(statement.address))
 item = QTableWidgetItem("$ {0:,.2f}".format(float(statement.balance())))
 item.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
 self.table.setItem(row, 3, item)
 self.table.resizeColumnsToContents()


 def printViaHtml(self):
 htmltext = ""
 for statement in self.statements:
 date = QDate.currentDate().toString(DATE_FORMAT)
 address = html.escape(statement.address).replace(
  ",", "<br>")
 contact = html.escape(statement.contact)
 balance = statement.balance()
 htmltext += ("<p align=right><img src=':/logo.png'></p>"
  "<p align=right>Greasy Hands Ltd."
  "<br>New Lombard Street"
  "<br>London<br>WC13 4PX<br>{0}</p>"
  "<p>{1}</p><p>Dear {2},</p>"
  "<p>The balance of your account is $ {3:,.2f}.").format(
  date, address, contact, float(balance))
 if balance < 0:
 htmltext += (" <p><font color=red><b>Please remit the "
  "amount owing immediately.</b></font>")
 else:
 htmltext += (" We are delighted to have done business "
  "with you.")
 htmltext += ("</p><p> </p><p>"
  "<table border=1 cellpadding=2 "
  "cellspacing=2><tr><td colspan=3>"
  "Transactions</td></tr>")
 for date, amount in statement.transactions:
 color, status = "black", "Credit"
 if amount < 0:
  color, status = "red", "Debit"
 htmltext += ("<tr><td align=right>{0}</td>"
  "<td>{1}</td><td align=right>"
  "<font color={2}>$ {3:,.2f}</font></td></tr>".format(
  date.toString(DATE_FORMAT), status, color,float(abs(amount))))
 htmltext += ("</table></p><p style='page-break-after:always;'>"
  "We hope to continue doing "
  "business with you,<br>Yours sincerely,"
  "<br><br>K. Longrey, Manager</p>")
 dialog = QPrintDialog(self.printer, self)
 if dialog.exec_():
 document = QTextDocument()
 document.setHtml(htmltext)
 document.print_(self.printer)

 def printViaQCursor(self):
 dialog = QPrintDialog(self.printer, self)
 if not dialog.exec_():
 return
 logo = QPixmap(":/logo.png")
 headFormat = QTextBlockFormat()
 headFormat.setAlignment(Qt.AlignLeft)
 headFormat.setTextIndent(
 self.printer.pageRect().width() - logo.width() - 216)
 bodyFormat = QTextBlockFormat()
 bodyFormat.setAlignment(Qt.AlignJustify)
 lastParaBodyFormat = QTextBlockFormat(bodyFormat)
 lastParaBodyFormat.setPageBreakPolicy(
 QTextFormat.PageBreak_AlwaysAfter)
 rightBodyFormat = QTextBlockFormat()
 rightBodyFormat.setAlignment(Qt.AlignRight)
 headCharFormat = QTextCharFormat()
 headCharFormat.setFont(QFont("Helvetica", 10))
 bodyCharFormat = QTextCharFormat()
 bodyCharFormat.setFont(QFont("Times", 11))
 redBodyCharFormat = QTextCharFormat(bodyCharFormat)
 redBodyCharFormat.setForeground(Qt.red)
 tableFormat = QTextTableFormat()
 tableFormat.setBorder(1)
 tableFormat.setCellPadding(2)

 document = QTextDocument()
 cursor = QTextCursor(document)
 mainFrame = cursor.currentFrame()
 page = 1
 for statement in self.statements:
 cursor.insertBlock(headFormat, headCharFormat)
 cursor.insertImage(":/logo.png")
 for text in ("Greasy Hands Ltd.", "New Lombard Street",
  "London", "WC13 4PX",
  QDate.currentDate().toString(DATE_FORMAT)):
 cursor.insertBlock(headFormat, headCharFormat)
 cursor.insertText(text)
 for line in statement.address.split(", "):
 cursor.insertBlock(bodyFormat, bodyCharFormat)
 cursor.insertText(line)
 cursor.insertBlock(bodyFormat)
 cursor.insertBlock(bodyFormat, bodyCharFormat)
 cursor.insertText("Dear {0},".format(statement.contact))
 cursor.insertBlock(bodyFormat)
 cursor.insertBlock(bodyFormat, bodyCharFormat)
 balance = statement.balance()
 cursor.insertText("The balance of your account is $ {0:,.2f}.".format(float(balance)))
 if balance < 0:
 cursor.insertBlock(bodyFormat, redBodyCharFormat)
 cursor.insertText("Please remit the amount owing "
   "immediately.")
 else:
 cursor.insertBlock(bodyFormat, bodyCharFormat)
 cursor.insertText("We are delighted to have done "
   "business with you.")
 cursor.insertBlock(bodyFormat, bodyCharFormat)
 cursor.insertText("Transactions:")
 table = cursor.insertTable(len(statement.transactions), 3,
   tableFormat)
 row = 0
 for date, amount in statement.transactions:
 cellCursor = table.cellAt(row, 0).firstCursorPosition()
 cellCursor.setBlockFormat(rightBodyFormat)
 cellCursor.insertText(date.toString(DATE_FORMAT),
   bodyCharFormat)
 cellCursor = table.cellAt(row, 1).firstCursorPosition()
 if amount > 0:
  cellCursor.insertText("Credit", bodyCharFormat)
 else:
  cellCursor.insertText("Debit", bodyCharFormat)
 cellCursor = table.cellAt(row, 2).firstCursorPosition()
 cellCursor.setBlockFormat(rightBodyFormat)
 format = bodyCharFormat
 if amount < 0:
  format = redBodyCharFormat
 cellCursor.insertText("$ {0:,.2f}".format(float(amount)), format)
 row += 1
 cursor.setPosition(mainFrame.lastPosition())
 cursor.insertBlock(bodyFormat, bodyCharFormat)
 cursor.insertText("We hope to continue doing business "
  "with you,")
 cursor.insertBlock(bodyFormat, bodyCharFormat)
 cursor.insertText("Yours sincerely")
 cursor.insertBlock(bodyFormat)
 if page == len(self.statements):
 cursor.insertBlock(bodyFormat, bodyCharFormat)
 else:
 cursor.insertBlock(lastParaBodyFormat, bodyCharFormat)
 cursor.insertText("K. Longrey, Manager")
 page += 1
 document.print_(self.printer)


 def printViaQPainter(self):
 dialog = QPrintDialog(self.printer, self)
 if not dialog.exec_():
 return
 LeftMargin = 72
 sansFont = QFont("Helvetica", 10)
 sansLineHeight = QFontMetrics(sansFont).height()
 serifFont = QFont("Times", 11)
 fm = QFontMetrics(serifFont)
 DateWidth = fm.width(" September 99, 2999 ")
 CreditWidth = fm.width(" Credit ")
 AmountWidth = fm.width(" W999999.99 ")
 serifLineHeight = fm.height()
 logo = QPixmap(":/logo.png")
 painter = QPainter(self.printer)
 pageRect = self.printer.pageRect()
 page = 1
 for statement in self.statements:
 painter.save()
 y = 0
 x = pageRect.width() - logo.width() - LeftMargin
 painter.drawPixmap(x, 0, logo)
 y += logo.height() + sansLineHeight
 painter.setFont(sansFont)
 painter.drawText(x, y, "Greasy Hands Ltd.")
 y += sansLineHeight
 painter.drawText(x, y, "New Lombard Street")
 y += sansLineHeight
 painter.drawText(x, y, "London")
 y += sansLineHeight
 painter.drawText(x, y, "WC13 4PX")
 y += sansLineHeight
 painter.drawText(x, y,
  QDate.currentDate().toString(DATE_FORMAT))
 y += sansLineHeight
 painter.setFont(serifFont)
 x = LeftMargin
 for line in statement.address.split(", "):
 painter.drawText(x, y, line)
 y += serifLineHeight
 y += serifLineHeight
 painter.drawText(x, y, "Dear {0},".format(statement.contact))
 y += serifLineHeight

 balance = statement.balance()
 painter.drawText(x, y, "The balance of your account is $ {0:,.2f}".format(float(balance)))
 y += serifLineHeight
 if balance < 0:
 painter.setPen(Qt.red)
 text = "Please remit the amount owing immediately."
 else:
 text = ("We are delighted to have done business "
  "with you.")
 painter.drawText(x, y, text)
 painter.setPen(Qt.black)
 y += int(serifLineHeight * 1.5)
 painter.drawText(x, y, "Transactions:")
 y += serifLineHeight

 option = QTextOption(Qt.AlignRight|Qt.AlignVCenter)
 for date, amount in statement.transactions:
 x = LeftMargin
 h = int(fm.height() * 1.3)
 painter.drawRect(x, y, DateWidth, h)
 painter.drawText(
  QRectF(x + 3, y + 3, DateWidth - 6, h - 6),
  date.toString(DATE_FORMAT), option)
 x += DateWidth
 painter.drawRect(x, y, CreditWidth, h)
 text = "Credit"
 if amount < 0:
  text = "Debit"
 painter.drawText(
  QRectF(x + 3, y + 3, CreditWidth - 6, h - 6),
  text, option)
 x += CreditWidth
 painter.drawRect(x, y, AmountWidth, h)
 if amount < 0:
  painter.setPen(Qt.red)
 painter.drawText(
  QRectF(x + 3, y + 3, AmountWidth - 6, h - 6),
  "$ {0:,.2f}".format(float(amount)),
  option)
 painter.setPen(Qt.black)
 y += h
 y += serifLineHeight
 x = LeftMargin
 painter.drawText(x, y, "We hope to continue doing "
   "business with you,")
 y += serifLineHeight
 painter.drawText(x, y, "Yours sincerely")
 y += serifLineHeight * 3
 painter.drawText(x, y, "K. Longrey, Manager")
 x = LeftMargin
 y = pageRect.height() - 72
 painter.drawLine(x, y, pageRect.width() - LeftMargin, y)
 y += 2
 font = QFont("Helvetica", 9)
 font.setItalic(True)
 painter.setFont(font)
 option = QTextOption(Qt.AlignCenter)
 option.setWrapMode(QTextOption.WordWrap)
 painter.drawText(
  QRectF(x, y, pageRect.width() - 2 * LeftMargin, 31),
  "The contents of this letter are for information "
  "only and do not form part of any contract.",
  option)
 page += 1
 if page <= len(self.statements):
 self.printer.newPage()
 painter.restore()


if __name__ == "__main__":
 app = QApplication(sys.argv)
 form = Form()
 form.show()
 app.exec_()

运行结果:

python3+PyQt5实现文档打印功能

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python 基础教程之str和repr的详解
Aug 20 Python
python不换行之end=与逗号的意思及用途
Nov 21 Python
使用python进行文本预处理和提取特征的实例
Jun 05 Python
Scrapy使用的基本流程与实例讲解
Oct 21 Python
Python Series从0开始索引的方法
Nov 06 Python
Python2.7实现多进程下开发多线程示例
May 31 Python
python-tkinter之按钮的使用,开关方法
Jun 11 Python
python3 tkinter实现点击一个按钮跳出另一个窗口的方法
Jun 13 Python
Python range、enumerate和zip函数用法详解
Sep 11 Python
如何利用Python写个坦克大战
Nov 18 Python
opencv-python图像配准(匹配和叠加)的实现
Jun 23 Python
Python Matplotlib绘制等高线图与渐变色扇形图
Apr 14 Python
Python结合ImageMagick实现多张图片合并为一个pdf文件的方法
Apr 24 #Python
python3+PyQt5实现柱状图
Apr 24 #Python
python3+PyQt5自定义视图详解
Apr 24 #Python
python自动重试第三方包retrying模块的方法
Apr 24 #Python
python3+PyQt5泛型委托详解
Apr 24 #Python
python去除扩展名的实例讲解
Apr 23 #Python
python3 遍历删除特定后缀名文件的方法
Apr 23 #Python
You might like
php文件夹的创建与删除方法
2015/01/24 PHP
PHP模拟post提交数据方法汇总
2016/02/16 PHP
PHPMailer ThinkPHP实现自动发送邮件功能
2018/06/10 PHP
Extjs Ext.MessageBox.confirm 确认对话框详解
2010/04/02 Javascript
深入理解JavaScript系列(12) 变量对象(Variable Object)
2012/01/16 Javascript
基于jquery的跟随屏幕滚动代码
2012/07/24 Javascript
extjs 04_grid 单击事件新发现
2012/11/27 Javascript
JavaScript加强之自定义callback示例
2013/09/21 Javascript
jQuery实现复选框成对选择及对应取消的方法
2015/03/03 Javascript
jQuery 实现评论等级好评差评特效
2016/05/06 Javascript
jQuery实现产品对比功能附源码下载
2016/08/09 Javascript
原生js实现放大镜特效
2017/03/08 Javascript
html5+canvas实现支持触屏的签名插件教程
2017/05/08 Javascript
基于Require.js使用方法(总结)
2017/10/26 Javascript
纯JS实现的读取excel文件内容功能示例【支持所有浏览器】
2018/06/23 Javascript
微信小程序自定义音乐进度条的实例代码
2018/08/28 Javascript
使用node搭建自动发图文微博机器人的方法
2019/03/22 Javascript
小程序实现投票进度条
2019/11/20 Javascript
使用Python3编写抓取网页和只抓网页图片的脚本
2015/08/20 Python
pandas 使用apply同时处理两列数据的方法
2018/04/20 Python
浅谈django rest jwt vue 跨域问题
2018/10/26 Python
Python GUI自动化实现绕过验证码登录
2020/01/10 Python
Python爬虫实现模拟点击动态页面
2020/03/05 Python
详解HTML5中ol标签的用法
2015/09/08 HTML / CSS
英国建筑用品在线:Building Supplies Online(BSO)
2018/04/30 全球购物
酒店总经理欢迎词
2014/01/08 职场文书
《自选商场》教学反思
2014/02/14 职场文书
军训口号
2014/06/13 职场文书
一份文言文检讨书
2014/09/13 职场文书
教师个人自我剖析材料
2014/09/29 职场文书
五星级酒店前台接待岗位职责
2015/04/02 职场文书
计划生育责任书
2015/05/09 职场文书
反四风问题学习心得体会
2016/01/22 职场文书
演讲稿:态度决定一切
2019/04/02 职场文书
世界十大儿童漫画书排名,法国国宝漫画排第五,第二是轰动日本连环
2022/03/18 欧美动漫
zabbix如何添加监控主机和自定义监控项
2022/08/14 Servers