打印时不考虑HTMLtable长宽

The HTML table length and width is not taken in consideration when printing

使用 Pyside6,我正在尝试打印 HTML Table。 HTML table 格式在浏览器中看起来不错。但是,当我在 Pyside6 的打印预览中打开它时,不考虑 table 的长度和宽度并且 table 折叠。

开发环境:

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

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

预期:

实际:

main.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>

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

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

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

所以将 翻译成 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 后你得到: