40. 打印机

一、打印机

  应用程序一般都有打印功能,可以将重要内容打印成纸质资料。PySide6 支持打印操作,它可以识别系统中已经安装的打印机,驱动打印机进行工作,可以用与打印机有关的类直接打印,也可通过打印对话框进行打印,还可对打印的内容在打印前进行打印预览。与打印有关的类主要在 QtPrintSupport 模块中。

  我们可以在终端中使用 pip 安装 PySide6 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载

pip install pyside6 -i https://mirrors.aliyun.com/pypi/simple

  国内常用的 pip 下载源列表:

二、打印机信息

  PySide6 提供识别打印机硬件的类 QPrinterInfo 和进行打印的类 QPrinter。我们可以将 QPrinter 作为 QPainter 的绘图设备,然后将图形、文字和图像等用打印机进行输出,保存到纸质介质上。

  打印机信息 QPrinterInfo 代表 本机上可以使用的一台打印机,通过 QPrinterInfo 可以 获取打印机的参数。用 QPrinterInfo 创建打印机信息实例对象 的方法如下所示:

QPrinterInfo()
QPrinterInfo(printer:QPrinter)

  打印机信息 QPrinterInfo 的常用方法如下:

# 实例方法
isDefault() -> bool                                                             # 获取是否是默认的打印机
isNull() -> bool                                                                # 获取是否不含打印机信息
isRemote() -> bool                                                              # 获取是否是远程网络打印机

defaultColorMode() -> QPrinter.ColorMode                                        # 获取默认颜色模式
defaultDuplexMode() -> QPrinter.DuplexMode                                      # 获取默认双面打印模式

defaultPageSize() -> QPrinter.PaperSize                                         # 获取默认纸张大小
minimumPhysicalPageSize() -> QSizeF                                             # 获取支持的最小打印纸尺寸
maximumPhysicalPageSize() -> QSizeF                                             # 获取支持的最大打印纸尺寸

supportedColorModes() -> list[QPrinter.ColorMode]                               # 获取支持的颜色模式
supportedDuplexModes() -> list[QPrinter.DuplexMode]                             # 获取支持的双面打印模式
supportedPageSizes() -> list[QPrinter.PaperSize]                                # 获取支持的纸张大小
supportedResolutions() -> list[int]                                             # 获取支持的分辨率
supportsCustomPageSizes() -> bool                                               # 获取是否支持自定义纸张大小

description() -> str                                                            # 获取打印机描述
location() -> str                                                               # 获取打印机位置信息
makeAndModel() -> str                                                           # 获取打印机厂商和型号
printerName() -> str                                                            # 获取打印机名称
state() -> QPrinter.PrinterState                                                # 获取打印机状态

# 静态方法
static availablePrinterNames() -> list[str]                                     # 获取可用的打印机名称列表
static availablePrinters() -> list[QPrinter]                                    # 获取可用的打印机列表
static defaultPrinter() -> QPrinter                                             # 获取默认打印机
static defaultPrinterName() -> str                                              # 获取默认打印机名称
static printerInfo(printerName:str) -> QPrinterInfo                             # 根据打印机名称获取打印机

  用 defaultDuplexMode() 方法 获取打印机默认的双面打印模式,返回值是 QPrinter.DuplexMode 类型的枚举值,可以取值如下:

QPrinter.DuplexMode.DuplexNone                                                  # 单面模式,对应值0
QPrinter.DuplexMode.DuplexAuto                                                  # 用打印机的默认设置来决定是单面模式还是双面模式,对应值1
QPrinter.DuplexMode.DuplexLongSide                                              # 双面模式,打印第2面前沿纸张长边翻面,对应值2
QPrinter.DuplexMode.DuplexShortSide                                             # 双面模式,打印第2面前沿纸张短边翻面,对应值3

三、打印机

  在 PySide6 中,QPrinter 类表示 绘图设备打印的纸张,使用 QPainter 类可以在 QPrinter 对象上 绘制图形、文字等内容QPrinter 继承自 QPagedPaintDeviceQPaintDevice。用 QPrinter 创建打印机实例 的方法如下所示:

QPrinter(mode:QPrinter.PrinterMode=QPrinter.ScreenResolution)
QPrinter(printer:QPrinterInfo,mode:QPrinter.PrinterMode=QPrinter.PrinterMode.ScreenResolution)

  其中参数 mode 设置打印模式,取值是 QPrinter.PrinterMode 类型的枚举值。

  打印机 QPrinter 的常用方法如下:

setPrinterName(name:str) -> None                                                # 设置打印机名称
printerName() -> str                                                            # 获取打印机名称

setOutputFileName(name:str) -> None                                             # 设置输出文件名称
outputFileName() -> str                                                         # 获取输出文件名称

setOutputFormat(format:OutputFormat) -> None                                    # 设置打印到文件时的格式
outputFormat() -> OutputFormat                                                  # 获取打印到文件时的格式

setFullPage(full:bool) -> None                                                  # 设置是否整页模式打印
fullPage() -> bool                                                              # 获取是否整页模式打印

