前言
之前一直在开发B/S架构的web应用,虽然web应用无需额外安装,但是browser客户端对客户端本机的硬件设备(摄像头、蓝牙设备、打印机、串口...)进行操作。
如果Python和JavaScript之间的函数可以相互调用就好了,Python+JavaScript融合起来的Client肯定会更加强大。
PyQt5概述
Gui:Graphical User Interface又称图形用户接口。也就是我们俗称的桌面应用。
Qt :一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架,支持Windows、Linux、MacOs。
PyQt5:使用Python对C++的Qt库的重新实现,由于最新Qt版本是5.11所以我们习惯称PyQt为PyQt5。
安装PyQt5
pip install PyQt5 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
安装pyqt5-tools
安装完pyqt5-tools之后就可以使用desinger了。desinger是一款图形化的UI组织工具。
pip install pyqt5-tools -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
desinger.exe路径
D:\Python3.6.1\Lib\site-packages\pyqt5_tools\Qt\bin\desinger.exe
配置desinger.exe
PyQt5程序的基本结构
0.导入相关模块
1.创建1个应用程序对象和1个Window窗口
2.开始在Windows中添加控件、设置控件展示样式、设置控件的信号和槽。
3.sys.exit(app.exec_()) 进入事件循环监听
from PyQt5.Qt import * import sys app=QApplication(sys.argv) #创建1个window window=QWidget() #设置这个window的标题 window.setWindowTitle("PyQt5初体验") #设置window的大小 window.resize(500,500) #设置把该window 放在桌面的位置 window.move(400,200) #在window中创建1个lable标签 label=QLabel(window) label.setText("Hello Martion") label.resize(100,200) label.move(200,200) #显示窗口 window.show() #进入消息循环模式 sys.exit(app.exec_())
控件是什么?
把不同的控件绘制在桌面上就是我们看到的桌面应用,控件接受和响应各种事件(鼠标、键盘)和用户进行交互。
控件就相当于前端的HTML标签,不同的标签有相同的属性也有自身独有的特性,是组织GUI界面的最小单位。
每个控件都是矩形的,他们按Z轴排序(叠加)显示
控件会被父控件和前面的控件剪切。
没有父控件的控件称之为窗口(windown/顶层控件)。
PyQt5的顶层和子控件
和HTML标签类似PyQt5中的控件也是有层级结构的。
顶层控件:作为1个窗口进行显示、做为容器承载其他控件。
子控件:在父级控件之内,作为父级控件的一部分。

from PyQt5.Qt import * import sys app=QApplication(sys.argv) #创建1个window顶层控件 window=QWidget() #设置这个window顶层控件的标题 window.setWindowTitle("我是父级控件") #设置window顶层控件的大小 window.resize(500,500) #设置把该window顶层控件放在桌面的位置 window.move(400,200) #在顶层控件中创建1个lable子级标签(继承window标签) label=QLabel(window) label.setText("我是子控件") #设置子标签的大小 label.resize(100,200) #设置把该lable标签放在顶层控件的位置 label.move(100,200) #显示顶层控件之后,子控件也跟随显示。 window.show() #进入消息循环模式 sys.exit(app.exec_())
PyQt5控件学习过程
PyQt5框架实现 使用了面向对象设计模式,每1种控件由于不同的类实现,所以我们想要对PyQt5框架进行系统的学习,就要从父类开始一直延伸到不同的子类。
Qobject 类
QObject是所有Qt对象的基类,学习PyQt5就从它开始,逐个击破。
QObject设置ID和属性:
obj.setObjectName("notice"):给QT对象设置1个唯一的名称,相当于对象的ID
print(obj.objectName()):获取QT对象的ID
obj.setProperty("notice_level1","error"):给QT对象动态设置1个属性和值
print(obj.property("notice_level1")):根据属性名称获取QT对象的值
print(obj.dynamicPropertyNames()):获取QT对象中所有通过setProperty()设置的属性

