赞
踩
参考列表
博主文章
: Qt+vue开发桌面应用程序
知乎文章 超级详细!:
基于 QWebChannel 的前端通信方案
工具书籍:
《PYQT5快速开发与实战》
使用技术栈
- VUE CLI
- element等框架均可
- QWebEngineView 与 静态页面交互
- 需要熟悉QT qrc资源库的操作
- PyQt5
如果需要在PYQT5上进行VUE-element的开发之类 可以参考此文章 请仔细观看此文章
提示:在资源文件的打包上也有大坑
持续更新避免踩坑 如果能做到此页面的联调成功 基本上就可以通过VUE-CLI完整的开发一个桌面应用了
以后也许会更新 VUE-ELEMENT 在PYQT上的应用
能实现vue-cli和pycharm pyqt的联调后 开发起来就不是很麻烦了 主要是nodejs操作GPIB或其他设备仪器太复杂了陷入了调用DLL的地狱,使用了ZMQ, WEBSOCKET等还是觉得体验实在是太割裂了,完全不像是nativeGUI,但是这样开发 还是有点electorn的体验了
可以参考我另一篇博文 如何调用静态html
调试准备 因为我是使用的pycharm 所以先要对Run/Debug Configurations进行一个设置
再如图位置 输入 < ;QTWEBENGINE_REMOTE_DEBUGGING=9927 > 即在9927端口进行调试
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # @Time : 2021/4/15 9:29 # @Author : Link # @Site : # @File : demo_one.py # @Software: PyCharm import itertools import json import sys import string from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout from PyQt5.QtWebEngineWidgets import QWebEngineView from PyQt5.QtCore import QUrl, QTimer from MySharedObject import MySharedObject from PyQt5.QtWebChannel import QWebChannel # from qweb.dist import src_rc # 创建一个 application实例 app = QApplication(sys.argv) win = QWidget() win.setWindowTitle('Web页面中的JavaScript与 QWebEngineView交互例子') # 创建一个垂直布局器 layout = QVBoxLayout() win.setLayout(layout) # 创建一个 QWebEngineView 对象 view = QWebEngineView() # htmlUrl = 'qrc:/index.html' htmlUrl = 'http://localhost:8080/' # 远程到nodejs服务调试 channel = QWebChannel() myObj = MySharedObject() channel.registerObject("bridge", myObj) # 注册对象到VUE中 主要! view.load(QUrl(htmlUrl)) # 创建一个 QWebChannel对象,用来传递pyqt参数到JavaScript view.page().setWebChannel(channel) def generator_a_z(): # 向前端发送数据 length = 1 while length: for letters in itertools.product(string.ascii_uppercase, repeat=length): yield ''.join(letters) length += 1 s = generator_a_z() timer = QTimer() timer.timeout.connect(lambda: myObj.connectSignal.emit( json.dumps({ "code": 200, "func": "messageShow", "data": next(s) }) )) timer.start(1000) # 把QWebView和button加载到layout布局中 layout.addWidget(view) # 显示窗口和运行app win.show() sys.exit(app.exec_()) # http://127.0.0.1:9927/ # 调试地址
# -*- coding: utf-8 -*- # @File : MySharedObject.py from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal from PyQt5.QtCore import pyqtProperty from PyQt5.QtWidgets import QWidget, QMessageBox class MySharedObject(QWidget): connectSignal = pyqtSignal(str) # 注册到VUE中 @pyqtSlot(str) def foo(self): print('aaa') def __init__(self): super(MySharedObject, self).__init__() def _getStrValue(self): # return '100' def _setStrValue(self, str): # print('获得页面参数 :%s' % str) QMessageBox.information(self, "Information", '获得页面参数 :%s' % str) # 需要定义对外发布的方法 静态页面测试通过 但VUE中暂时还没用到 strValue = pyqtProperty(str, fget=_getStrValue, fset=_setStrValue)
根据官方文档初始化一个项目 地址
注意 一定不要 Eslint或是关闭它
, 当然大神可以不用管
项目结构
qwebchannel.js只要PYQT中下载了PYQTWebEngine 后 用everything本地搜索就可以了,如果是下载的比较新 就不需要对这个文件做任何修改 不然可能需要 export QWebChannel
主要入口重要
import { QWebChannel } from './qwebchannel' const model = 'eng' // 可以写在env文件中 /* 这段代码 主要是为了能在离开QT启动的环境下 调用QWebChannel 不然会报错无qt.webChannelTransport程序无法运行 */ if (model === 'pro') { // 使用pro模式可以在离开QT环境下调试 window.qt = { webChannelTransport: { send() { console.log(` QWebChannel simulator activated ! `) } } } } /* 这个MAP 是为了做一个funtino的缓存 在view中建立页面的时候 如果需要从python直接控制view页面 就将function 注册到如下MAP中 为什么这么做的原因:因为web页面启动起来后 QWebChannel可能还未触发 我这边估计会延迟3s左右 在这个时候 qtWebChannel 还是空值 无法进行connect mounted() { this.$QtCallBackDict.messageShow = this.updateMessage }, methods:{ updateMessage(text){ this.message = text }, } */ export var callBackDict = { messageShow: null, newMessage: null, } export var qtWebChannel = null; //导出qtWebChannel,供其他页面调用 new QWebChannel(qt.webChannelTransport, (channel) => { // all published objects are available in channel.objects under // the identifier set in their attached WebChannel.id property console.log(channel.objects) qtWebChannel = channel.objects.bridge; callBack() }); /* bridge对象传入后 进行初始化 */ function callBack() { console.log("初始化") qtWebChannel.connectSignal.connect(connectSignalCallBack) } /* 对python端 MySharedObject下 connectSignal传来的json数据进行一个处理 */ function connectSignalCallBack(jsonString) { /* res: { code: 200/400 400就是后台有问题 func: string 在mount中载入 data: Dict 传入到view函数中 } */ const res = JSON.parse(jsonString) console.info(res) if (res.code === 400) { console.log(res) return } // 可以自己在这里加上校验之类 以免funcname不存在 callBackDict[res.func](res.data) }
VUE引入
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// 将函数暴露到Vue中
import { callBackDict, qtWebChannel } from './utils/requests'
Vue.prototype.$QtCallBackDict = callBackDict
Vue.prototype.$QtWebChannel = qtWebChannel
new Vue({
render: h => h(App),
}).$mount('#app')
更改APP.vue
<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png" /> <!-- <HelloWorld msg="Welcome to Your Vue.js App" /> --> <input v-model="message" type="text" /> </div> </template> <script> // import HelloWorld from "./components/HelloWorld.vue"; export default { name: "App", components: { HelloWorld, }, data() { return { message: "aa", }; }, mounted() { this.$QtCallBackDict.messageShow = this.updateMessage }, methods:{ updateMessage(text){ this.message = text }, } }; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。