setCopyCount(count:int) -> None                                                 # 设置打印份数
copyCount() -> int                                                              # 获取打印份数

setCollateCopies(collate:bool) -> None                                          # 设置是否对照打印
collateCopies() -> bool                                                         # 获取是否对照打印

setFromTo(fromPage:int, toPage:int) -> None                                     # 设置打印页码范围
fromPage() -> int                                                               # 获取打印页码范围起始页
toPage() -> int                                                                 # 获取打印页码范围结束页

setColorMode(mode:ColorMode) -> None                                            # 设置打印颜色模式
colorMode() -> ColorMode                                                        # 获取打印颜色模式

setPageOrder(order:QPrinter.PageOrder) -> None                                  # 设置打印页面顺序
pageOrder() -> QPrinter.PageOrder                                               # 获取打印页面顺序

setResolution(resolution:int) -> None                                           # 设置打印精度
resolution() -> int                                                             # 获取打印精度

setDocName(name:str) -> None                                                    # 设置打印文档名称
docName() -> str                                                                # 获取打印文档名称

setDuplex(duplex:QPrinter.Duplex) -> None                                       # 设置双面模式
duplex() -> QPrinter.Duplex                                                     # 获取双面模式

setFontEmbeddingEnabled(enable:bool) -> None                                    # 设置是否启用内置字体
fontEmbeddingEnabled() -> bool                                                  # 获取是否启用内置字体

setPaperSource(source:QPrinter.PaperSource) -> None                             # 设置纸张来源
paperSource() -> QPrinter.PaperSource                                           # 获取纸张来源

abort() -> bool                                                                 # 取消正在打印的文档
isValid() -> bool                                                               # 检查打印机是否有效

paperRect(unit:QPrinter.Unit) -> QRectF                                         # 获取打印纸大小
pageRect(unit:QPrinter.Unit) -> QRectF                                          # 获取打印页面大小

printRange() -> QPageLayout.PageRange                                           # 获取打印范围的模式
printerState() -> QPrinter.PrinterState                                         # 获取打印机状态

setPdfVersion(version:QPdfWriter.PdfVersion) -> None                            # 设置PDF版本

supportedResolutions() -> list[int]                                             # 获取支持的打印精度
supportsMultipleCopies() -> bool                                                # 检查是否支持多份打印

# 继承父类的方法
pageLayout() -> QPageLayout                                                     # 获取打印页面布局

# 继承父类的虚拟方法
setPageMargins(margins:QMarginsF, units:Unit=QPageLayout.Millimeter) -> bool    # 设置打印页边距
setPageOrientation(orientation:Orientation) -> bool                             # 设置打印方向
setPageRanges(ranges:QPageRanges) -> None                                       # 设置打印页码范围
setPageSize(pageSize:QPageSize) -> None                                         # 设置打印页面大小
setPageLayout(pageLayout:QPageLayout) -> bool                                   # 设置打印页面布局

# 继承父类的抽象方法
abstract newPage() -> bool                                                      # 生成新页

  用 QPrinterInfo 的静态方法 availablePrinterNames() 可以 获得本机已经安装的打印机名称列表,然后用 QPrintersetPrinterName(name:str) 方法 将其中一台打印机设置成 QPrinter

  用 setOutputFileName(name:str) 方法 设置打印机将打印内容打印到文件中而不是纸质介质上,参数是 文件名。如果 不设置该内容或设置为空字符串,则将 内容打印到纸张上吗,如果 设置了扩展名是 PDF 的文件名,则将 打印内容输出到 PDF 文档中,如果 设置的扩展名不是 PDF,则将 打印内容输出 到按照 setOutputFormat(format:QPrinter.OutputFormat) 方法设置的文件格式的文件中,其中参数 formatQPrinter.OutputFormat 类型的枚举值,可以取值如下:

QPrinter.OutputFormat.NativeFormat                                              # 本机定义格式,值是0
QPrinter.OutputFormat.PdfFormat                                                 # PDF格式,值是1

  在打印完第一页后,需要用 newPage() 方法 通知打印机弹出当前正在打印的纸张,继续进行下一页的打印,成功则返回 True。用 abort() 方法 取消当前的打印,成功则返回 True

  用 setFullPage(full:bool) 方法 设置是否是整页模式打印。在 setFullPage(True) 时,QPainter 的坐标原点在可打印区的左上角,与纸张坐标系的原点重合,但由于页边距的限制,实际上不能在整张纸上打印;在 setFullPage(False) 时,QPainter 的坐标原点在打印区域的左上角。

  用 setPrintRange(range:QPrinter.PrintRange) 方法 设置打印范围的模式,参数 range QPrinter.PrintRange 类型的枚举值,可以取值如下:

QPrinter.PrintRange.AllPages                                                    # 打印所有页,值是0
QPrinter.PrintRange.Selection                                                   # 打印选中的页,值是1
QPrinter.PrintRange.CurrentPage                                                 # 打印当前页,值是3

  用 setPageOrientation(orientation:QPageLayout.Orientation) 方法 设置打印方向,参数 orientationQPageLayout.Orientation 类型的枚举值,可以取值如下:

QPageLayout.Orientation.Portrait                                                # 纵向,值是0
QPageLayout.Orientation.Landscape                                               # 横向,值是1

  用 setPageOrder(order:QPrinter.PageOrder) 方法 设置打印顺序,参数 orderQPrinter.PageOrder 类型的枚举值,可以取值如下:

QPrinter.PageOrder.FirstPageFirst                                               # 正常顺序,值是0
QPrinter.PageOrder.LastPageFirst                                                # 反向顺序,值是1

  新建一个 ui.py 文件,用来存放 UI 相关的代码。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel, QPushButton
from PySide6.QtWidgets import QLineEdit, QSpinBox, QComboBox
from PySide6.QtWidgets import QFormLayout
from PySide6.QtGui import Qt
from PySide6.QtPrintSupport import QPrinterInfo

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(400, 120)                                                 # 1.设置窗口对象大小

        layout = QFormLayout(window)                                            # 2.创建一个表单布局

        self.printer_name_comboBox = QComboBox()                                # 3.创建一个下拉组合框,并添加到布局中
        layout.addRow("选择打印机", self.printer_name_comboBox)

        printer_name = QPrinterInfo.availablePrinterNames()                     # 4.获取可用的打印机名称列表
        self.printer_name_comboBox.addItems(printer_name)                       # 5.将可用的打印机名称列表添加到下拉组合框中
        self.printer_name_comboBox.setCurrentText(QPrinterInfo.defaultPrinterName())    # 6.设置下拉组合框的当前选中项为默认打印机文本项

        self.copies_spinBox = QSpinBox(minimum=0, maximum=100)                  # 7.创建一个整数选择控件,并添加到布局中
        layout.addRow("设置打印份数", self.copies_spinBox)

        self.output_file_path_lineEdit = QLineEdit(text="output.pdf")           # 8.创建一个单行文本框控件,并添加到布局中
        layout.addRow("输出到文件", self.output_file_path_lineEdit)

        self.printer_button_printer = QPushButton("打印")                       # 9.创建一个按钮控件,并添加到布局中
        layout.addRow(self.printer_button_printer)

        self.info_label = QLabel()                                              # 10.添加一个提示信息标签,并添加到布局中
        layout.addRow(self.info_label)

        self.info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)              # 11.设置标签文本的对齐方式

  新建一个 widget.py 文件,用来存放业务逻辑相关的代码。

import sys
import math

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtPrintSupport import QPrinter, QPrinterInfo
from PySide6.QtGui import QPageLayout, QPageSize, QPainter, QPen
from PySide6.QtCore import QPointF

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法

        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.choose_printer(QPrinterInfo.defaultPrinterName())                  # 3.选中默认的打印机

        self.__ui.printer_name_comboBox.currentTextChanged.connect(self.choose_printer) # 4.选中打印机设备的名称改变时发送信号
        self.__ui.printer_button_printer.clicked.connect(self.print_file)       # 5.点击打印按钮时发送信号


    def choose_printer(self, text:str):
        printInfo = QPrinterInfo.printerInfo(text)                              # 1.获取打印机信息   
        self.printer = QPrinter(printInfo)                                      # 2.创建打印机对象
        self.printer.setPageOrientation(QPageLayout.Orientation.Portrait)       # 3.设置页面方向为纵向
        self.printer.setFullPage(False)                                         # 4.设置是否为整页模式
        self.printer.setPageSize(QPageSize.PageSizeId.A4)                       # 5.设置页面大小为A4
        self.printer.setColorMode(QPrinter.ColorMode.GrayScale)                 # 6.设置打印模式为灰度模式

    def print_file(self):
        self.printer.setOutputFormat(QPrinter.OutputFormat.PdfFormat)           # 1.设置输出格式为PDF
        self.printer.setOutputFileName(self.__ui.output_file_path_lineEdit.text())  # 2.设置输出到文件

        if self.printer.isValid():                                              # 3.判断打印机是否有效
            self.painter = QPainter()                                           # 4.创建绘图设备
            if self.painter.begin(self.printer):                                # 5.开始绘图,绘图设备为打印机纸张
                pen = QPen()                                                    # 6.创建钢笔对象
                pen.setWidth(5)                                                 # 7.设置钢笔宽度为5
                self.painter.setPen(pen)                                        # 8.设置绘图设备的钢笔

                x = self.printer.paperRect(QPrinter.Unit.DevicePixel).width() / 2
                y = self.printer.paperRect(QPrinter.Unit.DevicePixel).height() / 2

                r = min(self.printer.pageRect(QPrinter.Unit.DevicePixel).width() / 2, 
                        self.printer.pageRect(QPrinter.Unit.DevicePixel).height() / 2)

                p1 = QPointF(r * math.cos(-90 * math.pi / 180) + x , r * math.sin(-90 * math.pi / 180) + y)
                p2 = QPointF(r * math.cos(-18 * math.pi / 180) + x , r * math.sin(-18 * math.pi / 180) + y)
                p3 = QPointF(r * math.cos(54 * math.pi / 180) + x , r * math.sin(54 * math.pi / 180) + y)
                p4 = QPointF(r * math.cos(126 * math.pi / 180) + x , r * math.sin(126 * math.pi / 180) + y)
                p5 = QPointF(r * math.cos(198 * math.pi / 180) + x , r * math.sin(198 * math.pi / 180) + y)

                page_copies = self.__ui.copies_spinBox.value()                  # 9.获取打印纸张个数
                for i in range(1, page_copies + 1):
                    self.painter.drawPolyline([p1, p3, p5, p2, p4, p1])         # 10.绘制多边形
                    self.__ui.info_label.setText(f"正在打印第{i}页,共{page_copies}页") # 11.设置提示标签的文本
                    if i != page_copies:
                        self.printer.newPage()                                  # 12.如果不是最后一页,打印新的纸张
                self.painter.end()                                              # 13.结束绘制

                self.__ui.info_label.setText(f"打印完成,一共{page_copies}页")

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