from PyQt5.Qt import * class Windown(QWidget): def __init__(self): super().__init__() self.setWindowTitle("QObject学习") self.resize(500,500) self.setup_ui() def setup_ui(self): # self.get_children_of_QObject() self.get_property_of_QObject_instance() self.get_name_of_QObject_instance() #获取QObject的子类 def get_children_of_QObject(self): print(QObject.__subclasses__()) #设置和获取QObject 对象的属性 def get_property_of_QObject_instance(self): obj=QObject() obj.setProperty("notice_level1","error") obj.setProperty("notice_level2", "warning") print(obj.property("notice_level1")) print(obj.dynamicPropertyNames()) #设置和获取QObject 对象的名称 def get_name_of_QObject_instance(self): obj = QObject() obj.setObjectName("notice") print(obj.objectName()) if __name__ == '__main__': import sys app=QApplication(sys.argv) window=Windown() window.show() sys.exit(app.exec_())
通过ID和属性设置控件的样式

QLabel#notice{ font-size:20px; color:gray; border:1px solid gray; border-radius:8px; } QLabel#notice[notice_level="normal"]{ color:green; border-color:green; } QLabel#notice[notice_level="warning"]{ color:yellow; border-color:yellow; } QLabel#notice[notice_level="error"]{ color:red; border-color:red; }

from PyQt5.Qt import * class Windown(QWidget): def __init__(self): super().__init__() self.setWindowTitle("QObject学习") self.resize(500,500) self.setup_ui() def setup_ui(self): #加载样式文件 with open("QObject.qss","r") as f: qApp.setStyleSheet(f.read()) label=QLabel(self) label.move(150,50) label.setText('normal....') label.setObjectName("notice") label.setProperty("notice_level","normal") label2=QLabel(self) label2.move(150,100) label2.setText("warning....") label2.setObjectName("notice") label2.setProperty("notice_level", "warning") label3=QLabel(self) label3.setText("error.....") label3.move(150,150) #设置qt对象ID和属性(和html不同的是ID在整个Qt对象中可以重复!) label3.setObjectName("notice") label3.setProperty("notice_level", "error") button=QPushButton(self) button.setText("提交") button.move(150,200) if __name__ == '__main__': import sys app=QApplication(sys.argv) window=Windown() window.show() sys.exit(app.exec_())
QObject对象的父子关系操作
print(p1.parent()):获取父级标签
print(html.children()):获取所有直接子控件
#控件2类型、id、FindChildrenRecursively递归查找|FindDirectChildrenOnly仅查找直接节点
print(html.findChild(QObject, "body",Qt.FindChildrenRecursively)) :筛选子控件(单个)
print(html.findChildren(QObject,"body")):筛选子控件(多个)

from PyQt5.Qt import * class Windown(QWidget): def __init__(self): super().__init__() self.setWindowTitle("QObject学习") self.resize(500,500) self.setup_ui() def setup_ui(self): html=QObject() body=QObject() body.setObjectName("body") head=QObject() div1=QObject() div2=QObject() p1 = QObject() p2 = QObject() #设置父子关系:1个对象只能有1个父级对象,以后设置的为准 body.setParent(html) head.setParent(html) div1.setParent(body) div2.setParent(body) p1.setParent(div1) p2.setParent(div2) #获取父对象 print(p1.parent()) #获取所有直接子对象 print(html.children()) #控件2类型、id、FindChildrenRecursively递归查找|FindDirectChildrenOnly仅查找直接节点 print(html.findChild(QObject, "body",Qt.FindChildrenRecursively)) print(html.findChild(QObject, "body", Qt.FindDirectChildrenOnly)) #查找多个 # print(html.findChildren(QObject,"body")) if __name__ == '__main__': import sys app=QApplication(sys.argv) window=Windown() window.show() sys.exit(app.exec_())
如果1个控件没有任何父控件,那么就会当成顶层控件(窗口)。
如果1个控件有父控件,那么这个子控件的位置受父控件约束,一旦父控件消失子控件也随之消失。
QObject信号操作
不管是GUI还是Web编程,都是信号驱动的!这些信号有内置的(click/move/leave....)也可以自定义信号。
信号和槽是相对而言的,通过PyQt5的QObject类创建的对象可以发出信号,当连接到槽的信号发出时, 槽(函数)就会被调用。
信号和槽是多对多的关系。一个信号可以连接多个槽,而一个槽也可以监听多个信号。
流程:
触发------》信号emit--->connect---->槽起到监听信息,响应用户行为的作用。
widget.信号.connect(槽) :绑定信号与槽
obj.disconnect():取消信号与槽绑定
widget.blockSigals(bool):暂停信号与槽的关系
widget.signalsBlocked():信号是否暂停
widget.receives("信号"):objectNameChanged信号对应的接收器(槽)数量
QObject内置的信号
obj.destroyed():对象名称发送改变时发射此信号。
obj.objectNameChanged():对象被销毁时,发射此信号。

