PYQT/QT 开发VUE ELEMENT应用程序(完结)

基础参考前篇文章

PYQT/QT 开发VUE GUI应用程序

框架完结,基于vue-element-admin开发

因为本人在对前端不是很熟悉, 只会做日常开发 可能很多地方表述不准请见谅

实际上开发起来还是比较割裂的,而且运行起来的顺滑度也没浏览器快的感觉,交互性能暂时没有测试

修改后的前端项目 已经上传到gitee

1. 测试效果

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

2. ELEMENT端修改

vue-admin-template中clone代码, 根据markdown中文文档步骤构建环境并启动

启动完成后进行修改添加功能

以table页面作为改动参考 改动结构如下

在这里插入图片描述

所做的更改 只有加入了两个js,修改了main.js 修改table.vue进行交互

2.1 加入两个必要的js

qt-request.js

import Vue from 'vue' // 引入Vue在初始化qtWebChannel后将object放入全局
import { QWebChannel } from './qwebchannel'
import { Message } from 'element-ui'

if (process.env.NODE_ENV === 'development') {
  window.qt = {
    webChannelTransport: {
      send() {
        console.log(`
              QWebChannel simulator activated !
              启动QT桌面端后请注销此段代码
            `)
      }
    }
  }
}

export var callBackDict = {}

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
  qtWebChannel = channel.objects.bridge
  Vue.prototype.$QtCallBackDict = callBackDict // 用于注册从QT端的回调
  Vue.prototype.$QtWebChannel = qtWebChannel
  Vue.prototype.$request = request  // 向QT端发送消息
  console.log(qtWebChannel)
  ChannelCallBack()
})

function request(func, data) {
  Vue.prototype.$QtWebChannel.request(
    JSON.stringify({ func: func, data: data })
  )
}

function ChannelCallBack() {
  console.log('初始化')
  qtWebChannel.connectSignal.connect(connectSignalCallBack)
}

function connectSignalCallBack(jsonString) {
  /*
  res: {
      code: 200/400 400就是后台有问题
      func: string 在mount中载入
      data: Dict 传入到view函数中
  }
  */
  console.info(callBackDict)
  const res = JSON.parse(jsonString)
  console.info(res)
  if (res.code === 400) {
    console.log(res)
    Message({
      message: res.message || 'Error',
      type: 'error',
      duration: 5 * 1000
    })
    return
  }
  const func = res.data.func
  const data = res.data.data
  callBackDict[func](data)
}

qwebchannel.js 自行添加

2.2 修改main.js引入全局QWebChannel

...
if (process.env.NODE_ENV === 'production') {
  const { mockXHR } = require('../mock')
  mockXHR()
}

/*
添加
载入QWebChannel
 */
import '@/utils/qt-request'

// set ElementUI lang to EN
Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui,按如下方式声明
// Vue.use(ElementUI)
...

2.3 修改table.vue

<script>
// 以前是如何的我就不写了 这是更改后的

export default {
  filters: {
    statusFilter(status) {
      const statusMap = {
        published: 'success',
        draft: 'gray',
        deleted: 'danger'
      }
      return statusMap[status]
    }
  },
  data() {
    return {
      list: null,
      listLoading: true,
      row: 5
    }
  },
  created() {
    this.$QtCallBackDict.getTableData = this.fetchData
  },
  mounted() {
    this.getTableData()
  },
  methods: {
    fetchData(table_data) {
      this.list = table_data
      this.listLoading = false
    },
    getTableData() {
      console.log(this.$QtWebChannel)
      this.$request('getTableData', { row: this.row })
      this.listLoading = true
    }
  }
}
</script>

2.4 自此WEB端修改完毕 npm run dev启动即可

3. PYTHON端开发

项目结构如下 绿色的是需要的

在这里插入图片描述

3.1 主函数入口

调用nodejs的服务器进行远程调试 主函数

#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

"""
@File    : demo_vue_element.py
@Author  : Link
@Time    : 2021/4/17 9:49
"""


import sys

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl, QTimer
from VueElementObject import VueElementObject
from PyQt5.QtWebChannel import QWebChannel


# 创建一个 application实例
app = QApplication(sys.argv)
win = QWidget()
win.setWindowTitle('Web页面中的JavaScript与 QWebEngineView交互例子')

# 创建一个垂直布局器
layout = QVBoxLayout()
win.setLayout(layout)

# 创建一个 QWebEngineView 对象
view = QWebEngineView()

htmlUrl = 'http://localhost:9528/'

# from qweb.dist import src_ui

# htmlUrl = 'qrc:/index.html'

channel = QWebChannel()
myObj = VueElementObject()
channel.registerObject("bridge", myObj)

view.load(QUrl(htmlUrl))

# 创建一个 QWebChannel对象,用来传递pyqt参数到JavaScript
view.page().setWebChannel(channel)


# 把QWebView和button加载到layout布局中
layout.addWidget(view)
# 显示窗口和运行app
win.show()
sys.exit(app.exec_())

3.2 其他函数

3.2.1 与VUE交互的主要函数
#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

"""
@File    : VueElementObject.py
@Author  : Link
@Time    : 2021/4/17 12:11
"""

from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal

import json

from qweb.utils import returnFailure
from qweb.view.table import get_table_data