四、控件界面打印

  如果要打印窗口或控件的界面,需要利用 QWidgetrender() 函数,它可以 把窗口或控件的指定区域打印到纸张或文件中render() 函数的格式如下所示:

render(painter:QPinter, targetOffset:QPoint, sourceRegion:Union[QRegion, QBitmap, QPolygon, QRect]=Default(QRegion), renderFlags:QWidget.RenderFlag=QWidget.RenderFlag.DrawWindowBackground | QWidget.RenderFlag.DrawChildren)

  其中,targetOffset 是指 在纸张或文件中的偏移量sourceRegion 是指 窗口或控件的区域,如果不给出则取 rect() 的返回值。target 是指 绘图设备,如 QPixmaprenderFlagsQWidget.RenderFlag 类型的枚举值的组合,可取值如下:

QWidget.RenderFlag.DrawWindowBackground                                         # 打印背景
QWidget.RenderFlag.DrawChildren                                                 # 打印子控件
QWidget.RenderFlag.IgnoreMask                                                   # 忽略mask()函数

  能打印控件内容的控件和打印函数如下:

能打印控件内容的控件和打印函数

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtPrintSupport import QPrinter, QPrinterInfo
from PySide6.QtGui import QPageLayout, QPageSize, QPainter
from PySide6.QtCore import QPoint

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法

        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.choose_printer(QPrinterInfo.defaultPrinterName())                  # 3.选中默认的打印机

        self.__ui.printer_name_comboBox.currentTextChanged.connect(self.choose_printer) # 4.选中打印机设备的名称改变时发送信号
        self.__ui.printer_button_printer.clicked.connect(self.print_file)       # 5.点击打印按钮时发送信号


    def choose_printer(self, text:str):
        printInfo = QPrinterInfo.printerInfo(text)                              # 1.获取打印机信息   
        self.printer = QPrinter(printInfo)                                      # 2.创建打印机对象
        self.printer.setPageOrientation(QPageLayout.Orientation.Portrait)       # 3.设置页面方向为纵向
        self.printer.setFullPage(False)                                         # 4.设置是否为整页模式
        self.printer.setPageSize(QPageSize.PageSizeId.A4)                       # 5.设置页面大小为A4
        self.printer.setColorMode(QPrinter.ColorMode.GrayScale)                 # 6.设置打印模式为灰度模式

    def print_file(self):
        self.printer.setOutputFormat(QPrinter.OutputFormat.PdfFormat)           # 1.设置输出格式为PDF
        self.printer.setOutputFileName(self.__ui.output_file_path_lineEdit_file.text()) # 2.设置输出到文件

        if self.printer.isValid():                                              # 3.判断打印机是否有效
            self.painter = QPainter()                                           # 4.创建绘图设备
            if self.painter.begin(self.printer):                                # 5.开始绘图,绘图设备为打印机纸张
                page_copies = self.__ui.copies_spinBox.value()                  # 6.获取打印纸张个数
                for i in range(1, page_copies + 1):
                    self.render(self.painter, QPoint(200, 0))                   # 7.打印窗口内容到文件中
                    self.__ui.info_label.setText(f"正在打印第{i}页,共{page_copies}页") # 8.设置提示标签的文本
                    if i != page_copies:
                        self.printer.newPage()                                  # 9.如果不是最后一页,打印新的纸张
                self.painter.end()                                              # 10.结束绘制

                self.__ui.info_label.setText(f"打印完成,一共{page_copies}页")

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

五、打印对话框

  除了直接用 QPrinter 进行打印外,还可以利用打印对话框 QPrintDialog 来打印,在对话框中完成对 QPrinter 的设置并进行打印。一般在打印前需要对打印的内容进行打印预览,打印预览对话框是 QPrintPreviewDialog,还可以利用打印预览控件 QPrintPreviewWidget 创建打印预览对话框。

  QPrintDialog 创建打印对话框的方法如下所示:

QPrintDialog(parent:QWidget=None)
QPrintDialog(printer:QPrinter,parent:QWidget=None)

  其中,parent表示父窗口,参数值为 QWidget 类的实例对象。printer 表示 打印机,参数值为 QPrinter 类创建的实例对象,如果没有提供 QPrinter 对象,则使用系统默认的打印机。

  QPrintDialog 打印对话框的常用方法如下:

# 实例方法
exec() -> int                                                                   # 模式显示对话框

setOption(option:PrintDialogOption, on:bool=True) -> None                       # 设置可选项
setOptions(options:Sequence[PrintDialogOption]) -> None                         # 设置多个可选项
testOption(option:PrintDialogOption) -> bool                                    # 测试是否设置了某种选项

# 继承QAbstractPrintDialog的虚拟方法
printer() -> QPrinter                                                           # 获取打印机
setPrintRange(range:QAbstractPrintDialog.PrintRange) -> None                    # 设置打印范围选项
setFromTo(fromPage:int, toPage:int) -> None                                     # 设置打印页数范围
setMinMax(min:int, max:int) -> None                                             # 设置打印页数的最小值和最大值

  一般用 exec() 方法 模式显示对话框,在对话框中单击 “打印” 按钮,返回值为 1,同时发送 accepted(printer:QPrinter) 信号,在对话框中单击 “取消” 按钮,返回值为 0。也可用 setVisible(visible:bool) 方法或 show() 方法显示对话框,这两种方法没有返回值。

  QPrintDialog 只有一个信号 accepted(printer:QPrinter),在对话框中单击 “打印” 按钮时发送信号,参数是设置了打印参数的 QPrinter 对象。

  QPrintDialog 打印对话框的常用信号如下:

accepted(printer:QPrinter)

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import  QPushButton
from PySide6.QtWidgets import  QVBoxLayout
from PySide6.QtPrintSupport import QPrintDialog

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(400, 120)                                                 # 1.设置窗口对象大小

        layout = QVBoxLayout(window)                                            # 2.创建一个垂直布局

        self.printer_button = QPushButton("打印", window)                       # 3.创建一个按钮控件,并添加到布局中
        layout.addWidget(self.printer_button)

        self.print_dialog = QPrintDialog(window)                                # 4.创建一个打印框对话框

  修改 widget.py 文件的内容。

import sys
import math

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtPrintSupport import QPrinter
from PySide6.QtGui import QPen, QPainter
from PySide6.QtCore import QPointF

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法

        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.__ui.printer_button.clicked.connect(self.open_print_dialog)        # 3.点击按钮时打开打印对话框
        self.__ui.print_dialog.accepted.connect(self.print_dialog_accepted)     # 4.在打印对话框框中点击打印按钮时发送信号


    def open_print_dialog(self):
        self.__ui.print_dialog.exec()                                           # 1.以模态方式显示打印对话框
  
    def print_dialog_accepted(self, printer:QPrinter):
        if printer.isValid():                                                   # 1.判断打印机是否有效
            painter = QPainter()                                                # 2.创建绘图设
            if painter.begin(printer):                                          # 3.开始绘图,绘图设备为打印机纸张
                pen = QPen()                                                    # 4.创建钢笔对象
                pen.setWidth(5)                                                 # 5.设置钢笔宽度为5
                painter.setPen(pen)                                             # 6.设置绘图设备的钢笔

                x = printer.paperRect(QPrinter.Unit.DevicePixel).width() / 2
                y = printer.paperRect(QPrinter.Unit.DevicePixel).height() / 2

                r = min(printer.pageRect(QPrinter.Unit.DevicePixel).width() / 2, 
                        printer.pageRect(QPrinter.Unit.DevicePixel).height() / 2)

                p1 = QPointF(r * math.cos(-90 * math.pi / 180) + x , r * math.sin(-90 * math.pi / 180) + y)
                p2 = QPointF(r * math.cos(-18 * math.pi / 180) + x , r * math.sin(-18 * math.pi / 180) + y)
                p3 = QPointF(r * math.cos(54 * math.pi / 180) + x , r * math.sin(54 * math.pi / 180) + y)
                p4 = QPointF(r * math.cos(126 * math.pi / 180) + x , r * math.sin(126 * math.pi / 180) + y)
                p5 = QPointF(r * math.cos(198 * math.pi / 180) + x , r * math.sin(198 * math.pi / 180) + y)

                painter.drawPolyline([p1, p3, p5, p2, p4, p1])                  # 7.绘制多边形
                painter.end()                                                   # 8.结束绘画

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

