一、调试
首先我们在开发此功能之前,我们先配置好调试功能,这样我们在开发中事半功倍,能清楚的看到日志,方便我们快捷的排错。
ok,这样我们在启动运行时候,就会开启一个远程调试功能,请pycharm的控制台日志:
在浏览器输入该地址。
就出现您的项目的webview内容,点击进入,就可以看到控制台了。。
二、实例代码
python 部分代码如下:
import json
from PyQt5.QtCore import QUrl, pyqtSlot, QObject, pyqtSignal, pyqtProperty, QTimer
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QMessageBox
from com.label.www.base.BaseQMainWindow import BaseQMainWindow
from com.label.www.brigde.CallHandler import CallHandler
#BaseQMainWindow是我自己的基类
class WebViewBox(QMainWindow):
def __init__(self):
super().__init__()
self.browser = None
self.initUI()
def initUI(self):
# 创建一个中央小部件和布局
central_widget = QWidget(self)
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
# 创建 QWebEngineView
self.browser = QWebEngineView()
# 确保启用 JavaScript
self.browser.settings().setAttribute(QWebEngineSettings.JavascriptEnabled, True)
# self.browser.settings().setAttribute(QWebEngineSettings.PluginsEnabled, True)
# self.browser.settings().setAttribute(QWebEngineSettings.LocalContentCanAccessRemoteUrls, True)
# self.browser.settings().setAttribute(QWebEngineSettings.LocalContentCanAccessFileUrls, True)
# self.browser.settings().setAttribute(QWebEngineSettings.AllowRunningInsecureContent, True)
# self.browser.settings().setAttribute(QWebEngineSettings.AllowGeolocationOnInsecureOrigins, True)
# self.browser.settings().setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True)
# 常见通信对象
self.callHandler = CallHandler()
self.channel = QWebChannel()
# 在页面中注入通信对象
self.channel.registerObject('pyqt', self.callHandler)
##前者是str,后者是一个QObject(里面放着需要调用的函数)
self.browser.page().setWebChannel(self.channel)
# 连接信号
self.browser.loadFinished.connect(self.on_load_finished)
#self.browser.setUrl(QUrl("http://localhost:8000/#/main"))
self.browser.load( QUrl("http://localhost:8000/#/main") )
self.browser.show()
###定时测试,发送数据到vue 界面
timer = QTimer(self)
timer.timeout.connect(self.send)
timer.start(1000)
# 将浏览器添加到布局
layout.addWidget(self.browser)
def send(self):
self.callHandler.connectSignal.emit(
json.dumps({
"code": 200,
"func": "messageShow",
"data": "111" })
)
#加载完成
def on_load_finished(self):
print("webview加载完成")
#初始化调用js函数
self.browser.page().runJavaScript("webviewInitLoad()")
CallHandler.py代码
# QObject 继承自 QObject 是所有 Qt 对象的基类。它提供了许多基本的功能和特性,例如信号和槽机制、对象树管理、事件处理
PyQt5.QtCore import QObject
from PyQt5.QtCore import QUrl, pyqtSlot, QObject, pyqtSignal, pyqtProperty
from PyQt5.QtWidgets import QFileDialog
class CallHandler(QObject):
# 定义一个信号,用于向JS发送数据
connectSignal = pyqtSignal(str)
def __init__(self):
super(CallHandler, self).__init__()
# 调用本地文件 js调用python代码函数
@pyqtSlot(str)
def localImport(self, message):
print(f"Received from JS: {message}")
#打开选择本地文件
file_path, _ = QFileDialog.getOpenFileName(parent=None, caption='', directory='', filter='', options=QFileDialog.Options())
if file_path:
print( file_path )
#跳转到标注界面
前端vue代码:
1、安装qwebchannel的通信js插件,直接yarn add qwebchannel 安装几个 或者 npm install qwebchannel.
2、定义channel类型,新建Channel.ts
export interface Channel {
objects: {
pyqt: {
[contextKey: string]: any
}
[namespaceKey: string]: {
[key: string]: any
}
}
}
3、ts下 window 的属性值问题类型定义,不然会找不到类型报错,这个我是在src同级目录新建的types 文件目录和typings.d.ts,这个目录和文件名无所谓,只要你在tsconfig.json 文件中include就可以。
// TS types
interface MessageFromQt {
data: {
type: number
[dataKey: string]: any
}
}
// 解决平台判断中的opera不存在问题
//declare interface Window 用于在 TypeScript 中扩展全局 Window 对象的类型,提供类型安全和更好的代码补全。//这种方式常用于添加自定义的全局函数和变量,使得 TypeScript 能够理解这些扩展并进行类型检查。declare global {
interface Window {
opera: any;
pyqt: any;
qt: {
webChannelTransport: {
send: (data: any) => void;
onmessage: (message: MessageFromQt) => void; // 根据实际使用定义类型
};
};
webviewInitLoad: () => void;
}
}
//解决window不存在问题
declare const window: Window | undefined
//解决document不存在问题
declare const document: Document | undefined
// 确保这个文件能被 TypeScript 编译器识别
export {};
我的tsconfig.json内容
{
"compilerOptions": {
"target": "ESNext", // ECMAScript 目标版本
"module": "ESNext", // 使用 ES 模块
"strict": false, // 启用所有严格类型检查选项
"jsx": "preserve", // 保留 JSX 语法
"moduleResolution": "Node", // 模块解析策略
"esModuleInterop": true, // 允许默认导入非 ECMAScript 模块
"skipLibCheck": true, // 跳过库文件的类型检查
"forceConsistentCasingInFileNames": true, // 强制一致的文件名大小写
"baseUrl": ".",
"paths": {
"@/*": ["src/*"] // 支持路径别名
}
},
"include": [
"types/**/*.ts",
"src/**/*.ts", // 包含所有 TypeScript 文件
"src/**/*.d.ts", // 包含所有声明文件
"src/**/*.tsx", // 包含所有 TSX 文件
"src/**/*.vue" // 包含所有 Vue 文件
],
"exclude": [
"node_modules", // 排除 node_modules 目录
"dist" // 排除构建输出目录
]
}
4、ok基础工作做完我们,初始化代码了,我是在全部初始化在App.vue中。
<script lang="ts" setup>
import {
onMounted,
} from 'vue';
import { QWebChannel } from "qwebchannel";
import { Channel } from '@/plugins/Channel'
//加载完成
onMounted(
()=>{
new QWebChannel(window.qt.webChannelTransport, (channel:Channel) => {
console.log("构造完成...")
//初始化完成
window.pyqt = channel.objects.pyqt;
//连接信号槽,监听发送信号
window.pyqt.connectSignal.connect(connectSignalCallBack)
});
}
)
//信号槽回调处理结构
const connectSignalCallBack = (jsonString) =>{
const res = JSON.parse(jsonString)
console.info(res)
if (res.code === 400) {
console.log(res)
return
}
callBackDict[res.func](res.data)
}
//pyqt回调函数字典
const callBackDict = {
messageShow: ()=>{
console.log("消息提示")
},
newMessage: ()=>{
console.log("新消息提示")
}
}
//pyqt初始化完成调用
window.webviewInitLoad = ()=>{
console.log("webviewInitLoad")
}
</script>
<template>
<router-view /> <!-- 渲染当前路由的组件 -->
</template>
<style scoped>
</style>
界面效果如下:
点击导入文件,调用python的localImport 槽函数。
成功啦!。。。
ok希望对您有帮助!
出处本人《菜鸟学编程》:https://mp.weixin.qq.com/s/KHnIIBmJW2PEaRExTeR62Q