在《PyQt5中使用QWebChannel和内嵌网页进行js交互》一文中,我记录了如何使用QWebchannel与内嵌网页进行js交互,其根本目标在于使用Qt5调起打印机服务。在这篇文章中我将介绍一下具体使用Qprinter打印超市热敏小票的过程。

PyQt5中使用Qprinter打印热敏小票

参考内容:

Qt5官方文档

《pyqt5的 QPrinter 使用模板》 by 一心狮

本文包含以下内容:

1.使用html进行热敏打印的方法

2.分析存在的问题

3.提出另一种打印方法来解决问题

使用html进行热敏打印

python端代码

# -*- coding:utf-8 -*-

# webprint.py

from PyQt5.QtWidgets import QApplication

from PyQt5.QtCore import QObject, pyqtSlot, QUrl, QSizeF

from PyQt5.QtWebChannel import QWebChannel

from PyQt5.QtWebEngineWidgets import QWebEngineView

from PyQt5.QtPrintSupport import QPrinter, QPrinterInfo

from PyQt5.QtGui import QTextDocument

import sys

class Printer:

def __init__(self):

self.p = QPrinterInfo.defaultPrinter() # 获取默认打印机

self.print_device = QPrinter(self.p) # 指定打印所使用的装置

def print(self, content):

# 设置打印内容的宽度,否则打印内容会变形

self.print_device.setPageSizeMM(QSizeF(110, 250))

d = QTextDocument() # 使用QTextDcument对html进行解析

d.setDocumentMargin(0) # 将打印的边距设为0

# 设置全局生效的默认样式

d.setDefaultStyleSheet('''

* {padding:0;margin: 0;}

h1 {font-size: 20px;}

h3 {font-size: 16px;}

.left {float: left;}

.right {float:right;}

.clearfix {clear: both;}

ul {list-style: none;}

.print_container {width: 250px;}

.section2 label {display: block;}

.section3 label {display: block;}

.section4 .total label {display: block;}

.section4 {border-bottom: 1px solid #DADADA;}

.section5 label {display: block;}

''')

d.setHtml(content) # 注入html内容

d.print(self.print_device) # 调用打印机进行打印

class Print(QObject):

def __init__(self):

super().__init__()

self.printer = Printer()

@pyqtSlot(str, result=str)

def print(self, content):

self.printer.print(content)

return

if __name__ == '__main__':

app = QApplication(sys.argv)

browser = QWebEngineView()

browser.setWindowTitle('使用PyQt5打印热敏小票')

browser.resize(900, 600)

channel = QWebChannel()

printer = Print()

channel.registerObject('printer', printer)

browser.page().setWebChannel(channel)

url_string = "file:///python/print/webprint.html" # 内置的网页地址

browser.load(QUrl(url_string))

browser.show()

sys.exit(app.exec_())

网页端代码

使用PyQt5打印热敏小票

* {padding:0;margin: 0;}

h1 {font-size: 20px;}

h3 {font-size: 16px;}

.left {float: left;}

.right {float:right;}

.clearfix {clear: both;}

ul {list-style: none;}

.print_container {width: 250px;}

.section2 label {display: block;}

.section3 label {display: block;}

.section4 .total label {display: block;}