六、打印预览对话框

  打印预览对话框 QPrintPreviewDialog 实际上包含一个打印预览控件 QPrintPreviewWidget,用户可以将打印预览控件 QPrintPreviewWidget 嵌入到自己的应用程序中,从而不使用打印预览对话框进行打印预览,而是在自定义的界面中进行打印预览。

  用 QPrintPreviewWidget 进行打印预览的过程与用打印预览对话框 QPrintPreviewDialog 进行预览的过程相同。首先要创建 QPrintPreviewWidget 的应用实例,可以将其放入其他控件中,然后将 QPrintPreviewWidget 的信号 paintRequested(printer:QPrinter) 与槽函数连接,最后在对应的槽函数中编写要打印的内容。

  QPrintPreviewWidge 继承自 QWidget,用 QPrintPreviewWidge 创建打印预览控件的方法如下所示:

QPrintPreviewWidget(parent:QWidget=None, flags:Qt.WindowFlags)
QPrintPreviewWidget(printer:QPrinter, parent:QWidget=None, flags:Qt.WindowFlags= Default(Qt.WindowFlags))

  如果没有指定 printer 参数,则使用系统默认的打印机。

  打印预览对话框 QPrintPreviewDialog 的显示方法仍是 exec()setVisible(visible:bool)show() 方法,在显示对话框之前会发送 paintRequested(printer:QPrinter) 信号,需要在 paintRequested(printer:QPrinter) 对应的槽函数中编写要预览的内容,把内容输入到参数 printer 上。要获取打印对话框中关联的打印机,可以使用 QPrintPreviewDialogprinter() 方法。

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import  QTextEdit, QMenuBar
from PySide6.QtWidgets import  QVBoxLayout

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小

        layout = QVBoxLayout(window)                                            # 2.创建一个垂直布局

        menuBar = QMenuBar()                                                    # 3.创建一个菜单栏工具,然后添加到布局中
        layout.addWidget(menuBar)

        self.file_menu = menuBar.addMenu("文件(&F)")                            # 4.创建一个菜单,然后添加到菜单栏中

        # 5.往菜单中添加动作
        self.open_action = self.file_menu.addAction("打开(&O)")
        self.preview_action = self.file_menu.addAction("打印预览(&V)")
        self.print_action = self.file_menu.addAction("打印(&P)")

        self.file_menu.addSeparator()                                           # 6.添加分隔符

        self.exit_action = self.file_menu.addAction("退出(&Q)")

        self.textEdit = QTextEdit()                                             # 7.创建一个多行文本框控件,然后添加到布局中
        layout.addWidget(self.textEdit)

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtPrintSupport import QPrinter, QPrinterInfo
from PySide6.QtPrintSupport import QPrintPreviewDialog, QPrintDialog
from PySide6.QtGui import Qt

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法

        self.printer = QPrinter(QPrinterInfo.defaultPrinter())

        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.__ui.open_action.triggered.connect(self.open_action_triggered)     # 3.点击打开动作触发信号
        self.__ui.preview_action.triggered.connect(self.preview_action_triggered)   # 4.点击打印预览动作触发信号
        self.__ui.print_action.triggered.connect(self.print_action_triggered)   # 5.点击打印动作触发信号
        self.__ui.exit_action.triggered.connect(self.close)                     # 6.点击退出动作触发信号

    def open_action_triggered(self):
        font = self.__ui.textEdit.font()                                        # 1.获取多行文本框的字体
        font.setPointSize(30)                                                   # 2.设置字体的大小
        self.__ui.textEdit.setFont(font)                                        # 3.设置多行文本框的字体
        for _ in range(10):
            self.__ui.textEdit.append("一定会有办法的!绝对没问题的!")            # 4.多行文本框中添加文本

    def preview_action_triggered(self):
        # 1.创建打印预览对话框
        preview_dialog = QPrintPreviewDialog(self.printer, self, flags=
                                      Qt.WindowType.WindowMinimizeButtonHint | 
                                      Qt.WindowType.WindowMaximizeButtonHint |
                                      Qt.WindowType.WindowCloseButtonHint)
  
        preview_dialog.paintRequested.connect(self.preview_paintRequested)      # 2.显示打印对话框之前发送信号
        preview_dialog.exec()                                                   # 3.以模态方式显示对话框
        self.printer = preview_dialog.printer()                                 # 4.取打印对话框中关联的打印机

    def preview_paintRequested(self, printer:QPrinter):
        self.__ui.textEdit.print_(printer)                                      # 1.打印当行文本框的文本

    def print_action_triggered(self):
        print_dialog = QPrintDialog(self.printer)                               # 1.创建打印对话框
        print_dialog.accepted.connect(self.print_dialog_accepted)               # 2.在打印对话框框中点击打印按钮时发送信号
        print_dialog.exec()                                                     # 3.以模态方式显示打印对话框
    
    def print_dialog_accepted(self, printer:QPrinter):
        self.__ui.textEdit.print_(printer)                                      # 1.打印当行文本框的文本

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

