我曾经在前面使用WxPython开发跨平台应用程序的时候,写了一篇《WxPython跨平台开发框架之列表数据的通用打印处理》,介绍在WxPython下实现表格数据分页打印处理的过程,在Windows下和MacOS测试效果表现一致。然后在WxPython跨平台的基础上,我利用类似WxPhon的程序框架,使用PySide6/PyQt6实现了另一套跨平台的程序开发,功能上更是比WxPython的实现更加细致和完善了,本篇随笔介绍使用PySide6/PyQt6实现Python跨平台表格数据分页打印预览处理。

1、回顾WxPython的列表数据的通用打印处理

WxPython实现数据的表格预览和打印处理,主要是利用wx.PrintPreviewwx.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)的尺寸变化,你可以使用 QPrinterQPrintDialog 来处理打印。要确保尺寸适应变化,你可以根据打印内容自动调整页面布局。

我编写了一个函数,用于计算缩放比例,如下函数所示。

    def calculateScale(self, printer: QPrinter, painter: QPainter) -> float:
"""计算每毫米的逻辑单位""" # 获取打印机的 DPI
ppiPrinterX = printer.resolution()
ppiPrinterY = ppiPrinterX # 假设 X 和 Y 方向的 DPI 相同 # 获取屏幕的 DPI
screen = QApplication.primaryScreen()
ppiScreenX = screen.logicalDotsPerInchX()
ppiScreenY = screen.logicalDotsPerInchY() # 计算缩放比例,
self.logScale = logScale = float(ppiPrinterX) / float(ppiScreenX) # 可根据 DPI 比例调整字体大小
print(f"缩放比例: {logScale}") # 获取页面大小和绘制区域大小
pageRect = printer.pageRect(QPrinter.Unit.DevicePixel) # 页面大小(像素)
paintRect = painter.viewport() # 绘制区域大小(像素) # 计算缩放比例
scale = logScale * float(paintRect.width()) / float(pageRect.width()) # 设置 QPainter 的缩放比例
painter.scale(scale, scale) # 计算每毫米的逻辑单位
logUnitsMM = float(ppiPrinterX) / (logScale * 25.4)
print(f"每毫米的逻辑单位: {logUnitsMM}")
return logUnitsMM

打印预览的处理,主要就是根据设置对话框,获得横向还是纵向,以及页面大小、标题等信息,然后实现QPreviewDialog里面的paintRequest事件即可,如下预览逻辑处理代码。

    def print_preview(self, setting: PrintSetting) -> None:
"""打印预览""" # print(setting.__dict__)
printer = QPrinter() # QPrinter.PrinterMode.HighResolution # 打印的处理
printer.setPageSize(setting.page_size)
printer.setPageOrientation(setting.page_orientation)
self.print_cols = setting.print_cols # 打印指定列的索引列表
self.print_title = setting.print_title # 打印标题
self.settings = setting # 保存打印设置 preview_dialog = QPrintPreviewDialog(printer)
preview_dialog.paintRequested.connect(self.print_preview_paint)
preview_dialog.exec()

打印预览的处理逻辑,主要就是需要根据缩放的尺寸获得对应的打印区域大小,并根据页面的大小和实现打印的内容显示,计算好尺寸,也就是一般按每页放置多少行,或者每行的高度来计算,如果需要分页,则标识一下即可。

    def print_preview_paint(self, printer: QPrinter) -> None:
"""打印预览绘制"""
self.painter = painter = QPainter(printer) # 计算每毫米的逻辑单位
self.logUnitsMM = self.calculateScale(printer, painter) # 获取页面大小
# unit 参数的可选值有:
# QPrinter.Unit.Point:点(1 点 = 1/72 英寸)
# QPrinter.Unit.Millimeter:毫米(常用)
# QPrinter.Unit.Inch:英寸
# QPrinter.Unit.Pixel:像素 # 获取页面的可打印区域
page_rect = printer.pageRect(QPrinter.Unit.Millimeter)
self.page_height = page_height = page_rect.height() * self.logUnitsMM
self.page_width = page_width = page_rect.width() * self.logUnitsMM

如果内容需要分页才能展示完,那么你要使用printer.newPage()来告诉打印机进行分页。

        # 分页打印
print(f"总行数: {total_rows}, 总页数: {total_pages}")
for page in range(total_pages):
if page > 0: # 非第一页,需要换页
printer.newPage()
self.print_page(page, rows_per_page, self.print_cols) self.painter.end()

打印的时候,我们打印列头和每列内容,都是根据实际的列宽进行一定比例的处理,让它能够兼容打印最佳效果。

打印表头的时候,如下代码。

        index = 0  # 用来计算递增的列数
for col in range(self.columnCount()):
if print_cols and col not in print_cols:
continue
header_text = self.GetColLabelValue(col)
self.painter.drawText(
int(x_offset + sum(col_widths[:index])), # 累计不同的列宽
y_offset,
header_text,
)
index += 1

打印表格每列的内容,处理规则也是类似,如下代码所示

       # 绘制表格内容
for row in range(
page * rows_per_page, min((page + 1) * rows_per_page, self.total_rows)
):
y_offset += self.row_height
index = 0 # 用来计算递增的列数
for col in range(self.columnCount()):
if print_cols and col not in print_cols:
continue
# 获取单元格数据
text = self.GetValue(row, col)
# 绘制单元格内容
self.painter.drawText(
int(x_offset + sum(col_widths[:index])), # 累计不同的列宽
y_offset,
text,
)
index += 1