from PyQt5.Qt import * class Windown(QWidget): def __init__(self): super().__init__() self.setWindowTitle("QObject学习") self.resize(500,500) self.setup_ui() def QObject信号的操作(self): obj=QObject() def name_changed(name): print("对象名称更改为",name) def name_changed2(name): print("The name of object change into", name) def destroy_slot(obj): print("对象被销毁",obj) obj.objectNameChanged.connect(name_changed2) obj.objectNameChanged.connect(name_changed) #解除signal和slot的绑定 # obj.objectNameChanged.disconnect() obj.setObjectName("xx0") #暂停信号与槽的关系 obj.blockSignals(True) obj.setObjectName("xx1") #恢复信号与槽的关系 obj.blockSignals(False) obj.setObjectName("xx2") #objectNameChanged信号对应的接收器(槽)数量 print(obj.receivers(obj.objectNameChanged)) obj.destroyed.connect(destroy_slot) def setup_ui(self): self.QObject信号的操作() if __name__ == '__main__': import sys app=QApplication(sys.argv) window=Windown() window.show() sys.exit(app.exec_())
QObject类型判定
print(obj.isWidgetType()):判断是否为WidgetType
print(obj.inherits("QWidget")):判断是否继承QWidget
print(obj.inherits("QPushButton")):判断是否继承QPushButton

label1=QLabel(self) label1.setText("社会我顺哥") label1.move(150,100) label2=QLabel(self) label2.setText("社会我旺哥") label2.move(150,150) btn=QPushButton(self) btn.setText("点我") btn.move(150,200) #查询所有windown中的子控件 for wdiget in self.children(): #把QLabel类型的控件设置为绿色 if wdiget.inherits("QLabel"): wdiget.setStyleSheet("background-color:green;")
QObject对象删除
obj.deleteLater
机制:删除1个对象时先解除它与父对象的关系,然后向主消息循环发送1个event,下一次消息循环接收到这个event之后,对象被销毁。
延迟删除的好处在于保证本次消息循环代码不报错,坏处是无法及时释放内存。
Qt事件机制
因为信号封装了事件机制,所有用户在PyQt5程序界面的各种操作,就会触发信号进而执行槽函数。
一个PyQt5应用包含2个消息队列(系统产生的消息、程序内部产生的消息), 应用程序的消息循环就是在不断得处理这些队列中的消息。
1.用户操作会产生各种事件
2.第一个接收到消息是操作系统、操作系统将消息分发到对应应用程序的消息队列中。
3.PyQt程序消息循环如果发现“消息事件”则会包装成QEvent对象,进行分发。
4.把事件接收者(receiver)和事件对象(evt)传递给QAppplication对象的notify(receiver,evt)方法。
5.notify方法调用事件接收者的event(event)方法
6.事件接收者的event方法会根据具体的事件类型,分发给事件接收者 具体的事件函数。
7.事件函数发送信号执行槽函数。