七、打印预览控件

  打印预览对话框 QPrintPreviewDialog 实际上包含一个打印预览控件 QPrintPreviewWidget,用户可以将打印预览控件 QPrintPreviewWidget 嵌入到自己的应用程序中,从而不使用打印预览对话框进行打印预览,而是在自定义的界面中进行打印预览。

  用 QPrintPreviewWidget 进行打印预览的过程与用打印预览对话框 QPrintPreviewDialog 进行预览的过程相同。首先要创建 QPrintPreviewWidget 的应用实例,可以将其放入其他控件中,然后将 QPrintPreviewWidget 的信号 paintRequested(printer:QPrinter) 与槽函数连接,最后在对应的槽函数中编写要打印的内容。

  QPrintPreviewWidge 继承自 QWidget,用 QPrintPreviewWidge 创建打印预览控件的方法如下所示:

QPrintPreviewWidget(parent:QWidget=None, flags:Qt.WindowFlags)
QPrintPreviewWidget(printer:QPrinter, parent:QWidget=None, flags:Qt.WindowFlags= Default(Qt.WindowFlags))

  如果没有指定 printer 参数,则使用系统默认的打印机。

  QPrintPreviewDialog 打印对话框的常用方法如下:

# 实例方法
pageCount() -> int                                                              # 获取页数
currentPage() -> int                                                            # 获取当前预览的页
zoomFactor() -> float                                                           # 获取缩放系数

# 槽函数
updatePreview() -> None                                                         # 更新预览,发送paintRequested(printer)信号

print_() -> None                                                                # 用关联的QPrinter进行打印

setCurrentPage(pageNumber:int) -> None                                          # 设置当前预览的页

setOrientation(orientation:QPageLayout.Orientation) -> None                     # 设置预览方向
setPortraitOrientation() -> None                                                # 设置预览为竖直方向
setLandscapeOrientation() -> None                                               # 设置预览为横向方向

setViewMode(viewMode:QprintPreviewWidget.ViewMode) -> None                      # 设置预览模式

setSinglePageViewMode() -> None                                                 # 设置预览为单页模式
setFacingPagesViewMode() -> None                                                # 设置预览为双页模式
setAllPagesViewMode() -> None                                                   # 以所有页全部显示模式预览

setZoomMode(zoomMode:QPrintPreviewWidget.ZoomMode) -> None                      # 设置缩放模式
setZoomFactor(zoomFactor:float) -> None                                         # 设置缩放系数
zoomIn(zoom:float=1.1) ->None                                                   # 缩小显示
zoomOut(zoom:float=1.1) -> None                                                 # 放大显示

fitToWidth() -> None                                                            # 以最大宽度方式显示当前页
fitInView() -> None                                                             # 以最大适合方式显示当前页

  打印预览控件 QPrintPreviewWidget 的信号有 paintRequested(printer:QPrinter)previewChanged()。当 显示打印预览控件或更新预览控件 时发送 paintRequested(printer:QPrinter) 信号,需要在参数 printer写入需要预览的内容。当 打印预览控件的内部状态发生改变 时,例如预览方向发生改变,就会发送 previewChanged() 信号。

paintRequested(printer:QPrinter)                                                # 当显示打印预览控件或更新预览控件时发送信号
previewChanged()                                                                # 当打印预览控件的内部状态发生改变时发送信号

  用 setViewMode(viewMode:QPrintPreviewWidget.ViewMode) 方法 设置预览模式,参数 viewMode 可取值如下:

QPrintPreviewWidget.ViewMode.SinglePageView                                     # 单页模式,值是0
QPrintPreviewWidget.ViewMode.FacingPagesView                                    # 左右两页模式,值是1
QPrintPreviewWidget.ViewMode.AllPagesView                                       # 所有页模式,值是2

  可以对预览进行缩放,用 setZoomMode(zoomMode:QPrintPreviewWidget.ZoomMode) 方法 设置缩放模式,参数 zoomMode 可取值如下:

QPrintPreviewWidget.ZoomMode.CustomZoom                                         # 自定义缩放模式,值是0
QPrintPreviewWidget.ZoomMode.FitToWidth                                         # 以最大宽度方式显示,值是1
QPrintPreviewWidget.ZoomMode.FitInView                                          # 以最大适合方式显示,值是2

八、PDF文档生成器

  PySide6 可以将 QPainter 绘制的图形、文字和图像等转换成 PDF 文档。转换成 PDF 文档的类是 QPdfWriter,它继承自 QObjectQPagedPaintDevice。用 QPdfWriter 创建实例对象的方法如下所示:

QPdfWriter(filename:str)
QPdfWriter(device:QIODevice)

  PDF 文档生成器 QPdfWriter 的常用方法如下:

# 实例方法
creator() -> str                                                                # 获取创建者
setCreator(creator:str) -> None                                                 # 设置创建者

resolution() -> int                                                             # 设置分辨率
setResolution(resolution:int) : None                                            # 设置分辨率

title() -> str                                                                  # 获取PDF文档标题
setTitle(title:str) -> None                                                     # 设置PDF文档标题

setPdfVersion(version:PdfVersion) -> None                                       # 设置PDF版本

# 继承父类的实例方法
pageRanges() -> QPageRanges                                                     # 获取页码范围

# 继承父类的虚拟方法
abstract newPage() -> bool                                                      # 生成新页

