【问题标题】:The HTML table length and width is not taken in consideration when printing打印时不考虑 HTML 表格的长宽
【发布时间】:2021-11-24 01:05:50
【问题描述】:

使用Pyside6,我正在尝试打印一个 HTML 表格。 HTML 表格格式在浏览器中看起来不错。但是,当我在Pyside6的打印预览中打开它时,没有考虑表格的长度和宽度,表格会塌陷。

开发环境:

  1. Ubuntu 20.04
  2. Python 3.8.10(使用python虚拟环境)
  3. PySide6 版本 6.1.3

我还在 Windows 中使用 Python 3.9.7 和 Pyside6 6.2 版尝试了相同的代码,并得到了相同的结果。

预期:

实际:

ma​​in.py

from PySide6.QtGui import (
    QPageSize,
    QPageLayout,
    QTextBlockFormat,
    QTextCursor,
    QTextDocument,
    QTextFormat,
)
from PySide6.QtWidgets import QApplication
from PySide6.QtPrintSupport import QPrinter, QPrintPreviewDialog

app = QApplication()

dialog = QPrintPreviewDialog()


def handle_paint_requested(printer):
    document = QTextDocument()
   
    f = open("template.html", "r")
    billTemplate = f.read()

    document.setHtml(billTemplate)
    document.print_(printer)


dialog.paintRequested.connect(handle_paint_requested)
dialog.exec()

template.html

<p>&nbsp;</p>
<table style="border-collapse: collapse; width: 300px;" border="1">
    <tbody>
        <tr>
            <td style="width: 50%; height: 50px;">test1</td>
            <td style="width: 50%; height: 50px;">&nbsp;</td>
        </tr>
    </tbody>
</table>

【问题讨论】:

  • 我想知道这是否与 pixels 在打印上下文中没有得到尊重或正确解释有关。您是否尝试过任何基于 em 或测量的维度? (另外,如果从浏览器打开打印预览会怎样?)

标签: python pyside6 qprinter qtextdocument


【解决方案1】:

由于 QTextDocument 仅支持 HTML4 属性的子集,因此会导致观察到的错误。

一种解决方法是使用在 Qt 6.2 中重新引入的 QtWebEngine。目前只有 windows .whl 在 pypi 中可用(请参阅 herehere 了解更多信息),因此我们可以安装您必须执行的 Linux 和 MacOs 包:

python -m pip install pyside6 \
   --index-url=http://download.qt.io/official_releases/QtForPython

所以将my previous answer 翻译成 PySide6:

import os
from pathlib import Path

from PySide6.QtCore import (
    QCoreApplication,
    QEventLoop,
    QObject,
    QPointF,
    Qt,
    QUrl,
    Slot,
)
from PySide6.QtGui import QKeySequence, QPainter, QShortcut
from PySide6.QtPrintSupport import QPrintDialog, QPrinter, QPrintPreviewDialog
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWidgets import (
    QApplication,
    QDialog,
    QProgressBar,
    QProgressDialog,
)

CURRENT_DIRECTORY = Path(__file__).resolve().parent


class PrintHandler(QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.m_page = None
        self.m_inPrintPreview = False

    def setPage(self, page):
        assert not self.m_page
        self.m_page = page
        self.m_page.printRequested.connect(self.printPreview)

    @Slot()
    def print(self):
        printer = QPrinter(QPrinter.HighResolution)
        dialog = QPrintDialog(printer, QWebEngineView.forPage(self.m_page))
        if dialog.exec_() != QDialog.Accepted:
            return
        self.printDocument(printer)

    @Slot()
    def printPreview(self):
        if not self.m_page:
            return
        if self.m_inPrintPreview:
            return
        self.m_inPrintPreview = True
        printer = QPrinter()
        preview = QPrintPreviewDialog(printer, QWebEngineView.forPage(self.m_page))
        preview.paintRequested.connect(self.printDocument)
        preview.exec()
        self.m_inPrintPreview = False

    @Slot(QPrinter)
    def printDocument(self, printer):
        loop = QEventLoop()
        result = False

        def printPreview(success):
            nonlocal result
            result = success
            loop.quit()

        view = QWebEngineView.forPage(self.m_page)
        view.printFinished.connect(printPreview)
        progressbar = QProgressDialog(view)
        progressbar.findChild(QProgressBar).setTextVisible(False)
        progressbar.setLabelText("Wait please...")
        progressbar.setRange(0, 0)
        progressbar.show()
        progressbar.canceled.connect(loop.quit)
        view.print(printer)
        loop.exec()
        progressbar.close()
        if not result:
            painter = QPainter()
            if painter.begin(printer):
                font = painter.font()
                font.setPixelSize(20)
                painter.setFont(font)
                painter.drawText(QPointF(10, 25), "Could not generate print preview.")
                painter.end()


def main():
    import sys

    QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
    app = QApplication(sys.argv)
    app.setApplicationName("Previewer")

    filename = CURRENT_DIRECTORY / "template.html"
    url = QUrl.fromLocalFile(os.fspath(filename))

    view = QWebEngineView()
    view.setUrl(url)
    view.resize(1024, 750)
    view.show()

    handler = PrintHandler()
    handler.setPage(view.page())

    printPreviewShortCut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_P), view)
    printShortCut = QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_P), view)

    printPreviewShortCut.activated.connect(handler.printPreview)
    printShortCut.activated.connect(handler.print)

    sys.exit(app.exec())


if __name__ == "__main__":
    main()

按下 Ctrl + P 后你会得到:

【讨论】:

  • 我收到错误 dialog = QPrintDialog(printer, self.m_page.view()) AttributeError: 'PySide6.QtWebEngineCore.QWebEnginePage' object has no attribute 'view'
  • dialog = QPrintDialog(printer, QWebEngineView.forPage(self.m_page))
  • 我的主要目标是在 linux 机器上运行它。那么我必须等到 PySide6 6.2 版可用于 linux 吗?任何预计到达时间?
  • 感谢您在这种情况下的所有帮助。在我的 linux 系统中,我启动了一个新项目集虚拟环境并设置了 pyside 6 版本 6.1.3。然后我运行了上面的命令。我得到了错误。 ModuleNotFoundError:没有名为“PySide6.QtWebEngineWidgets”的模块。我想我可能会等待 linux 官方版本,如果它会在几天内可用。上面的代码在windows上运行良好。
  • @kumar 查看我帖子中的链接,其中解释了为什么 linux 和 macos 没有 .whl,以及如何在 Linux 中使用 QtForPython 的本地 pypi 服务器安装 pyside6 6.2。
猜你喜欢
  • 2018-01-11
  • 2019-05-02
  • 1970-01-01
  • 2019-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-26
  • 1970-01-01
相关资源
最近更新 更多