import sys from PyQt5.Qt import * class App(QApplication): #4. def notify(self, recevier,evt): if recevier.inherits("QPushButton") and evt.type()==QEvent.MouseButtonPress: print(recevier,evt) return super().notify(recevier,evt) class Btn(QPushButton): #5. def event(self, event): if event.type()==QEvent.MouseButtonPress: print(event) return super().event(event) #6. def mousePressEvent(self, *args,**kwargs): print("鼠标被按下了!") return super().mousePressEvent(*args,**kwargs) app=App(sys.argv) window=QWidget() btn=Btn(window) btn.setText("按钮") btn.move(100,100) def func(): print("按钮被点击了") btn.pressed.connect(func) window.show() sys.exit(app.exec_())
QObject定时器
timer_id=obj.startTimer(1000):开启定时器,间隔1000毫秒执行1次
timerEvent(self, timerEvent):定时器定时执行的事件
obj.killTimer(timer_id):停止某个定时器

from PyQt5.Qt import * import sys #2.定时执行(继承QObject然后重写timerEvent方法) class MyLabel(QLabel): # def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) self.setText("10") self.move(100, 100) self.setStyleSheet("background-color:yellow;font-size:22px") # label继续于Qobject self.timer_id1 = self.startTimer(1000) def timerEvent(self, *args,**kwargs): #获取当前标签的大小和内容 self.resize(self.width()+10,self.height()+10) present_second=int(self.text()) present_second-=1 self.setText(str(present_second)) if present_second==0: self.killTimer(self.timer_id1) #0.创建1个应用程序对象 app=QApplication(sys.argv) window=QWidget() window.setWindowTitle("QObject定时器的使用") window.resize(500,500) label=MyLabel(window) obj=QObject() #1.间隔1秒钟就会执行obj的startTimer()方法 timer_id=obj.startTimer(1000) #3.使用obj的killTimer(timer_id)方法停止某1个定时器 obj.killTimer(timer_id) window.show() sys.exit(app.exec_())
QWidget类
Qwidget是QOject的子类(QObject的方法它全部具备), QWidget可以绘制1个最基本、简单的空白控件(div),是所有可视化控件的基类。

from PyQt5.Qt import * import sys app=QApplication(sys.argv) #没有父控件的控件就是窗口 window=QWidget() window.setWindowTitle("QObject定时器的使用") window.resize(500,500) #window的子控件1 red_one=QWidget(window) red_one.resize(100,100) red_one.setStyleSheet("background-color:red") red_one.move(300,0) #window的子控件2 green_one=QWidget(window) green_one.resize(100,100) green_one.setStyleSheet("background-color:green") green_one.move(300,100) #显示窗口 window.show() #进入世界循环 sys.exit(app.exec_())
QWidget的位置和大小信息
控件以左上角为坐标原点,向右为x轴方向,向下为y轴方向。
参照位置:如果有父控件就参照父控件,如果是顶级控件就参照整个window。
获取控件的位置和大小
x():获取相对于父控件的x位置,顶层控件(没有父控件)则相对于桌面的x位置。
y():获取相对于父控件的y位置,顶层控件(没有父控件)则相对于桌面的x位置。
pos():获取x和y的组合
width():获取控件的宽度(用户区域)
height():获取控件的高度(用户区域)
size():获取width和height的组合。
geometry():获取用户区域(不包含窗口) x,y,width和height相当于父控件位置和尺寸组合。
rect():获取用户区域0,0,width和height的组合
frameSize():获取框架的大小
frameGeometry():获取框架的尺寸
ps:控件显示完毕之后,获取具体的位置或尺寸数据才会正确。
代码
from PyQt5.Qt import * import sys app=QApplication(sys.argv) #没有父控件的控件就是窗口 window=QWidget() window.setWindowTitle("QObject定时器的使用") window.resize(500,500) #window的子控件1 red_one=QWidget(window) red_one.move(300,0) red_one.resize(100,100) red_one.setStyleSheet("background-color:red") #显示窗口 window.show() print(red_one.x())#300 print(red_one.y())#0 print(red_one.width())#100 print(red_one.height())#100 print(red_one.pos())#PyQt5.QtCore.QPoint(300, 0) print(red_one.geometry())#PyQt5.QtCore.QRect(300, 0, 100, 100) print(red_one.rect())#PyQt5.QtCore.QRect(0, 0, 100, 100) #进入世界循环 sys.exit(app.exec_())
设置控件的位置和大小
move():设置控件相对于父控件的x,y也就是pos。
resize(width,height):设置控件用户区域的宽和高,并非整个框架。
setGeomerty(x_noFrame,y_noFrame,width,height):设置用户区域距离父控件的位置和宽高。
adjustSize():根据内容自适应大小。
setFixedSize():设置固定尺寸。

