PyQt5(Python GUI图形化用户接口)

前言

之前一直在开发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.1Libsite-packagespyqt5_toolsQtindesinger.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_())
QObject设置ID和属性

通过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;
}
QObject.qss
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.py

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信号的操作

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_())
PyQt5事件机制

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_())
QObject定时器

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控件初体验

 

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()
custom-signal

多线程

'''
多线程更新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_())
View Code

 加载本地的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_())
QUrl.fromLocalFile(html_path)

嵌入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_())
self.browser.setHtml()

以上我们主要学习了如何使用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_())
View Code

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_())
Python

==============

<!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>
JavaScript

  

参考

原文地址:https://www.cnblogs.com/sss4/p/13043985.html