使用PySide6/PyQt6实现Python跨平台表格数据分页打印预览处理 ...

海哥  金牌会员 | 2025-3-11 21:02:14 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 956|帖子 956|积分 2868

我曾经在前面使用WxPython开发跨平台应用步伐的时候,写了一篇《WxPython跨平台开发框架之列表数据的通用打印处理》,介绍在WxPython下实现表格数据分页打印处理的过程,在Windows下和MacOS测试结果表现同等。然后在WxPython跨平台的底子上,我利用类似WxPhon的步伐框架,使用PySide6/PyQt6实现了另一套跨平台的步伐开发,功能上更是比WxPython的实现更加过细和美满了,本篇随笔介绍使用PySide6/PyQt6实现Python跨平台表格数据分页打印预览处理。
1、回首WxPython的列表数据的通用打印处理

WxPython实现数据的表格预览和打印处理,重要是利用wx.PrintPreview、wx.Printer 和 wx.Printout 等 wxPython 提供的用于打印功能的核心类来处理。
一样平常列表界面,如下所示。

我们打印模块的处理,必要把这些列表的记录显示在打印预览界面上,并决定是否继续打印即可。
打印预览入口,在列表界面上右键,弹出打印菜单,如下界面所示。

打印预览界面如下所示。

 其打印的逻辑,重要就是调用MyPrintOut的自界说对象,然后调用PrintPreview进行打印预览窗体的显示即可。详细的逻辑还是在自界说的 MyPrintout 类内里。 2、使用PySide6/PyQt6实现Python跨平台表格数据分页打印处理

而使用PySide6/PyQt6实现Python跨平台表格数据分页打印预览处理,逻辑上有所不同,这里没有PrintOut对象来处理了。必要根据表格的TableModel对象来进行数据的分页打印。
在开始介绍实现逻辑前,我们先来看看PySide6/PyQt6实现打印预览的结果。

同样我们是在表格展示上给出通用的打印菜单入口,如上图所示,作为答应预览的统一入口。
而由于数据打印的时候,表格列字段大概有些多有些少,因此最好可以或许根据表格列选择那些可以打印,那些忽略。而选择后,可以进一步选择横向或者竖向等信息,因此在弹出打印预览前,我们让用户确认一下答应的信息,我订做了一个打印预览前的设置对话框,如下所示。

如许我们可以定制打印的相干信息,也方便我们对打印的格式精细化控制。

对于模型数据很多,这必要考虑到分页的处理,我们必要再实现打印预览的时候,实现分页显示的逻辑,分页打印预览的界面如下所示。

了解了PySide/PyQt的打印预览界面后,我们来分析下实现打印的逻辑处理。
打印预览和打印的时候,我们必要考虑显示器和现实打印设备之间的显示尺寸是不同的,有时候显示器设置显示为200%或其他偏大的数据,如果不注意尺寸的调解,很大概打印预览得到的是一个很小区域的显示内容。
在 PySide6 /PyQt6 中,如果你想实现 QTableView 打印功能并确保兼容不同操纵系统(如 macOS 和 Windows)的尺寸变革,你可以使用 QPrinter 和 QPrintDialog 来处理打印。要确保尺寸顺应变革,你可以根据打印内容主动调解页面结构。
我编写了一个函数,用于盘算缩放比例,如下函数所示。
  1.     def calculateScale(self, printer: QPrinter, painter: QPainter) -> float:
  2.         """计算每毫米的逻辑单位"""
  3.         # 获取打印机的 DPI
  4.         ppiPrinterX = printer.resolution()
  5.         ppiPrinterY = ppiPrinterX  # 假设 X 和 Y 方向的 DPI 相同
  6.         # 获取屏幕的 DPI
  7.         screen = QApplication.primaryScreen()
  8.         ppiScreenX = screen.logicalDotsPerInchX()
  9.         ppiScreenY = screen.logicalDotsPerInchY()
  10.         # 计算缩放比例,
  11.         self.logScale = logScale = float(ppiPrinterX) / float(ppiScreenX)
  12.         # 可根据 DPI 比例调整字体大小
  13.         print(f"缩放比例: {logScale}")
  14.         # 获取页面大小和绘制区域大小
  15.         pageRect = printer.pageRect(QPrinter.Unit.DevicePixel)  # 页面大小(像素)
  16.         paintRect = painter.viewport()  # 绘制区域大小(像素)
  17.         # 计算缩放比例
  18.         scale = logScale * float(paintRect.width()) / float(pageRect.width())
  19.         # 设置 QPainter 的缩放比例
  20.         painter.scale(scale, scale)
  21.         # 计算每毫米的逻辑单位
  22.         logUnitsMM = float(ppiPrinterX) / (logScale * 25.4)
  23.         print(f"每毫米的逻辑单位: {logUnitsMM}")
  24.         return logUnitsMM