import sys from PyQt5.Qt import * app=QApplication(sys.argv) window=QWidget() window.resize(500,500) # window.move(300,300) w=QWidget(window) w.resize(100,100) w.setStyleSheet("background-color:red") #总的控件个数 widget_count=23 #一行有多少列 colum_count=5 #计算1个控件的宽度 widget_width=window.width()//colum_count #总共有多少行(最大编号//一行有多少列)+1 row_count=(widget_count-1)//colum_count+1 #总高度/总行数=单个的高度 widget_hight=window.height()//row_count for i in range(0,widget_count): w=QWidget(window) w.resize(widget_width,widget_hight) #当前控件所在的列号 = 当前控件的编号 %(取于)总列数 #当前控件所在的行号 = 当前控件的编号 //(整除)总列数 #当前控件说所在的列号 * 控件的宽度 widget_x=i%colum_count*widget_width #当前控件所在的行号 * 控件的高度 widget_y =i//colum_count * widget_hight w.move(widget_x,widget_y) w.setStyleSheet("background-color:red;border:1px solid syin") w.show() window.show() sys.exit(app.exec_())
设置控件最小、最大尺寸
windown.resize(500,500):设置弹性最大、最小尺寸
windown.setFixedSize(500,500):设置固定最大、最小尺寸
windown.setMinimumSize(200,200):设置最小尺寸(到达这个尺寸之后无法再缩小)
windown.setMaximumSize(500,500):设置最大尺寸(到达这个尺寸之后无法再缩小)
windown.setMinimumWidth(300):限定最小/最大的宽度和高度
windown.setMaximumHeight(400)
windown.setMaximumWidth(500)
windown.setMinimumHeight(400)
一旦设置了固定尺寸/限定了宽度和长度之后,resize() API 将无法修改控件限定范围外的大小。
调整内容边距
qlabel.setContentsMargins(10,50,0,0): 设置内容边距顺序为左、上、右、下
print(qlabel.getContentsMargins()):获取内容边距
print(qlabel.contentsRect()):获取内容区域

from PyQt5.Qt import * import sys app=QApplication(sys.argv) windown=QWidget() windown.setWindowTitle("内容边距") windown.resize(500,500) qlabel=QLabel(windown) qlabel.setText("社会我顺哥") qlabel.resize(100,100) qlabel.setStyleSheet("background-color:cyan;border:1px solid red") #设置内容边距:左、上、右、下 qlabel.setContentsMargins(10,50,0,0) #获取内容边距 print(qlabel.getContentsMargins()) #获取内容区域 print(qlabel.contentsRect()) windown.show() sys.exit(app.exec_())
QWidget鼠标操作
设置鼠标的形状:缺省情况下我们的鼠标是箭头,但是我们可以改变鼠标的形状。
window.setCursor(Qt.ArrowCursor) 箭头
window.setCursor(Qt.UpArrowCursor)向上箭头
window.setCursor(Qt.CrossCursor) 十字架
window.setCursor(Qt.IBeamCursor)
window.setCursor(Qt.WaitCursor)等待
window.setCursor(Qt.BusyCursor) 繁忙
window.setCursor(Qt.ForbiddenCursor) 禁止
window.setCursor(Qt.PointingHandCursor) 手指
window.setCursor(Qt.WhatsThisCursor)箭头+问号
window.setCursor(Qt.SizeVerCursor)
window.setCursor(Qt.SizeHorCursor)
window.setCursor(Qt.SizeBDiagCursor)
window.setCursor(Qt.SizeAllCursor)
window.setCursor(Qt.SplitVCursor)
window.setCursor(Qt.SplitHCursor)
window.setCursor(Qt.OpenHandCursor)打开手
window.setCursor(Qt.ClosedHandCursor) 关闭手
window.setCursor(Qt.BlankCursor)空白的鼠标
window.unsetCursor():重置鼠标形状,在改变鼠标形状之后我们还可以将其恢复原样。
获取鼠标对象
current_cursor=label.cursor() #获取鼠标对象信息
print(current_cursor.pixmap())#获取鼠标对象的图片
current_cursor.setPos(10,100)#设置鼠标位置
print(current_cursor.pos())#获取鼠标的位置
鼠标跟踪
window.setMouseTracking(True):开启鼠标追踪之后会自动触发控件的mouseMoveEven()方法
自定义信号

