Python實(shí)現(xiàn)跨平臺(tái)表格數(shù)據(jù)分頁打印預(yù)覽處理詳解
我曾經(jīng)在前面使用WxPython開發(fā)跨平臺(tái)應(yīng)用程序的時(shí)候,寫了一篇《WxPython跨平臺(tái)開發(fā)框架之列表數(shù)據(jù)的通用打印處理》,介紹在WxPython下實(shí)現(xiàn)表格數(shù)據(jù)分頁打印處理的過程,在Windows下和MacOS測試效果表現(xiàn)一致。然后在WxPython跨平臺(tái)的基礎(chǔ)上,我利用類似WxPhon的程序框架,使用PySide6/PyQt6實(shí)現(xiàn)了另一套跨平臺(tái)的程序開發(fā),功能上更是比WxPython的實(shí)現(xiàn)更加細(xì)致和完善了,本篇隨筆介紹使用PySide6/PyQt6實(shí)現(xiàn)Python跨平臺(tái)表格數(shù)據(jù)分頁打印預(yù)覽處理。
1、回顧WxPython的列表數(shù)據(jù)的通用打印處理
WxPython實(shí)現(xiàn)數(shù)據(jù)的表格預(yù)覽和打印處理,主要是利用wx.PrintPreview
、wx.Printer
和 wx.Printout
等 wxPython 提供的用于打印功能的核心類來處理。
一般列表界面,如下所示。
我們打印模塊的處理,需要把這些列表的記錄顯示在打印預(yù)覽界面上,并決定是否繼續(xù)打印即可。
打印預(yù)覽入口,在列表界面上右鍵,彈出打印菜單,如下界面所示。
打印預(yù)覽界面如下所示。
其打印的邏輯,主要就是調(diào)用MyPrintOut的自定義對(duì)象,然后調(diào)用PrintPreview進(jìn)行打印預(yù)覽窗體的顯示即可。具體的邏輯還是在自定義的 MyPrintout 類里面。
2、使用PySide6/PyQt6實(shí)現(xiàn)Python跨平臺(tái)表格數(shù)據(jù)分頁打印處理
而使用PySide6/PyQt6實(shí)現(xiàn)Python跨平臺(tái)表格數(shù)據(jù)分頁打印預(yù)覽處理,邏輯上有所不同,這里沒有PrintOut對(duì)象來處理了。需要根據(jù)表格的TableModel對(duì)象來進(jìn)行數(shù)據(jù)的分頁打印。
在開始介紹實(shí)現(xiàn)邏輯前,我們先來看看PySide6/PyQt6實(shí)現(xiàn)打印預(yù)覽的效果。
同樣我們是在表格展示上給出通用的打印菜單入口,如上圖所示,作為答應(yīng)預(yù)覽的統(tǒng)一入口。
而由于數(shù)據(jù)打印的時(shí)候,表格列字段可能有些多有些少,因此最好能夠根據(jù)表格列選擇那些可以打印,那些忽略。而選擇后,可以進(jìn)一步選擇橫向或者豎向等信息,因此在彈出打印預(yù)覽前,我們讓用戶確認(rèn)一下答應(yīng)的信息,我訂做了一個(gè)打印預(yù)覽前的設(shè)置對(duì)話框,如下所示。
這樣我們可以定制打印的相關(guān)信息,也方便我們對(duì)打印的格式精細(xì)化控制。
對(duì)于模型數(shù)據(jù)很多,這需要考慮到分頁的處理,我們需要再實(shí)現(xiàn)打印預(yù)覽的時(shí)候,實(shí)現(xiàn)分頁顯示的邏輯,分頁打印預(yù)覽的界面如下所示。
了解了PySide/PyQt的打印預(yù)覽界面后,我們來分析下實(shí)現(xiàn)打印的邏輯處理。
打印預(yù)覽和打印的時(shí)候,我們需要考慮顯示器和實(shí)際打印設(shè)備之間的顯示尺寸是不同的,有時(shí)候顯示器設(shè)置顯示為200%或其他偏大的數(shù)據(jù),如果不注意尺寸的調(diào)整,很可能打印預(yù)覽得到的是一個(gè)很小區(qū)域的顯示內(nèi)容。
在 PySide6 /PyQt6 中,如果你想實(shí)現(xiàn) QTableView
打印功能并確保兼容不同操作系統(tǒng)(如 macOS 和 Windows)的尺寸變化,你可以使用 QPrinter
和 QPrintDialog
來處理打印。要確保尺寸適應(yīng)變化,你可以根據(jù)打印內(nèi)容自動(dòng)調(diào)整頁面布局。
我編寫了一個(gè)函數(shù),用于計(jì)算縮放比例,如下函數(shù)所示。
def calculateScale(self, printer: QPrinter, painter: QPainter) -> float: """計(jì)算每毫米的邏輯單位""" # 獲取打印機(jī)的 DPI ppiPrinterX = printer.resolution() ppiPrinterY = ppiPrinterX # 假設(shè) X 和 Y 方向的 DPI 相同 # 獲取屏幕的 DPI screen = QApplication.primaryScreen() ppiScreenX = screen.logicalDotsPerInchX() ppiScreenY = screen.logicalDotsPerInchY() # 計(jì)算縮放比例, self.logScale = logScale = float(ppiPrinterX) / float(ppiScreenX) # 可根據(jù) DPI 比例調(diào)整字體大小 print(f"縮放比例: {logScale}") # 獲取頁面大小和繪制區(qū)域大小 pageRect = printer.pageRect(QPrinter.Unit.DevicePixel) # 頁面大?。ㄏ袼兀? paintRect = painter.viewport() # 繪制區(qū)域大?。ㄏ袼兀? # 計(jì)算縮放比例 scale = logScale * float(paintRect.width()) / float(pageRect.width()) # 設(shè)置 QPainter 的縮放比例 painter.scale(scale, scale) # 計(jì)算每毫米的邏輯單位 logUnitsMM = float(ppiPrinterX) / (logScale * 25.4) print(f"每毫米的邏輯單位: {logUnitsMM}") return logUnitsMM
打印預(yù)覽的處理,主要就是根據(jù)設(shè)置對(duì)話框,獲得橫向還是縱向,以及頁面大小、標(biāo)題等信息,然后實(shí)現(xiàn)QPreviewDialog里面的paintRequest事件即可,如下預(yù)覽邏輯處理代碼。
def print_preview(self, setting: PrintSetting) -> None: """打印預(yù)覽""" # 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 # 打印標(biāo)題 self.settings = setting # 保存打印設(shè)置 preview_dialog = QPrintPreviewDialog(printer) <strong>preview_dialog.paintRequested.connect(self.print_preview_paint)</strong> preview_dialog.exec()
打印預(yù)覽的處理邏輯,主要就是需要根據(jù)縮放的尺寸獲得對(duì)應(yīng)的打印區(qū)域大小,并根據(jù)頁面的大小和實(shí)現(xiàn)打印的內(nèi)容顯示,計(jì)算好尺寸,也就是一般按每頁放置多少行,或者每行的高度來計(jì)算,如果需要分頁,則標(biāo)識(shí)一下即可。
def print_preview_paint(self, printer: QPrinter) -> None: """打印預(yù)覽繪制""" self.painter = painter = QPainter(printer) # 計(jì)算每毫米的邏輯單位 self.logUnitsMM = self.calculateScale(printer, painter) # 獲取頁面大小 # unit 參數(shù)的可選值有: # QPrinter.Unit.Point:點(diǎn)(1 點(diǎn) = 1/72 英寸) # QPrinter.Unit.Millimeter:毫米(常用) # QPrinter.Unit.Inch:英寸 # QPrinter.Unit.Pixel:像素 # 獲取頁面的可打印區(qū)域 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
如果內(nèi)容需要分頁才能展示完,那么你要使用printer.newPage()來告訴打印機(jī)進(jìn)行分頁。
# 分頁打印 print(f"總行數(shù): {total_rows}, 總頁數(shù): {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()
打印的時(shí)候,我們打印列頭和每列內(nèi)容,都是根據(jù)實(shí)際的列寬進(jìn)行一定比例的處理,讓它能夠兼容打印最佳效果。
打印表頭的時(shí)候,如下代碼。
index = 0 # 用來計(jì)算遞增的列數(shù) 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])), # 累計(jì)不同的列寬 y_offset, header_text, ) index += 1
打印表格每列的內(nèi)容,處理規(guī)則也是類似,如下代碼所示
# 繪制表格內(nèi)容 for row in range( page * rows_per_page, min((page + 1) * rows_per_page, self.total_rows) ): y_offset += self.row_height index = 0 # 用來計(jì)算遞增的列數(shù) for col in range(self.columnCount()): if print_cols and col not in print_cols: continue # 獲取單元格數(shù)據(jù) text = self.GetValue(row, col) # 繪制單元格內(nèi)容 self.painter.drawText( int(x_offset + sum(col_widths[:index])), # 累計(jì)不同的列寬 y_offset, text, ) index += 1
其他如標(biāo)題,橫線、頁碼等信息,根據(jù)顯示規(guī)則繪制即可。
以上就是Python實(shí)現(xiàn)跨平臺(tái)表格數(shù)據(jù)分頁打印預(yù)覽處理詳解的詳細(xì)內(nèi)容,更多關(guān)于Python表格數(shù)據(jù)分頁打印的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
pandas將DataFrame的幾列數(shù)據(jù)合并成為一列
本文主要介紹了pandas將DataFrame的幾列數(shù)據(jù)合并成為一列,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02pytorch 計(jì)算ConvTranspose1d輸出特征大小方式
這篇文章主要介紹了pytorch 計(jì)算ConvTranspose1d輸出特征大小方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06使用python創(chuàng)建股票的時(shí)間序列可視化分析
這篇文章主要為大家詳細(xì)介紹了python創(chuàng)建股票的時(shí)間序列可視化分析,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03Python的Flask框架中使用Flask-Migrate擴(kuò)展遷移數(shù)據(jù)庫的教程
Flask-Migrate可以幫助Flask應(yīng)用程序通過預(yù)設(shè)的Python腳本完成數(shù)據(jù)庫遷移操作,這里我們就來看一下Python的Flask框架中使用Flask-Migrate擴(kuò)展遷移數(shù)據(jù)庫的教程,需要的朋友可以參考下2016-06-06