复制代码
打印预览的处理,重要就是根据设置对话框,获得横向还是纵向,以及页面大小、标题等信息,然后实现QPreviewDialog内里的paintRequest变乱即可,如下预览逻辑处理代码。
  1.     def print_preview(self, setting: PrintSetting) -> None:
  2.         """打印预览"""
  3.         # print(setting.__dict__)
  4.         printer = QPrinter()  # QPrinter.PrinterMode.HighResolution
  5.         # 打印的处理
  6.         printer.setPageSize(setting.page_size)
  7.         printer.setPageOrientation(setting.page_orientation)
  8.         self.print_cols = setting.print_cols  # 打印指定列的索引列表
  9.         self.print_title = setting.print_title  # 打印标题
  10.         self.settings = setting  # 保存打印设置
  11.         preview_dialog = QPrintPreviewDialog(printer)
  12.         <strong>preview_dialog.paintRequested.connect(self.print_preview_paint)</strong>
  13.         preview_dialog.exec()
复制代码
打印预览的处理逻辑,重要就是必要根据缩放的尺寸获得对应的打印区域大小,并根据页面的大小和实现打印的内容显示,盘算好尺寸,也就是一样平常按每页放置多少行,或者每行的高度来盘算,如果必要分页,则标识一下即可。
  1.     def print_preview_paint(self, printer: QPrinter) -> None:
  2.         """打印预览绘制"""
  3.         self.painter = painter = QPainter(printer)
  4.         # 计算每毫米的逻辑单位
  5.         self.logUnitsMM = self.calculateScale(printer, painter)
  6.         # 获取页面大小
  7.         # unit 参数的可选值有:
  8.         # QPrinter.Unit.Point:点(1 点 = 1/72 英寸)
  9.         # QPrinter.Unit.Millimeter:毫米(常用)
  10.         # QPrinter.Unit.Inch:英寸
  11.         # QPrinter.Unit.Pixel:像素
  12.         # 获取页面的可打印区域
  13.         page_rect = printer.pageRect(QPrinter.Unit.Millimeter)
  14.         self.page_height = page_height = page_rect.height() * self.logUnitsMM
  15.         self.page_width = page_width = page_rect.width() * self.logUnitsMM
复制代码
如果内容必要分页才能展示完,那么你要使用printer.newPage()来告诉打印机进行分页。
  1.         # 分页打印
  2.         print(f"总行数: {total_rows}, 总页数: {total_pages}")
  3.         for page in range(total_pages):
  4.             if page > 0:  # 非第一页,需要换页
  5.                 printer.newPage()
  6.             self.print_page(page, rows_per_page, self.print_cols)
  7.         self.painter.end()
复制代码
打印的时候,我们打印列头和每列内容,都是根据现实的列宽进行一定比例的处理,让它可以或许兼容打印最佳结果。
打印表头的时候,如下代码。
  1.         index = 0  # 用来计算递增的列数
  2.         for col in range(self.columnCount()):
  3.             if print_cols and col not in print_cols:
  4.                 continue
  5.             header_text = self.GetColLabelValue(col)
  6.             self.painter.drawText(
  7.                 int(x_offset + sum(col_widths[:index])),  # 累计不同的列宽
  8.                 y_offset,
  9.                 header_text,
  10.             )
  11.             index += 1
复制代码
打印表格每列的内容,处理规则也是类似,如下代码所示
  1.        # 绘制表格内容
  2.         for row in range(
  3.             page * rows_per_page, min((page + 1) * rows_per_page, self.total_rows)
  4.         ):
  5.             y_offset += self.row_height
  6.             index = 0  # 用来计算递增的列数
  7.             for col in range(self.columnCount()):
  8.                 if print_cols and col not in print_cols:
  9.                     continue
  10.                 # 获取单元格数据
  11.                 text = self.GetValue(row, col)
  12.                 # 绘制单元格内容
  13.                 self.painter.drawText(
  14.                     int(x_offset + sum(col_widths[:index])),  # 累计不同的列宽
  15.                     y_offset,
  16.                     text,
  17.                 )
  18.                 index += 1
复制代码
其他如标题,横线、页码等信息,根据显示规则绘制即可。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表