#自定义信号 from PyQt5.QtCore import * #信号 class MyTypeSingnal(QObject): #定义1个信号 sendmsg=pyqtSignal(int) def run(self): #定义这个信号发出时携带的数据 self.sendmsg.emit("Hello PyQt5") #槽 class MySlot(QObject): #定义1个槽 def get(self,msg): print("信息"+msg) if __name__ == '__main__': signal=MyTypeSingnal() slot=MySlot() #信号和槽建立连接 signal.sendmsg.connect(slot.get) #触发信号 signal.run() #信号和槽进行解除绑定 signal.sendmsg.disconnect(slot.get) #再次触发信号 signal.run()
多线程

''' 多线程更新UI数据 ''' import time,sys from PyQt5.QtCore import QThread,pyqtSignal,QDateTime from PyQt5.QtWidgets import QApplication,QDialog,QLineEdit class BackendThread(QThread): #定义1个信号 update_date=pyqtSignal(str) #信号发出时执行 def run(self): while True: time.sleep(1) current_date=QDateTime.currentDateTime() current_time=current_date.toString("yyyy-MM-dd hh:mm:ss") self.update_date.emit(str(current_time)) class ThreadUpdateUI(QDialog): def __init__(self): QDialog.__init__(self) self.setWindowTitle("QT多线程") self.resize(100,100) self.input=QLineEdit(self) self.input.resize(400,100) self.initUi() def initUi(self): self.backend=BackendThread() #信号--->emit--->connect---->槽 self.backend.update_date.connect(self.hadleDisplay) #触发信号 self.backend.start() #槽 def hadleDisplay(self,data): self.input.setText(data) if __name__ == '__main__': app=QApplication(sys.argv) exaple=ThreadUpdateUI() exaple.show() sys.exit(app.exec_())
PyQtWebEngine
PyQtWebEngine实现了Python和JavaScript之间交互,这意味着如果你之前可以开发Web应用就可以开放出一个desptop应用。
因为这PyQtWebEngine可以把.HTML文件渲染出效果来,也可以把Python嵌入到JavaScript中。
pip install PyQtWebEngine -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
加载外部的web界面

import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtWebEngineWidgets import * class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setWindowTitle('京东') self.setGeometry(5,30,1355,730) self.browser=QWebEngineView() #加载外部的web界面 self.browser.load(QUrl('https:www.jd.com')) self.setCentralWidget(self.browser) if __name__ == '__main__': app=QApplication(sys.argv) win=MainWindow() win.show() app.exit(app.exec_())
加载本地的HTML文件

<html> <body> <h4>这个表格有一个标题,以及粗边框:</h4> <table border="6"> <caption>我的标题</caption> <tr> <td onclick="zhanggen()">100</td> <td>200</td> <td>300</td> </tr> <tr> <td>400</td> <td>500</td> <td>600</td> </tr> </table> <script> function zhanggen() { alert(6666) } </script> </body>

import sys,os from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtWebEngineWidgets import * class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setWindowTitle('京东') self.setGeometry(5,30,1355,730) self.browser=QWebEngineView() #加载本地的html文件 html_path=os.getcwd()+"/index.html"#D:\PyQt5模块\index.html self.browser.load(QUrl.fromLocalFile(html_path)) self.setCentralWidget(self.browser) if __name__ == '__main__': app=QApplication(sys.argv) win=MainWindow() win.show() app.exit(app.exec_())
嵌入HTML字符串

