前言
之前一直在開發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>