目录
1,QTimer
2,QThread
3,网页交互(QWebEngineView和QWebChannel)
3.1显示网页页面
3.2,JS与Pyqt交互(QwebEngineView 和QwebChannel)
3.2.1,PyQt调用js (runJavaSCript)
3.2.2 js调用python程序(QwebChannel)比较复杂。其实是实现了js与python程序调用
3.2.3 runjavaScript和 Qwebchannel传递信息的不同用处
多线程技术涉及三种方法,其中一个是使用计时器模块QTimer,一种是使用多线程模块QThread,还有一种是使用事件处理的功能
如果在应用程序中周期性地进行某项操作,使用QTimer,Qtimer类提供了重复的和单次的定时器要是用定时器,需要先创建一个QTimer实例,将其timeout信号连接到相应的槽,并调用start()。然后,定时器以恒定的间隔发出timeout信号
Qtimer类中常用方法:
start(millseconds):启动或重新自动定时器,时间间隔为毫秒,如果定时已经运行,它将被停止并重新启动,如果sigleShot信号为真,定时器将被激活一次
stop()停止计时器
常用的信号:
signalShot:在给定的时间间隔调用一个槽函数时发射此信号
timeout:当定时器超时时发射此信号
注意:start()之后,每秒都会调用update()
from PyQt5.QtWidgets import QGridLayout,QApplication,QWidget,QPushButton,QLabel
import sys
from PyQt5.QtCore import QTimer,QDateTime
class TimerDemo(QWidget):
def __init__(self):
super(TimerDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('demo')
self.setGeometry(300,300,300,200)
layout=QGridLayout(self)
#定义计时器,并连接槽函数
self.timer=QTimer()
self.timer.timeout.connect(self.show_time)
self.label=QLabel()
layout.addWidget(self.label,0,0,1,2)
self.btn1=QPushButton('start',self)
layout.addWidget(self.btn1,1,0)
self.btn1.clicked.connect(self.start_program)
self.btn2=QPushButton('end',self)
layout.addWidget(self.btn2,1,1)
self.btn2.clicked.connect(self.end_program)
def show_time(self):
date=QDateTime.currentDateTime()
now=date.toString('yyyy-MM--dd hh:mm:ss')
self.label.setText(now)
def start_program(self):
self.timer.start(1000)
self.btn1.setEnabled(False)
self.btn2.setEnabled(True)
def end_program(self):
self.timer.stop()
self.btn2.setEnabled(False)
self.btn1.setEnabled(True)
if __name__=='__main__':
app=QApplication(sys.argv)
demo=TimerDemo()
demo.show()
sys.exit(app.exec_())
from PyQt5.QtWidgets import QLabel,QApplication
import sys
from PyQt5.QtCore import QTimer,Qt
if __name__ == '__main__':
app=QApplication(sys.argv)
label=QLabel('五秒退出')
label.setWindowFlags(Qt.SplashScreen|Qt.FramelessWindowHint)
label.show()
#设置窗口无边框
timer=QTimer()
timer.singleShot(5000,app.quit)#*********
sys.exit(app.exec_())
QThread是Qt线程类中最核心的底层类,由于PyQt的跨平台特性,QThread隐藏所有与平台相关的代码
要使用QThread开始一个线程,可以创建它的一个子类,然后覆盖其QThread.run()函数
QThread类中常用的方法和信号:
start():启动线程
wait():阻止线程,知道满足如下条件之一,*与此QThread对象关联的线程已完成执行,即从run()返回时。如果线程
完成执行,此函数将返回True:如果线程尚未启动,此函数也返回True。*等待时间的单位是毫秒,如果事件是ULONG_MAX(默认值)。则等待,永远不会超时。如果等待超时,此函数将返回False
QThread类中常用的信号
started:在开始执行run()函数之前,从相关线程发射此信号
finished:当线程完成业务逻辑时,从相关线程发射此信号
流程:
class Thread(QThread): #继承QThread
def __init__(self):
super(Thread,self).__init__()
def run(self):
#线程相关的代码
passs
========================
#创建一个新的线程
thread=Thread()
thread.start()
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
global sec
sec = 0
class WorkThread(QThread):
#实例化一个信号对象
trigger = pyqtSignal()
def __int__(self):
super(WorkThread, self).__init__()
def run(self):
#开始进行循环
for i in range(2000000000):
pass
# 循环完毕后发出信号
self.trigger.emit()
def countTime():
global sec
sec += 1
# LED显示数字+1
lcdNumber.display(sec)
def work():
# 计时器每秒计数
timer.start(1000)
# 计时开始
workThread.start()
# 当获得循环完毕的信号时,停止计数
workThread.trigger.connect(timeStop)
def timeStop():
#定时器停止
timer.stop()
print("运行结束用时", lcdNumber.value())
global sec
sec = 0
if __name__ == "__main__":
app = QApplication(sys.argv)
top = QWidget()
top.resize(300, 120)
# 垂直布局类QVBoxLayout
layout = QVBoxLayout(top)
# 加显示屏,按钮到布局中
lcdNumber = QLCDNumber()
layout.addWidget(lcdNumber)
button = QPushButton("测试")
layout.addWidget(button)
#实例化定时器与多线程类
timer = QTimer()
workThread = WorkThread()
button.clicked.connect(work)
# 每次计时结束,触发 countTime
timer.timeout.connect(countTime)
top.show()
sys.exit(app.exec_())
上面的代码实现了界分离UI线程和工作线程
3,处理密集型耗时的事情(频繁调用QApplication.processEVents)
有时候需要处理一些跟界面无关的但非常耗时的事情,这些事情跟界面在同一个线程中,由于时间太长,导致无法响应,处于假死状态。这种情况下,有一种方法是使用多线程,即在子线程中处理文件保存,主线程负责界面相关
如果不使用多线程,最简单的办法就是在文件保存过程中频繁调用QApplication.processEVent()。该函数的作用是让程序处理那些还没处理的时间,然后再把使用权返回给调用者
from PyQt5.QtWidgets import QProgressDialog,QLineEdit,QLCDNumber,QGridLayout,QApplication,QWidget,QPushButton,QLabel
import sys
from PyQt5.QtCore import pyqtSignal,QTimer,QDateTime,Qt,QThread
class ProgressEventDemo(QWidget):
def __init__(self):
super(ProgressEventDemo, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('demo')
layout=QGridLayout(self)
self.label=QLabel('文件数量')
layout.addWidget(self.label,0,0)
self.edit=QLineEdit('10000')
layout.addWidget(self.edit,0,1)
self.btn=QPushButton('开始')
layout.addWidget(self.btn,1,1)
self.btn.clicked.connect(self.progrress)
def progrress(self):
num=int(self.edit.text())
dialog=QProgressDialog()
dialog.setWindowTitle('please wait..')
dialog.setLabelText('正在操作。。')
dialog.setCancelButtonText('取消')
dialog.setMinimumDuration(5)
dialog.setWindowModality(Qt.WindowModal)
dialog.setRange(0,num)
for i in range(num):
dialog.setValue(i)
if dialog.wasCanceled():
print('操作失败')
break
else:
QApplication.processEvents()#可以实现一边执行耗时程序,一边刷新页面的功能
for j in range(100):
print(8000)
print('-------------------')
if __name__=='__main__':
app=QApplication(sys.argv)
demo=ProgressEventDemo()
demo.show()
sys.exit(app.exec_())
参考:https://www.jianshu.com/p/ffd2252113f1
https://www.cnblogs.com/yaoyu126/p/7524625.htmlHtml 与本地代码交互实例
打印热敏小票:https://www.jianshu.com/p/8298c2474630
import sys
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QHBoxLayout,QWidget,QMainWindow,QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView
class UiDemo(QWidget):
def __init__(self):
super().__init__()
self.initUi()
def initUi(self):
self.setWindowTitle('demo')
self.setGeometry(300,300,400,300)
layout=QHBoxLayout(self)
browser=QWebEngineView()
browser.load(QUrl("http://www.baidu.com"))
layout.addWidget(browser)
if __name__ == '__main__':
app=QApplication(sys.argv)
demo=UiDemo()
demo.show()
sys.exit(app.exec_())
可以这样理解:在pyqt的组件界面对显示的网页页面进行更改(举例,如点击PyQt界面的QpushButton 改变网页中的字体的颜色。而不是点击网页中的Button标签按钮),同时可以进行pyqt和网页间的信息传递。相当于pyqt组件控制网页的组件
流程:编写html和js---->pyqt加载html----->利用QwebEngineView.page().runJavaScript()方法加载js。因为是异步,加载js的同时有返回值
前端:
Title
后端:
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QHBoxLayout,QPushButton
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl,QObject
from PyQt5.QtWebChannel import QWebChannel
class GuiDemo(QWidget):
def __init__(self):
super(GuiDemo, self).__init__()
self.initUi()
def initUi(self):
self.setWindowTitle('demo')
self.setGeometry(300,300,500,300)
layout=QHBoxLayout(self)
#显示web页面
self.view=QWebEngineView()
self.view.load(QUrl('E:/workspace/test/test/runjs/index.html'))
layout.addWidget(self.view)
#按钮,当点击按钮是调用html中的js函数
btn=QPushButton('点击调用js')
layout.addWidget(btn)
btn.clicked.connect(self.use_Js)
def js_callback(self,result):
print(result)
def use_Js(self):
#向js中传值
value='hehe'
self.view.page().runJavaScript('Transport("'+value+'");',self.js_callback) #第一个参数是调用html中js。第二个参数是js的返回值 。注意:第一个参数有传值的话,一定有双引号
if __name__=='__main__':
app=QApplication(sys.argv)
demo=GuiDemo()
demo.show()
sys.exit(app.exec_())
效果:
可以这样理解:将网页js不能处理的操作交给python操作(比如打印网页,点击加载的网页按钮调用Pyqt中的Qprint进行打印)。即使没有pyqt界面也可以(利用在实现网页打印,可以直接利用js调用pyton中的方法。浏览器相当于一个Qt编写的界面,然后加载html)
原理:将python的一个对象映射到javascript
流程:编写html和js(要加载qwebchannel.js,以及将没定义的处理类隐射到js中)-------->pyqt加载html------->定义通道Qwebchannel -------->定义处理类(编写处理类作为槽函数pyqtSlot)-------------->将处理类注册到通道(相当于连接)---------->将页面与channel连接|view.setwebChannel(channel)
实现网页截图:需要html2canvas.js 参考官网https://html2canvas.hertzen.com/
js实现页面打印
前端的代码:
前端
QWebChannel测试
便利店
***************************************
***************************************
品名
数量
金额
今麦郎
1
100.00
***************************************
***************************************
后端
import sys,base64
from PyQt5.QtWidgets import QApplication,QWidget,QHBoxLayout,QLabel
from PyQt5.QtCore import QObject, pyqtSlot, QUrl
from PyQt5.QtGui import QImage,QTextDocument,QTextCursor
from PyQt5.QtPrintSupport import QPrinter
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import QWebEngineView
class Test(QObject):
def __init__(self):
super().__init__()
@pyqtSlot(str,result=str)
def print_img(self,img_url):
#去掉头部的base64标示
img_url=img_url.replace('data:image/png;base64,', '')
#将base64解码成二进制
url=base64.b64decode(img_url)
#QImage加载二进制,形成图片流
image=QImage()
image.loadFromData(url)
'''直接输出打印到pdf'''
printer=QPrinter()
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName('test.pdf')
#实例化一个富文本
document=QTextDocument()
cursor=QTextCursor(document)
cursor.insertImage(image)
#调用print()方法 参数为当前实例化的打印函数
document.print(printer)
return 'sucess' #处理成功传回success
if __name__ == '__main__':
app = QApplication(sys.argv)
#加载网页
view=QWebEngineView()
view.load(QUrl('E:/workspace/test/test/test.html'))
# '''流程:定义通道,连接通道'''
# #定义通道
channel = QWebChannel() #必须定义成全局的,否则会出错,不能在定义界面的类里面里面定义会出错
# #定义pyqt操作函数
test = Test() # 必须定义成全局的,否则会出错,不能在定义界面的类里面会出错
# #通道与操作函数连接,也就是注册
channel.registerObject('pyjs', test)
# #网页连接通道
view.page().setWebChannel(channel)
view.show()
sys.exit(app.exec_())
输出:
成功得到pdf文件
个人总结:仅当参考
runjavaScript:主要用来传递PyQt与页面(也就是js)之间的数据
Qwebchannel:主要用来完成一些js无法完成的功能,相当有后端操作