当前位置:   article > 正文

PYQT/QT 开发VUE GUI应用程序(持续更新)_pyqt vue

pyqt vue

PYQT/QT 开发VUE GUI应用程序(持续更新)

参考列表

博主文章: Qt+vue开发桌面应用程序

知乎文章 超级详细!: 基于 QWebChannel 的前端通信方案

工具书籍:PYQT5快速开发与实战》

使用技术栈

  1. VUE CLI
  2. element等框架均可
  3. QWebEngineView 与 静态页面交互
  4. 需要熟悉QT qrc资源库的操作
  5. PyQt5

如果需要在PYQT5上进行VUE-element的开发之类 可以参考此文章 请仔细观看此文章

提示:在资源文件的打包上也有大坑

持续更新避免踩坑 如果能做到此页面的联调成功 基本上就可以通过VUE-CLI完整的开发一个桌面应用了

以后也许会更新 VUE-ELEMENT 在PYQT上的应用

能实现vue-cli和pycharm pyqt的联调后 开发起来就不是很麻烦了 主要是nodejs操作GPIB或其他设备仪器太复杂了陷入了调用DLL的地狱,使用了ZMQ, WEBSOCKET等还是觉得体验实在是太割裂了,完全不像是nativeGUI,但是这样开发 还是有点electorn的体验了

测试附件

1.联调效果 python传递数据到前台1S更新一次

在这里插入图片描述在这里插入图片描述

2.调试教程

2.1. 准备调试

可以参考我另一篇博文 如何调用静态html

调试准备 因为我是使用的pycharm 所以先要对Run/Debug Configurations进行一个设置

在这里插入图片描述
在这里插入图片描述

再如图位置 输入 < ;QTWEBENGINE_REMOTE_DEBUGGING=9927 > 即在9927端口进行调试

2.2.将调试端口加入到浏览器书签中

在这里插入图片描述

2.3.启动python代码 看到如下提示

在这里插入图片描述

2.4.进入http://127.0.0.1:9927/端口点击项目查看Console 并进行联调

在这里插入图片描述

3.过一遍Python端需要的模块

#!/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/  # 调试地址

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
# -*- 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)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

4.VUE CLI端

根据官方文档初始化一个项目 地址

注意 一定不要 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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

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')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

更改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>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

5.启动 那个先启动都行 作为调试阶段只关注是否能链接成功

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/615007
推荐阅读
相关标签
  

闽ICP备14008679号