第六国际 2024-07-09 15:46 采纳率: 58.3%
浏览 12
已结题

Pyqt5 中QWebEngineView 使用QWebChannel ,无法与python 端进行数据交互

Pyqt5 中QWebEngineView与QWebChannel封装进函数里使用,会导致页面访问Python 端失效,不封装在一起,直接在主函数使用是没问题的。(我们实际应用场景是把QWebEngineView与QWebChannel这部分代码放到一个单独的Qtab里面运行,所以不能直接放在主函数里,要封装起来)

这是我的页面代码

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <script src="./qwebchannel.js"></script>
  <script type="text/javascript" src="./vue.min.js"></script>
</head>
<body>
  <h1>Python-Vue 交互测试</h1>
  <div id='app'>
    <input type='button' @click="queryProductInfo" value="产品信息">
  </div>
  <script>
    new Vue({
      el: '#app',
      mounted() {
        // 确保 qwebchannel.js 加载完成
        if (typeof qt !== 'undefined') {
          window.channel = new QWebChannel(qt.webChannelTransport, (channel) => {
            window.py_object = channel.objects.python_object;
            console.log("QWebChannel connected");
          });
        } else {
          alert("qc对象未获取到!");
        }
      },
      methods: {
        queryProductInfo(){
          if (window.py_object) {
            window.py_object.queryProductInfo();
          } else {
            console.error("Python object not available");
          }
        },
      }
    })
    window.onQueryProductInfo = function(info){
      alert(info)
      console.log(info)
    }
  </script>
</body>
</html>

这是我的python代码

from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWebChannel import QWebChannel
import json
from SQLiteUtil import SqliteTool
import sys
import os


class PythonToJS(QObject):
    mySqlite = SqliteTool()

    def __init__(self, view):
        super().__init__()
        self.view = view

    # 获取产品信息
    @pyqtSlot()
    def queryProductInfo(self):
        # # 查询数据
        print('queryProductInfo')
        obj = json.dumps("hello, world", ensure_ascii=False)
        self.view.page().runJavaScript('%s(%s)' % ('onQueryProductInfo', obj))

# 把QWebEngineView与QWebChannel封装进函数里使用
def view():
    view = QWebEngineView()
    channel = QWebChannel()
    python_object = PythonToJS(view)
    channel.registerObject("python_object", python_object)
    view.page().setWebChannel(channel)
    curdir = os.getcwd()
    url = os.path.join(curdir, 'qtweb.html')
    view.load(QUrl.fromLocalFile(url))
    return view



if __name__ == "__main__":
    app = QApplication(sys.argv)
    # view = QWebEngineView()
    # channel = QWebChannel()
    # python_object = PythonToJS(view)
    # channel.registerObject("python_object", python_object)
    # view.page().setWebChannel(channel)
    # curdir = os.getcwd()
    # url = os.path.join(curdir, 'qtweb.html')
    # view.load(QUrl.fromLocalFile(url))
    view = view()
    view.show()
    sys.exit(app.exec_())

如果直接使用注释部分,而不是通过封装的函数使用QWebChannel,则是正常的

img

下面是正常运行的结果

img

  • 写回答

7条回答 默认 最新

  • 叫兽-郭老师 Java领域新星创作者 2024-07-09 15:59
    关注

    🕒下午好,题主!目前:🟢[在线]
    📢参考通义千问、由郭老师整理提供!
    📣今日诗号:惆怅东栏一株雪,人生看得几清明。

    你遇到的问题是由于 Python 的垃圾回收机制导致的。当你在函数 view() 内部创建 PythonToJS 对象,并将其注册到 QWebChannel 后,函数结束时,python_object 就会被垃圾回收器回收,从而导致网页无法再访问到该对象。

    以下是两种解决方案:

    方案一:使用 self 保存 PythonToJS 对象的引用

    PythonToJS 对象作为主窗口类的一个成员变量,这样可以避免其被垃圾回收。

    from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtSignal
    from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
    from PyQt5.QtWebEngineWidgets import QWebEngineView
    from PyQt5.QtWebChannel import QWebChannel
    import json
    # from SQLiteUtil import SqliteTool
    import sys
    import os
    
    class PythonToJS(QObject):
        # mySqlite = SqliteTool()
        def __init__(self, view):
            super().__init__()
            self.view = view
    
        # 获取产品信息
        @pyqtSlot()
        def queryProductInfo(self):
            # # 查询数据
            print('queryProductInfo')
            obj = json.dumps("hello, world", ensure_ascii=False)
            self.view.page().runJavaScript('%s(%s)' % ('onQueryProductInfo', obj))
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
    
            self.view = QWebEngineView()
            self.channel = QWebChannel()
            self.python_object = PythonToJS(self.view)  # 保存为成员变量
            self.channel.registerObject("python_object", self.python_object)
            self.view.page().setWebChannel(self.channel)
    
            curdir = os.getcwd()
            url = os.path.join(curdir, 'qtweb.html')
            self.view.load(QUrl.fromLocalFile(url))
    
            self.setCentralWidget(self.view)
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        window = MainWindow()
        window.show()
        sys.exit(app.exec_())
    

    方案二:使用 setParent 设置父对象

    在创建 PythonToJS 对象时,将其父对象设置为 view,这样 PythonToJS 对象的生命周期就会与 view 绑定。

    # ... 其他代码 ...
    
    def view():
        view = QWebEngineView()
        channel = QWebChannel()
        python_object = PythonToJS(view)
        python_object.setParent(view)  # 设置父对象
        channel.registerObject("python_object", python_object)
        view.page().setWebChannel(channel)
        curdir = os.getcwd()
        url = os.path.join(curdir, 'qtweb.html')
        view.load(QUrl.fromLocalFile(url))
        return view
    
    # ... 其他代码 ...
    

    两种方案都可以解决问题,建议根据实际情况选择合适的方案。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(6条)

报告相同问题?

问题事件

  • 系统已结题 7月17日
  • 已采纳回答 7月9日
  • 赞助了问题酬金20元 7月9日
  • 修改了问题 7月9日
  • 展开全部

悬赏问题

  • ¥15 安装quartus II18.1时弹出此error,怎么解决?
  • ¥15 想用adb命令做一个通话软件,播放录音
  • ¥30 Pytorch深度学习服务器跑不通问题解决?
  • ¥15 部分客户订单定位有误的问题
  • ¥15 如何在maya程序中利用python编写领子和褶裥的模型的方法
  • ¥15 Bug traq 数据包 大概什么价
  • ¥15 在anaconda上pytorch和paddle paddle下载报错
  • ¥25 自动填写QQ腾讯文档收集表
  • ¥15 DbVisualizer Pro 12.0.7 sql commander光标错位 显示位置与实际不符
  • ¥15 android 打包报错