setPageLayout(pageLayout:QPageLayout) -> bool                                   # 设置页面布局
setPageMargins(margins:QMarginsF, units:Unit=QPageLayout.Millimeter) -> bool    # 设置页边距
setPageOrientation(orientation:Qt.Orientation) -> bool                          # 设置页面方向
setPageRanges(ranges:QPageRanges) -> bool                                       # 设置页码范围
setPageSize(pageSize:QPageSize) -> bool                                         # 设置页面大小

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel, QPushButton
from PySide6.QtWidgets import QLineEdit, QSpinBox, QComboBox
from PySide6.QtWidgets import QFormLayout
from PySide6.QtGui import Qt
from PySide6.QtPrintSupport import QPrinterInfo

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(400, 120)                                                 # 1.设置窗口对象大小

        layout = QFormLayout(window)                                            # 2.创建一个表单布局

        self.printer_name_comboBox = QComboBox()                                # 3.创建一个下拉组合框,并添加到布局中
        layout.addRow("选择打印机", self.printer_name_comboBox)

        printer_name = QPrinterInfo.availablePrinterNames()                     # 4.获取可用的打印机名称列表
        self.printer_name_comboBox.addItems(printer_name)                       # 5.将可用的打印机名称列表添加到下拉组合框中
        self.printer_name_comboBox.setCurrentText(QPrinterInfo.defaultPrinterName())    # 6.设置下拉组合框的当前选中项为默认打印机文本项

        self.copies_spinBox = QSpinBox(minimum=0, maximum=100)                  # 7.创建一个整数选择控件,并添加到布局中
        layout.addRow("设置打印份数", self.copies_spinBox)

        self.output_file_path_lineEdit = QLineEdit(text="output.pdf")           # 8.创建一个单行文本框控件,并添加到布局中
        layout.addRow("输出到文件", self.output_file_path_lineEdit)

        self.printer_button_printer = QPushButton("打印")                       # 9.创建一个按钮控件,并添加到布局中
        layout.addRow(self.printer_button_printer)

        self.info_label = QLabel()                                              # 10.添加一个提示信息标签,并添加到布局中
        layout.addRow(self.info_label)

        self.info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)              # 11.设置标签文本的对齐方式

  修改 widget.py 文件的内容。

import sys
import math

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPdfWriter, QPageSize, QPainter, QPen
from PySide6.QtCore import QPointF

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法

        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.__ui.printer_button_printer.clicked.connect(self.print_file)       # 3.点击打印按钮时发送信号


    def print_file(self):
        pdfWriter = QPdfWriter(self.__ui.output_file_path_lineEdit.text())      # 1.创建一个PDF生成器,并设置输出文件名
        pdfWriter.setPdfVersion(QPdfWriter.PdfVersion.PdfVersion_1_6)           # 2.设置PDF版本为1.6

        page_size = QPageSize(QPageSize.PageSizeId.A4)                          # 3.设置页面大小为A4
        pdfWriter.setPageSize(page_size)                                        # 4.设置PDF生成器的纸张尺寸

        painter = QPainter()                                                    # 5.创建打印机对象
  
        if painter.begin(pdfWriter):                                            # 6.开始绘画
            pen = QPen()                                                        # 7.创建钢笔对象
            pen.setWidth(5)                                                     # 8.设置画笔宽度为5
            painter.setPen(pen)                                                 # 9.设置打印机控件的钢笔对象

            size = page_size.size(QPageSize.Unit.Millimeter)
            x = size.width() * 20
            y = size.height() * 20
            r = min(x / 2, y / 2)
    
            p1 = QPointF(r * math.cos(-90 * math.pi / 180) + x , r * math.sin(-90 * math.pi / 180) + y)
            p2 = QPointF(r * math.cos(-18 * math.pi / 180) + x , r * math.sin(-18 * math.pi / 180) + y)
            p3 = QPointF(r * math.cos(54 * math.pi / 180) + x , r * math.sin(54 * math.pi / 180) + y)
            p4 = QPointF(r * math.cos(126 * math.pi / 180) + x , r * math.sin(126 * math.pi / 180) + y)
            p5 = QPointF(r * math.cos(198 * math.pi / 180) + x , r * math.sin(198 * math.pi / 180) + y)

            page_copies = self.__ui.copies_spinBox.value()                      # 10.获取打印纸张个数
            for i in range(1, page_copies + 1):
                painter.drawPolyline([p1, p3, p5, p2, p4, p1])                  # 11.绘制多边形
                self.__ui.info_label.setText(f"正在打印第{i}页,共{page_copies}页") # 12.设置提示标签的文本
                if i != page_copies:
                    pdfWriter.newPage()                                         # 13.如果不是最后一页,打印新的纸张
            painter.end()                                                       # 14.结束绘制

            self.__ui.info_label.setText(f"打印完成,一共{page_copies}页")

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
posted @ 2025-05-10 21:37  星光映梦  阅读(15)  评论(0)    收藏  举报