import os import sys from PyQt5.QtWebEngineWidgets import * from PyQt5.QtWidgets import * class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setWindowTitle('京东') self.setGeometry(5, 30, 1355, 730) self.browser = QWebEngineView() # 加载本地的html文件 html_path = os.getcwd() + "/index.html" # D:\PyQt5模块\index.html self.browser.setHtml(''' <html> <body> <h4>这个表格有一个标题,以及粗边框:</h4> <table border="6"> <caption>我的标题</caption> <tr> <td onclick="zhanggen()">100</td> <td>200</td> <td>300</td> </tr> <tr> <td>400</td> <td>500</td> <td>600</td> </tr> </table> <script> function zhanggen() { alert(6666) } </script> </body> ''') self.setCentralWidget(self.browser) if __name__ == '__main__': app = QApplication(sys.argv) win = MainWindow() win.show() app.exit(app.exec_())
以上我们主要学习了如何使用QtWebEngineWidgets加载出HTML文件的网页效果。下面我们来看看他们之间如何交换数据?
self.browser.page().runJavaScript
Python调用JavaScript中的函数

import sys,os,time from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtWebChannel import QWebChannel from PyQt5.QtWebEngineWidgets import QWebEngineView class PyQt5CallJs(QWidget): def __init__(self): super(PyQt5CallJs,self).__init__() self.setWindowTitle('PyQt5调用JavaScript') #垂直布局 self.setGeometry(100,100,400,200) self.layout=QVBoxLayout() self.setLayout(self.layout) #创建浏览器 self.browser=QWebEngineView() html = os.getcwd() + "./templates/test.html" self.browser.load(QUrl.fromLocalFile(html)) self.layout.addWidget(self.browser) #绑定clicked事件 button=QPushButton("开始检测") button.clicked.connect(self.progress) self.layout.addWidget(button) #执行 def progress(self): for n in range(0,101): self.browser.page().runJavaScript('zhanggen("%s")'%(str(n)),self.progress_callback) #回调 def progress_callback(self, result): print(result) # QMessageBox.information(self, "提示", str(result)) if __name__ == '__main__': app = QApplication(sys.argv) windown=PyQt5CallJs() windown.show() sys.exit(app.exec_())
PyQt QtWebChannel
JavaScript调用Python中的函数

import sys,os from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtWebChannel import QWebChannel from PyQt5.QtWebEngineWidgets import QWebEngineView import datetime class ProgressBar(QWidget): def __init__(self): super(ProgressBar,self).__init__() self.setWindowTitle('进度条') self.resize(600,300) #创建brwser并使用浏览器加载html文件 self.browser=QWebEngineView() html = os.getcwd() + "./ww.html" self.browser.load(QUrl.fromLocalFile(html)) #在brwser中注册1个Python类的对象 self.channel = QWebChannel() self.channel.registerObject('printer',self) self.browser.page().setWebChannel(self.channel) #把brwser添加设置到layout里面 layout = QVBoxLayout() layout.addWidget(self.browser) self.setLayout(layout) # pyqtSlot,中文网络上大多称其为槽。作用是接收网页发起的信号 @pyqtSlot(str, result=str) def print(self, content): print('输出文本:',content) #返回值 return str(datetime.datetime.now()) if __name__ == '__main__': app = QApplication(sys.argv) windown=ProgressBar() windown.show() sys.exit(app.exec_())
==============

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>测试</title> <script src="./qwebchannel.js"></script> <!-- 引入qwebchannel.js,才能与QWebEngineView进行交互 --> <script type="text/javascript" src="./qwebchannel.js"></script> <script> window.onload = function () { new QWebChannel(qt.webChannelTransport, function (channel) { // 此处channel.objects.printer中的printer就是上文提到的功能类注册的标识名 window.printer = channel.objects.printer; }); }; </script> </head> <body> <button onclick="sendMes()">发送消息</button> <p id="mes"></p> <script> //接收Python函数的返回值 function callback(result){ alert(result) } function sendMes() { // 调用python端的功能类的方法执行操作 printer.print('你收到一条网页发送的消息!',callback) } </script> </body> </html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南