其他如标题,横线、页码等信息,根据显示规则绘制即可。

使用PySide6/PyQt6实现Python跨平台表格数据分页打印预览处理的更多相关文章

  1. C# 使用PrintDocument 绘制表格 完成 打印预览

    C# 使用PrintDocument 绘制表格 完成 打印预览 DataTable   经过不断的Google与baidu,最终整理出来的打印类 主要是根据两个参考的类组合而成,稍微修改了一下,参考代 ...

  2. C# 使用PrintDocument 绘制表格 完成 打印预览 DataTable

    经过不断的Google与baidu,最终整理出来的打印类 主要是根据两个参考的类组合而成,稍微修改了一下,参考代码及来源见最后(其中一份是VB语言的) 其中遇到的一些问题也已经得到了解决(分页,打印预 ...

  3. layui 表格中实现照片预览,点击查看原图

    人员表格中实现照片预览,并且可点击放大.查看原图 <table id="dutyInfoTable" class="layui-hide">< ...

  4. selenium+python对表格数据的操作

    一.直接获取整个表格数据,包含表头 def table_info(self): tr_data=[] table_data=[] css='id=>useradmin'#根据表格id找到表格 s ...

  5. python 图片在线转字符画预览

    文章链接:https://mp.weixin.qq.com/s/yiFOmljhyalE8ssAgwo6Jw 关于python图片转字符画,相信大家都不陌生,经常出现在 n个超有趣的python项目中 ...

  6. python 之头像上传,预览

    上传头像 我们需要实现的效果是:当我们点击默认头像,用户可以进行选择要上传的头像文件,其原理就是头像的img标签与文件input(file类型)框重合或者关联,可以通过如下两种方式进行实现: 方法一l ...

  7. Antd 表格数据分页展示

    分页组件代码 render(){ const {total,size,currenPage} = this.state // 参数分别为数据总条数.每页数据条数.当前页页码 return ( // 渲 ...

  8. 【第二篇】.NET用NPOI读取Excel表格并在页面预览

    博主用的是npoi2.0.1,支持.xls也支持.xlsx 直接上代码吧. <table class="table table-bordered table-striped" ...

  9. Web打印控件Lodop实现表格物流单的打印

    Web打印控件Lodop实现表格物流单的打印 一.lodop打印预览效果图 LODOP.PRINT_SETUP();打印维护效果图 LODOP.PREVIEW();打印预览图 二.写在前面 最近项目用 ...

  10. c# listview数据预览(转载的放在这里备用)

    public class PrintListView : ListView { /// <summary> /// 指示是否进行打印预览,默认值为 true /// </summar ...

随机推荐

  1. kafka各个版本的特性

    1. kafka-0.8.2 新特性 1.1 异步发送 producer不再区分同步(sync)和异步方式(async),所有的请求以异步方式发送,这样提升了客户端效率.producer请求会返回一个 ...

  2. Spring Cloud Sleuth in a Monolith Application

    1. Overview   In this article, we're introducing Spring Cloud Sleuth – a powerful tool for enhancing ...

  3. Qt/C++编写跨平台的推流工具(支持win/linux/mac/嵌入式linux/安卓等)

    一.前言 跨平台的推流工具当属OBS最牛逼,功能也是最强大的,唯一的遗憾就是多路推流需要用到插件,而且CPU占用比较高,默认OBS的规则是将对应画布中的视频画面和设定的音频一起重新编码再推流,意味着肯 ...

  4. Qt音视频开发07-合并音视频文件

    一.前言 之前已经把音视频分开存储了对应的文件,因为这个需求特别少,当然确实有部分用户是需要把音视频分开存储,但是毕竟是很少数,绝大部分的用户都是音视频合并到一个MP4文件,所以如果要合并到一个文件, ...

  5. FFmpeg命令行选项

    如下内容取自官网文档"Documentation-ffmpeg"和"Documentation-ffmpeg-all" 1 帮助信息 如下选项适用于 ff 系列 ...

  6. 即时通讯技术文集(第29期):IM开发技术合集(Part2) [共18篇]

    为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第29 期. [- 1 -] 谈谈移动端 IM 开发中登录请求的优化 [链接] http://w ...

  7. JMeter 线程组全家桶教程

    宝子们,今天咱就来唠唠 JMeter 里那些超重要的线程相关的玩意儿,学会了它们,你就能在性能测试的世界里 "横冲直撞" 啦! 一.线程组 -- 性能测试的主力军 想象一下,你开了 ...

  8. GIS开发的基础优化策略

    GIS开发的基础优化策略 1. GIS开发 空间字段要建对,类型明确,坐标系明确. 空间索引要建立,提高查询效率. 使用空间字段要谨慎,不用的地方不要查. 地图显示尽量用切片,用WMTS. WMS能用 ...

  9. 修复展锐SL8541E 偶现开机无法启动OTG

    哎,又是紫光展锐,真的拉啊!!! 问题是这样的,当USB口插上OTG线再开机,会偶现无法启动OTG.这个问题排查了好久,现在终于改好了,下面记录一下分析过程. 异常log[上]和正常log[下] 前面 ...

  10. IIS上开启反向代理实现Vue项目接口跨域处理

    通常情况下的Vue应用都使用Nginx部署,Nginx有专门的反向代理设置,但若将Vue应用部署在IIS中,针对Vue应用中设置的接口跨域,IIS需要进行反向代理设置. 跨域的设置分为开发环境和生产环 ...