PDF 输出不适用于 Pyqt5 和 Python 3.5
Posted
技术标签:
【中文标题】PDF 输出不适用于 Pyqt5 和 Python 3.5【英文标题】:PDF output not working with Pyqt5 and Python 3.5 【发布时间】:2018-02-18 10:18:03 【问题描述】:我已经为此测试了至少 20 种不同的解决方法。
我想打印一个小部件。
我的小部件是一个发票,它包含在许多其他小部件中,例如 QLineEdits、带有文本的 QLabels、充当图像的 QLabels、QDropDown 菜单等。这是一个屏幕截图(像 NIF 这样的所有数据都是临时占位符真正的企业):
所以应该很容易吧?好像不是这样的。
-
首先我尝试将它发送到打印机,仅此一项就很难处理许多不同的打印特定选项。经过我所有的研究,我发现 QPrintDialog 可以处理大部分内容
在测试了一段时间后,我注意到它可以很好地抓取小部件,但它会将它打印到一个非常小的部分,所以经过大量研究后,我找到了一种扩展它的方法,这就是我最终的结果。李>
代码:
def print_as_pdf(widgettoprint):
# Printer
printer = QPrinter()
setupdialog = QPrintDialog(printer, widgettoprint)
if setupdialog.exec() == QPrintDialog.Accepted:
# Renderer
painter = QPainter(printer)
painter.begin(printer)
# Scale it
xscale = printer.pageRect().width() / widgettoprint.width()
yscale = printer.pageRect().height() / widgettoprint.height()
scale = min(xscale, yscale)
painter.translate(printer.paperRect().x() + printer.pageRect().width() / 2,
printer.paperRect().y() + printer.pageRect().height() / 2)
painter.scale(scale, scale)
painter.translate(-1 * widgettoprint.width() / 2, -1 * widgettoprint.height() / 2)
widgettoprint.render(painter)
painter.end()
return True
else:
return False
它成功了,它按预期打印了整个 A4 页面,但是文本的质量很差。我发现它只是截取它而不是将数据保存为文本或矢量数据。
所以这对我不起作用,但我必须尝试。我尝试使用相同的方法(选择 PDF 作为打印机)打印为 PDF,它只是生成一个带有屏幕截图的 PDF。我无法选择或复制文本数据。
-
所以我研究了替代品。我找到了Reportlab,但无法让它工作。我也尝试过PyFPDF,但特别是在不选择打印机的情况下创建 PDF 会破坏将发票实际打印到其他打印机的能力。
好吧,我花了几天的挫折试图寻找替代方案,而不是从头开始重建我的 7000 行代码程序。我找到了this blog about jinja2 and qt 解决方法,并决定试一试。将整个发票重新创建为 html 模板将是一项相当大的工作(因为有更多不同的发票,而不仅仅是这张)。但是出现了一个新问题,PyQt5 没有 QtWebKit 或 QWebView,据我所知,使用此代码和 QtWebEngine 打印一个白色的空 PDF:
代码:
import os
from jinja2 import Environment, FileSystemLoader
from PyQt5 import QtWebEngineWidgets
from PyQt5.QtPrintSupport import QPrinter, QPrintDialog
from PyQt5.QtGui import QPainter
PATH = os.path.dirname(os.path.abspath(__file__))
TEMPLATE_ENVIRONMENT = Environment(
autoescape=False,
loader=FileSystemLoader(os.path.join(PATH, 'userfiles/templates')),
trim_blocks=False)
def render_template(template_filename, context):
return TEMPLATE_ENVIRONMENT.get_template(template_filename).render(context)
def test():
something = ['something1', 'something2', 'something3']
context =
'something': something,
'invoicenumber': "17012"
# Generate the HTML data with the template without creating a file, on-the-fly
html = render_template('invoices.html', context)
# add html to a webengine/widget
web = QtWebEngineWidgets.QWebEngineView()
web.page().setHtml(html)
# Print that widget
printer = QPrinter()
setupdialog = QPrintDialog(printer)
if setupdialog.exec() == QPrintDialog.Accepted:
web.render(printer)
print("done")
test()
HTML 模板在哪里:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Factura invoicenumber </title>
</head>
<body>
<center>
<h1>Factura invoicenumber </h1>
<p> something|length something</p>
</center>
<ol align="left">
something[0]
something[1]
something[2]
</ol>
</body>
</html>
我可能会花费更多的几周和几个月的时间来尝试实现这一目标。打印本来应该很容易,因为市场上的每个随机程序似乎都能够打印或创建 PDF,但现在对我来说,这是我编程学习经历中最糟糕的部分。
目标: 这个问题旨在为我的问题找到永久解决方案:如何将我的发票小部件打印到可选(Windows 平台)打印机?然后,如果选择了 PDF 打印机,请使用矢量或其他任何不创建屏幕截图的方式以无限质量进行打印。
由于我仍在学习(编程、Python 和 Qt),我也希望能解释我做错了什么。
【问题讨论】:
您需要show()
网络视图才能获得一些可见的输出。然而,当我在 linux 上尝试这个时,结果并不是那么令人印象深刻。如果您使用的是 Windows,您可能想尝试像这样创建打印机:QPrinter(QPrinter.HighResolution)
。
PS:AFAICS,通过网络视图渲染只会创建一个包含图像的 pdf。因此,如果我正确理解了您的要求,它似乎并没有真正让您有所收获。
嗯,那它确实也行不通。我该怎么办?
你读过 Qt Wiki 上的Handling PDF 吗?这有很多有用的建议。
实际上,我认为您可以使用QTextDocument
实现您想要的 - 我什至已经提供了如何在 SO 上做到这一点的示例!请参阅this answer 和this answer。我刚刚测试了第一个,并且可以确认可以选择和复制生成的 pdf 的单个文本元素。
【参考方案1】:
虽然我自己在 python 中编程,但我对在其中编程 GUI 知之甚少。但是,我发现了几个问题和站点,可以作为您自己实施的起点。我知道其中一些是 QT4,但请看一看,我相信事情并没有太大变化(但我可能是错的):Pyqt take screenshot of certain screen areaScreenshot of a window using python@ 987654323@https://github.com/Python-Devs-Brasil/PyQt5-Tutorials/blob/master/Post-2(QtCore)/screenshot.pyhttps://github.com/baoboa/pyqt5/blob/master/examples/desktop/screenshot.pyHow to grab a desktop screenshot with PyQt?
编辑
您是否尝试过通过 matplotlib
保存到 pdf 文件?https://pythonspot.com/en/matplotlib-save-figure-to-image-file/saving images in python at a very high quality
编辑 2 另外,看看这个Create a pdf with fillable fields python
编辑 3 您还可以查看此问题中提到的库的文档和示例Python PDF library
【讨论】:
感谢您的回答,但我认为您错过了目标 :(。所有这些链接旨在捕获屏幕截图,我已经能够做到。我的目标不是那个。我的目标是将 PDF 打印为“不是”屏幕截图,因为否则您无法使用鼠标选择 PDF 上的数据。所需的解决方案需要将 PDF 呈现为布局(将转换视为 PDF 到 HTML 的示例。如果结果只是一个屏幕截图,那么它是 HTML 的意义是没有用的。PNG 可以工作。但你需要它 HTML 来选择数据/捕获/编辑数据)。我需要我的发票为 PDF,但不是屏幕截图。 第二次编辑可能是我需要的。我正在检查它。 请告诉我第二次编辑中的问题是否有帮助。以上是关于PDF 输出不适用于 Pyqt5 和 Python 3.5的主要内容,如果未能解决你的问题,请参考以下文章
pyinstaller 不适用于 pyqt5 和 matplotlib