.section4 {border-bottom: 1px solid #DADADA;}

.section5 label {display: block;}

便利店

***************************************

订单号:700001001201811161631123558

下单时间:2018-10-16 16:31:14

收银员:王小明

***************************************

品名数量金额

今麦郎1100.00

合 计

100.00

收款金额

100

找零金额

0.00

顾客已付款

***************************************

电话:

***************************************

欢迎光临,谢谢惠顾!

便利店

进行html打印

window.onload = function() {

new QWebChannel(qt.webChannelTransport, function (channel) {

window.printer = channel.objects.printer;

});

}

function do_print() {

if (printer !== null) {

var html = document.querySelector('#capture').innerHTML;

printer.print(html);

}

}

关于使用qwebchannel进行js交互的内容这里不再赘述,请查阅本文开头提到的文章。

问题分析

运行上述代码,我们可以成功地调起打印机服务。但是打印出来的内容却惨不忍睹,热敏小票的左边和顶部空出一大片空白,以至于打印出来的票据内容丢失了大半!

惨不忍睹的html打印

为什么会这样呢?在代码中我们已经对QTextDocument进行了setDocumentMargin设置,打印时却依然有巨大的边距。

一开始我以为是margin设置无效,后来查看了pyqt5的源码以及在Google上搜索,才得知QTextDocument强制左边和顶部留白。事实上默认的margin已经是0了。这样一来使用QTextDocument进行打印的计划宣告破产,我不得不苦苦思索,在互联网上胡搜一通,看看是否有人遇到相同的问题。

值得一提的是,热心的(:p)简书网友一心狮,他向我提供了一种思路:

先在项目内,放置一个已经排版好的excel文件。然后用win32com,对这个 execl文件,进行操作,如赋值,如打印

这确实是一个不错的方法,遗憾的是对我来说不太适用。超市热敏小票的内容不是固定长度的,而且我打算用pyinstaller将所有代码封装成一个独立的可执行程序(exe),放置一个excel文件也不太方便。

后来在Stackoverflow我偶然的看见了一个同样的问题,具体链接我忘了保存。下面只有一个回答,答者粗略地提到一个解决方法——Qt5打印图片不会留边距,可以从这个角度着手,把要打印的内容转为图片再打印。这条曲线救国的思路真是太棒了!

使用图片进行热敏打印

想要使用图片打印,首先就要把文字内容转成图片才行。幸好这世上已经有人提供了简单方便的html转图片方案,而且是在网页端进行的!这个方案就是使用起来方便简单的html2canvas:

The script allows you to take "screenshots" of webpages or parts of it, directly on the users browser. The screenshot is based on the DOM and as such may not be 100% accurate to the real representation as it does not make an actual screenshot, but builds the screenshot based on the information available on the page.

简而言之就是支持对html页面的部分进行“截屏”操作。

使用方法极其简单:

html2canvas(document.querySelector("#capture")).then(canvas => {

document.body.appendChild(canvas)

});

转好了图片,我们只需在python端对图片数据流使用QPainter连接打印机进行打印即可。

python端代码

# -*- coding:utf-8 -*-

from PyQt5.QtWidgets import QApplication

from PyQt5.QtCore import QObject, pyqtSlot, QUrl

from PyQt5.QtWebChannel import QWebChannel

from PyQt5.QtWebEngineWidgets import QWebEngineView

from PyQt5.QtPrintSupport import QPrinter, QPrinterInfo

from PyQt5.QtGui import QPainter, QImage

import sys, base64

class Printer:

def __init__(self):

self.p = QPrinterInfo.defaultPrinter()

self.print_device = QPrinter(self.p)

def print_(self, data_url):

image_content = base64.b64decode(data_url) # 数据流base64解码

image = QImage()

image.loadFromData(image_content) # 使用QImage构造图片

painter = QPainter(self.print_device) # 使用打印机作为绘制设备

painter.drawImage(0, 0, image) # 进行绘制(即调起打印服务)

painter.end() # 打印结束

class Print(QObject):

def __init__(self):

super().__init__()

self.printer = Printer()

@pyqtSlot(str, result=str)

def print_(self, data_url):

# 去除头部标识

self.printer.print_(data_url.replace('data:image/png;base64,', ''))

return

if __name__ == '__main__':

app = QApplication(sys.argv)

browser = QWebEngineView()

browser.setWindowTitle('使用PyQt5打印热敏小票')

browser.resize(900, 600)

channel = QWebChannel()

printer = Print()

channel.registerObject('printer', printer)

browser.page().setWebChannel(channel)

url_string = "file:///python/print/webprint.html" # 内置的网页地址

browser.load(QUrl(url_string))

browser.show()

sys.exit(app.exec_())

网页端代码

使用PyQt5打印热敏小票

* {padding:0;margin: 0;}

h1 {font-size: 20px;}

h3 {font-size: 16px;}

.left {float: left;}

.right {float:right;}

.clearfix {clear: both;}

ul {list-style: none;}

.print_container {width: 250px;}

.section2 label {display: block;}

.section3 label {display: block;}

.section4 .total label {display: block;}

.section4 {border-bottom: 1px solid #DADADA;}

.section5 label {display: block;}

便利店

***************************************

订单号:700001001201811161631123558

下单时间:2018-10-16 16:31:14

收银员:王小明

***************************************

品名数量金额

今麦郎1100.00

合 计

100.00

收款金额

100

找零金额

0.00

顾客已付款

***************************************

电话:

***************************************

欢迎光临,谢谢惠顾!

便利店

进行图像打印

window.onload = function() {

new QWebChannel(qt.webChannelTransport, function (channel) {

window.printer = channel.objects.printer;

});

}

function do_print_() {

if (printer !== null) {

html2canvas(document.querySelector("#capture")).then(canvas => {

var data_url = canvas.toDataURL();

printer.print_(data_url);

});

}

}

运行代码,我们欣喜地发现,热敏小票的排版终于正常了!

令人欣喜的图片打印

事实上,无论是图片打印,或者excel打印,都是同样的曲线救国思路。在得知第一种方法的情况下,我却没能想到第二种方法,看来我的联想能力还有待锻炼。

以上,就是我的解决历程。

附:完整代码(包含两种打印方式)

python端代码

# -*- coding:utf-8 -*-

from PyQt5.QtWidgets import QApplication

from PyQt5.QtCore import QObject, pyqtSlot, QUrl, QSizeF

from PyQt5.QtWebChannel import QWebChannel

from PyQt5.QtWebEngineWidgets import QWebEngineView

from PyQt5.QtPrintSupport import QPrinter, QPrinterInfo

from PyQt5.QtGui import QTextDocument, QPainter, QImage

import sys, base64

class Printer:

def __init__(self):

self.p = QPrinterInfo.defaultPrinter()

self.print_device = QPrinter(self.p)

def print(self, content):

self.print_device.setPageSizeMM(QSizeF(110, 250))

d = QTextDocument()

d.setDocumentMargin(0)

d.setDefaultStyleSheet('''

* {padding:0;margin: 0;}

h1 {font-size: 20px;}

h3 {font-size: 16px;}

.left {float: left;}

.right {float:right;}

.clearfix {clear: both;}

ul {list-style: none;}

.print_container {width: 250px;}

.section2 label {display: block;}

.section3 label {display: block;}

.section4 .total label {display: block;}

.section4 {border-bottom: 1px solid #DADADA;}

.section5 label {display: block;}

''')

d.setHtml(content)

d.print(self.print_device)

def print_(self, data_url):

image_content = base64.b64decode(data_url) # 数据流base64解码

image = QImage()

image.loadFromData(image_content) # 使用QImage构造图片

painter = QPainter(self.print_device) # 使用打印机作为绘制设备

painter.drawImage(0, 0, image) # 进行绘制(即调起打印服务)

painter.end() # 打印结束

class Print(QObject):

def __init__(self):

super().__init__()

self.printer = Printer()

@pyqtSlot(str, result=str)

def print(self, content):

self.printer.print(content)

return

@pyqtSlot(str, result=str)

def print_(self, data_url):

# 去除头部标识

self.printer.print_(data_url.replace('data:image/png;base64,', ''))

return

if __name__ == '__main__':

app = QApplication(sys.argv)

browser = QWebEngineView()

browser.setWindowTitle('使用PyQt5打印热敏小票')

browser.resize(900, 600)

channel = QWebChannel()

printer = Print()

channel.registerObject('printer', printer)

browser.page().setWebChannel(channel)

url_string = "file:///python/print/webprint.html" # 内置的网页地址

browser.load(QUrl(url_string))

browser.show()

sys.exit(app.exec_())

网页端代码

使用PyQt5打印热敏小票

* {padding:0;margin: 0;}

h1 {font-size: 20px;}

h3 {font-size: 16px;}

.left {float: left;}

.right {float:right;}

.clearfix {clear: both;}

ul {list-style: none;}

.print_container {width: 250px;}

.section2 label {display: block;}

.section3 label {display: block;}

.section4 .total label {display: block;}

.section4 {border-bottom: 1px solid #DADADA;}

.section5 label {display: block;}

便利店

***************************************

订单号:700001001201811161631123558

下单时间:2018-10-16 16:31:14

收银员:王小明

***************************************

品名数量金额

今麦郎1100.00

合 计

100.00

收款金额

100

找零金额

0.00

顾客已付款

***************************************

电话:

***************************************

欢迎光临,谢谢惠顾!

便利店

进行html打印

进行图像打印

window.onload = function() {

new QWebChannel(qt.webChannelTransport, function (channel) {

window.printer = channel.objects.printer;

});

}

function do_print() {

if (printer !== null) {

var html = document.querySelector('#capture').innerHTML;

printer.print(html);

}

}

function do_print_() {

if (printer !== null) {

html2canvas(document.querySelector("#capture")).then(canvas => {

var data_url = canvas.toDataURL();

printer.print_(data_url);

});

}

}

python打印小票_PyQt5中使用Qprinter打印热敏小票相关推荐

  1. python调用小票打印机_PyQt5中使用Qprinter打印热敏小票

    在<PyQt5中使用QWebChannel和内嵌网页进行js交互>一文中,我记录了如何使用QWebchannel与内嵌网页进行js交互,其根本目标在于使用Qt5调起打印机服务.在这篇文章中 ...

  2. H5网页调用58热敏小票打印机实现打印小票

    在微信公众号和H5网页开发中,常常需要开发调用打印机进行小票打印操作,通常的做法是调用蓝牙打印机,但是蓝牙打印机由于蓝牙连接的原因,往往稳定性差,需要客户端配合才能发挥好的效果,另外蓝牙打印机距离受限 ...

  3. C#并口热敏小票打印机打印位图

    C#并口热敏小票打印机打印位图 原文:C#并口热敏小票打印机打印位图 最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了. 这是DEMO的窗体: 下面是打印所需要 ...

  4. linux文件扫描并打印,Linux系统中扫描、打印的实现(转)

    Linux系统中扫描.打印的实现(转)[@more@] 扫描图片是日常办公中进行的比较频繁的工作,如何在Linux中使用扫描仪就成为了一个问题.下面笔者就详细介绍一下在Linux中如何进行扫描. 常见 ...

  5. 转:C#并口热敏小票打印机打印位图

    最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了. 这是DEMO的窗体: 下面是打印所需要调用的代码: [html] view plain copy class ...

  6. python打印小票_pyqt5 商店小票打印的实现模板

    说明 最近在用pyqt5做商店小票打印,用的是得力DL-581PW(NEW)热敏小票打印机. 商店小票打印,属于escpos打印. 在网上找了很多实现方法,看了很多相关文章,经历了很多困难,最后终于实 ...

  7. 条码标签打印软件如何实现标签重复打印

    重复打印是批量打印中的一种重要的打印方式.在批量打印条码.标签.图片的时候经常会遇到,把同一个标签重复打印多份,或者是把同一张标签纸重复打印多张.那么在中琅条码标签打印软件中如何实现重复打印的呢?下面 ...

  8. WORD如何设置打印? 三分钟学会WORD打印技巧

    我们在办公的时候,很多人时常会需要打印各种各样的文件,很多人都只知道,去打印当前页,或者是整个文档,但在Word打印中也有很多不同的技巧,那么Word如何设置打印?今天呢就来给大家分享一下Word打印 ...

  9. cad打印本计算机未配置,cad无法打印怎么设置_cad图纸无法打印的处理方法

    很多设计人员在电脑中使用cad工作时,经常需要打印各种文件.但最近有小伙伴在使用的过程中,却遇到了cad无法打印的情况,这是怎么回事呢?我们又该如何解决呢?对此今天小编就来为大家分享关于cad图纸无法 ...

最新文章

  1. P1979 [NOIP]华容道
  2. DVWA安装——一个菜鸟的入门教程
  3. 设计模式之抽象工厂模式学习笔记
  4. 一键搞定Java桌面应用安装部署 —— exe4j + Inno Setup 带着JRE, 8M起飞
  5. java中exception_Java中的异常 Exceptions
  6. 编辑器,webstorm,phpstorm系列配置方法汇总-笔记
  7. msdb 数据库_如何检索有关存储在MSDB数据库中的SSIS包的信息
  8. 力扣——315. 计算右侧小于当前元素的个数
  9. logstash增量同步mysql数据到es
  10. Unity3D教程:尽量避免使用foreach
  11. qfiledialog的取消_QFileDialog类(老九学堂C++会员友情翻译,不喜勿喷)
  12. 【BZOJ3505】[Cqoi2014]数三角形 组合数
  13. string和wstring相互转换以及wstring显示中文问题
  14. Iocomp.Ultra Pack V5.SP3 for .Net Crack
  15. 双线性变换(Tustin transform/bilinear transformation)
  16. win7美化_win7/8/10桌面插件美化
  17. jvm 面试之参数实战
  18. 为何老人与年轻人都更愿意选择OPPO?这些用户需求值得关注
  19. 利用雅可比方法求线性方程组C语言_工程项目经济评价的基本方法
  20. PCIE switch 连接绿联SSD

热门文章

  1. unity七日签到系统
  2. 企业如何判断软文推广效果好不好?
  3. Ubuntu下Apache的安装和配置——web服务器
  4. 浩辰CAD 2021 Linux版全球首发,破局双重“封锁”
  5. 数据管理、数据治理、数据资源等概念的定义
  6. 目前微型计算机有哪些树莓派,树莓派推出Pi 400型微型计算机
  7. mastering markdown
  8. Halcon畸变矫正流程
  9. 十进制转换为任意2~16进制||后附带小数的计算
  10. 720s ideapad 黑苹果_现在不买就后悔了 首款完美支持黑苹果的超极本?