class VueElementObject(QObject):
    funcDict = {}
    connectSignal = pyqtSignal(str)

    def __init__(self):
        super(VueElementObject, self).__init__()
        self.table_init()

    def table_init(self):
        self.funcDict["getTableData"] = get_table_data

    # @call_back_vue  # 不能加上装饰 装饰器加上了后 在前端不会有request Object
    @pyqtSlot(str)
    def request(self, req: str):
        print(req)
        try:
            request_data = json.loads(req)
            func = request_data.get("func", None)
            if func is None:
                raise Exception("没有传入[func]函数名")
            if func not in self.funcDict:
                raise Exception("QT中不存在此函数用于调用")
            data = self.funcDict[func](request_data)
            if data is None:
                return
            if not isinstance(data, str):
                raise Exception("返回值必须是一个json字符串类型")
            self.connectSignal.emit(data)
        except Exception as err:
            self.connectSignal.emit(returnFailure(str(err)))
3.2.2 与返回给VUE端的数据结构
#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

"""
@File    : utils.py
@Author  : Link
@Time    : 2021/4/17 12:48
"""
import json


def returnSuccess(message, **kwargs):
    return json.dumps({"data": kwargs, "message": message, 'code': 200})


def returnFailure(message, **kwargs):
    return json.dumps({"data": kwargs, "message": message, 'code': 400})
3.2.3 和VUE table页面交互的函数
#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

"""
@File    : table.py
@Author  : Link
@Time    : 2021/4/17 13:46
"""

from faker import Faker

from qweb.utils import returnSuccess

fake = Faker()


def generator_table(row: int):
    data = []
    for i in range(row):
        data.append({
            'id': i,
            'title': fake.text(),
            'author': fake.name(),
            'display_time': fake.date_time().strftime("%Y-%m-%d %H:%M:%S"),
            'pageviews': fake.random_int(),
            'status': fake.random_sample(['published', 'draft', 'deleted'], 1)[0]
        })
    return data


def get_table_data(req: dict):
    if req["func"] != 'getTableData':
        raise Exception("func error")
    return returnSuccess("success", func=req["func"], data=generator_table(req["data"]["row"]))

4.开发调试

在这里插入图片描述

5.完成打包

5.1 打包web端

使用vue-element-admin配置的打包命令 npm run build:prod 进行打包

在这里插入图片描述

打包后的项目文件如图 没有src.qrc哦 接下来就需要创建qrc文件

5.2 使用QT QRC文件打包web项目

在WEB项目打包后的位置 使用QT设计师 新建一个qrc文件
在这里插入图片描述

以/ 为前缀只添加一个路径

在这里插入图片描述

然后手动从各个文件夹 全部引入到qrc文件中如图

在这里插入图片描述

在这里插入图片描述

5.3 完成QRC文件的创建

qrc文件结构

<RCC>
  <qresource prefix="/">
    <file>favicon.ico</file>
    <file>index.html</file>
    <file>static/css/app.949a0224.css</file>
    <file>static/css/chunk-61dbd1f1.9a9361c6.css</file>
    <file>static/css/chunk-73d31757.c58e968f.css</file>
    <file>static/css/chunk-385e7a5c.3c7f5ad9.css</file>
    <file>static/css/chunk-76391674.94702ff7.css</file>
    <file>static/css/chunk-elementUI.68c70ad5.css</file>
    <file>static/css/chunk-libs.3dfb7769.css</file>
    <file>static/fonts/element-icons.535877f5.woff</file>
    <file>static/fonts/element-icons.732389de.ttf</file>
    <file>static/img/404.a57b6f31.png</file>
    <file>static/img/404_cloud.0f4bc32b.png</file>
    <file>static/js/app.addc5b1b.js</file>
    <file>static/js/chunk-2d0c8bf7.0b0747b8.js</file>
    <file>static/js/chunk-2d0cfaef.f8c4497e.js</file>
    <file>static/js/chunk-2d0d0f79.fd0ef435.js</file>
    <file>static/js/chunk-2d0e4b0c.e753d0e8.js</file>
    <file>static/js/chunk-2d0e4e1f.e61c70fd.js</file>
    <file>static/js/chunk-2d0e944c.acc12e3a.js</file>
    <file>static/js/chunk-2d226cab.bb682c8f.js</file>
    <file>static/js/chunk-2d2104c6.a3d40e6f.js</file>
    <file>static/js/chunk-61dbd1f1.beca85de.js</file>
    <file>static/js/chunk-73d31757.6e68b9ff.js</file>
    <file>static/js/chunk-385e7a5c.d1dde1bb.js</file>
    <file>static/js/chunk-772faed3.b6b0959c.js</file>
    <file>static/js/chunk-76391674.8f3ab814.js</file>
    <file>static/js/chunk-elementUI.e8701db4.js</file>
    <file>static/js/chunk-libs.7506166c.js</file>
  </qresource>
</RCC>

5.4 集成封装

使用如下命令 pyrcc5.exe src.qrc -o src_ui.py 将src.qrc文件转为py文件

并将 src_ui.py 文件放入Python项目中引入,最终目录结构和代码如图
在这里插入图片描述

OK直接运行 可以启动后 就可以使用pyinstaller进行打包exe分发了 本人打包后是140M 比electron要小点 但是运气起来感觉不是很好看。。。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