PyQt - JavaScript 交互

本文介绍了如何在PyQt应用中实现Python与JavaScript的交互,通过QWebChannel对象定义、注册、引入交互文件以及在js页面加载事件中绑定,详细展示了交互过程。包括槽函数、信号的使用,以及Demo中的main.py、Ui_main.py、index.html和qwebchannel.js文件的示例。

PyQt - JavaScript 交互

先上图看效果
1176578-20181202121620416-455360562.gif

1. Python中定义QWebChannel对象

  • 槽函数
    接收js发射的信号

  • 信号
    在js中绑定一个js方法
class TInteractObj(QObject):
    """
    一个槽函数供js调用(内部最终将js的调用转化为了信号),
    一个信号供js绑定,
    这个一个交互对象最基本的组成部分.
    """

    # 定义信号,该信号会在js中绑定一个js方法.
    sig_send_to_js = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        # 交互对象接收到js调用后执行的回调函数.
        self.receive_str_from_js_callback = None

    # str表示接收str类型的信号,信号是从js发出的.
    @pyqtSlot(str)
    def receive_str_from_js(self, str):
        self.receive_str_from_js_callback(str)

2. Python中注册QWebChannel对象

注册方法

    def init_channel(self):
        """
        为webview绑定交互对象
        """
        self.interact_obj = TInteractObj(self)
        self.interact_obj.receive_str_from_js_callback = self.receive_data

        channel = QWebChannel(self.webview.page())
        # interact_obj 为交互对象的名字,js中使用.
        channel.registerObject("interact_obj", self.interact_obj)

        self.webview.page().setWebChannel(channel)

3. html中引入交互文件

<script type="text/javascript" src="qwebchannel.js"></script>

4. js页面加载事件(windows.onload)中进行绑定

  1. 获取交互对象
  2. 绑定
  • 事件->交互对象->对象上的槽函数
  • 交互对象->信号-> js 函数
<script type="text/javascript">
        window.onload = function () {
            new QWebChannel(qt.webChannelTransport, function (channel) {
                // 获取qt中绑定的交互对象
                window.pyjs = channel.objects.interact_obj

                // js 绑定qt中的信号
                pyjs.sig_send_to_js.connect(function (str) {
                    document.getElementById("output").value = str;
                });

                // 按钮点击事件
                document.getElementById("send").onclick = function () {
                    var text_area = document.getElementById("output");
                    if (!text_area.value) {
                        return;
                    }
                    // js调用qt中的方法
                    pyjs.receive_str_from_js(text_area.value)
                    text_area.value = "";
                }
            });
        }
    </script>

5. Demo

main.py

import os
import sys

from PyQt5.QtCore import QUrl, pyqtSlot, QObject, pyqtSignal
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWidgets import QMainWindow, QApplication

from Ui_main import Ui_MainWindow


class TInteractObj(QObject):
    """
    一个槽函数供js调用(内部最终将js的调用转化为了信号),
    一个信号供js绑定,
    这个一个交互对象最基本的组成部分.
    """

    # 定义信号,该信号会在js中绑定一个js方法.
    sig_send_to_js = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        # 交互对象接收到js调用后执行的回调函数.
        self.receive_str_from_js_callback = None

    # str表示接收str类型的信号,信号是从js发出的.
    @pyqtSlot(str)
    def receive_str_from_js(self, str):
        self.receive_str_from_js_callback(str)


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)

        self.index = (os.path.split(os.path.realpath(__file__))[0]) + "/index.html"
        self.webview.load(QUrl.fromLocalFile(self.index))
        self.init_channel()

    def init_channel(self):
        """
        为webview绑定交互对象
        """
        self.interact_obj = TInteractObj(self)
        self.interact_obj.receive_str_from_js_callback = self.receive_data

        channel = QWebChannel(self.webview.page())
        # interact_obj 为交互对象的名字,js中使用.
        channel.registerObject("interact_obj", self.interact_obj)

        self.webview.page().setWebChannel(channel)

    def receive_data(self, data):
        self.textBrowser.setText(data)

    @pyqtSlot()
    def on_pushButton_clicked(self):
        if not self.textBrowser.toPlainText():
            return
        # 这个信号是在js中和一个js方法绑定的,所以发射这个信号时会执行对应的js方法.
        self.interact_obj.sig_send_to_js.emit(self.textBrowser.toPlainText())
        self.textBrowser.clear()


if __name__ == '__main__':
    app = QApplication(sys
<think>我们正在使用PyQt5的QWebEngineView来加载网页,并实现与网页中的JavaScript交互,以及通过Java后端服务进行数据交互。由于PyQt5的QWebEngineView是基于Chromium的,它支持与网页中的JavaScript进行双向交互。步骤概述:1.在PyQt5中嵌入QWebEngineView来加载网页。2.使用PyQt5调用网页中的JavaScript函数。3.在网页中通过JavaScript调用PyQt5中的Python方法(通过将Python对象暴露给JavaScript)。4.与Java后端的交互:可以通过网页中的JavaScript发起Ajax请求与Java后端通信,或者通过PyQt5的Python代码直接与Java后端通信(例如使用requests库),然后将结果传递给网页。具体实现:一、PyQt5调用网页JavaScript我们可以使用`QWebEngineView`的`page().runJavaScript()`方法来执行网页中的JavaScript代码。二、网页JavaScript调用PyQt5我们需要创建一个继承自`QObject`的类,并将这个类的实例暴露给JavaScript上下文。然后在这个类中定义一些可以被JavaScript调用的方法(使用`@pyqtSlot`装饰器)。三、与Java后端的交互有两种方式:a)在网页的JavaScript中直接发起请求到Java后端(例如使用fetch或XMLHttpRequest)。b)在PyQt5的Python代码中发起请求(例如使用requests库),然后将数据通过调用网页JavaScript函数传递回网页,或者通过暴露给JavaScript的方法来传递。下面是一个示例,展示如何在PyQt5中实现与网页的交互,并间接与Java后端通信。示例代码:"""import sysfromPyQt5.QtCoreimport QUrl, QObject,pyqtSlotfrom PyQt5.QtWidgetsimport QApplication,QMainWindow,QVBoxLayout, QWidget,QPushButtonfrom PyQt5.QtWebEngineWidgetsimport QWebEngineView#创建一个用于暴露给JavaScript的类class WebBridge(QObject):def__init__(self, parent=None):super().__init__(parent)#定义一个可以被JavaScript调用的方法@pyqtSlot(str)defshowMessage(self,message):print("Messagefrom JavaScript:", message)#从Java后端获取数据(这里模拟通过Python请求Java后端,然后将数据传递给JavaScript)@pyqtSlot()def fetchDataFromJavaBackend(self):#这里我们模拟一个请求Java后端的操作,实际中可以使用requests库#假设我们从Java后端获取到一个字符串data= "Datafrom Javabackend viaPython"#将数据传递回网页,我们可以通过调用网页中的JavaScript函数来实现#注意:这里我们需要知道网页中有一个名为`receiveDataFromPython`的JavaScript函数self.parent().page().runJavaScript(f"receiveDataFromPython('{data}')")class MainWindow(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("PyQt5 WebInteraction Example")self.setGeometry(100,100,800,600)layout =QVBoxLayout()#创建一个WebEngineViewself.browser= QWebEngineView()#加载一个本地HTML文件或者远程URLself.browser.load(QUrl.fromLocalFile("path/to/your/html/file.html"))#请替换为你的HTML文件路径#或者加载远程URL:self.browser.load(QUrl("http://example.com"))#创建WebBridge对象,并暴露给JavaScriptself.bridge =WebBridge(self.browser)#将对象暴露给JavaScript,命名为'pyBridge'self.browser.page().setWebChannel(self.bridge)#创建一个按钮,用于触发调用网页中的JavaScript函数self.button= QPushButton("CallJavaScript Function")self.button.clicked.connect(self.call_js_function)layout.addWidget(self.button)layout.addWidget(self.browser)container= QWidget()container.setLayout(layout)self.setCentralWidget(container)def call_js_function(self):#调用网页中的JavaScript函数,例如我们有一个名为`greet`的函数self.browser.page().runJavaScript("greet('Hellofrom PyQt5!')")if __name__== "__main__":app= QApplication(sys.argv)window= MainWindow()window.show()sys.exit(app.exec_()) """在HTML文件中,我们需要引入Qt的WebChannel库,并设置与PyQt5的通信。示例HTML文件(假设为index.html): ```<!DOCTYPEhtml><html><head><meta charset="UTF-8"><title>PyQt5Web Interaction</title><!--引入qwebchannel.js,这个文件通常可以在Qt的安装目录中找到,或者从PyQt5的示例中获取--><scriptsrc="qwebchannel.js"></script></head> <body><h1>PyQt5 andJavaScript Interaction</h1><button onclick="callPyQtMethod()">Call PyQt Method</button><buttononclick="callFetchData()">FetchData fromJava viaPython</button><script>varpyBridge;//初始化WebChannelnewQWebChannel(qt.webChannelTransport, function(channel) {pyBridge =channel.objects.pyBridge;});//定义一个函数,供PyQt5调用function greet(message){alert(message);}//定义一个函数,供PyQt5调用(接收数据)functionreceiveDataFromPython(data){alert("Received datafrom Python: "+ data);}//调用PyQt5的方法function callPyQtMethod(){if (pyBridge) {pyBridge.showMessage("Hello fromJavaScript!");}}//调用PyQt5的方法来获取Java后端数据functioncallFetchData(){if (pyBridge) {pyBridge.fetchDataFromJavaBackend();}}</script></body> </html>```注意:1.你需要将`qwebchannel.js`文件放在与HTML文件相同的目录下。这个文件可以从PyQt5的安装目录中获取(例如在Python的site-packages中搜索),或者从Qt的安装目录中获取(例如在Qt的examples中)。2.在HTML中,我们通过`QWebChannel`来获取PyQt5暴露的对象`pyBridge`,然后就可以调用它的方法了。与Java后端的交互:在示例中,我们通过PyQt5中的Python代码模拟了从Java后端获取数据,然后通过调用网页的JavaScript函数将数据传递回网页。当然,你也可以直接在网页的JavaScript中通过Ajax请求Java后端(这样就不需要经过Python),例如:```function fetchDataFromJavaDirectly(){//假设Java后端提供了一个REST APIfetch('http://localhost:8080/api/data').then(response =>response.json()).then(data =>{console.log(data);//处理数据});} ```选择哪种方式取决于你的需求:-如果数据需要经过Python处理,那么通过PyQt5获取再传递给网页是合适的。 -如果网页可以直接访问Java后端,那么直接在JavaScript中发起请求更简单。安全提示:由于跨域问题,如果Java后端不在同一个域,可能需要配置CORS。希望这个示例能帮助你实现PyQt5中网页与Java和JavaScript交互。相关问题:1.如何在PyQt5中加载本地HTML文件并执行其中的JavaScript?2.如何解决PyQt5的WebEngineView与JavaScript交互时的跨域问题?3.在PyQt5中,如何将Python对象暴露给JavaScript,并允许JavaScript调用Python方法?4.如何从PyQt5的Python代码中调用网页中的JavaScript函数?</think>在PyQt5中实现网页与Java和JavaScript交互,主要涉及三种技术协同工作。以下是清晰的分步实现方案: ### 一、核心交互机制 1. **PyQt5 ↔ JavaScript** 使用`QWebChannel`实现双向通信: ```python # 创建通信通道 from PyQt5.QtWebChannel import QWebChannel channel = QWebChannel() # 暴露Python对象给JS class Bridge(QObject): @pyqtSlot(str, result=str) def py_call_js(self, data): return "Python处理: " + data bridge = Bridge() channel.registerObject("pyBridge", bridge) browser.page().setWebChannel(channel) # browser是QWebEngineView实例 ``` 2. **JavaScript ↔ Java** 通过HTTP/RESTful API通信: ```javascript // 在网页JS中调用Java后端 fetch('http://localhost:8080/java-api', { method: 'POST', body: JSON.stringify({action: "getData"}) }) .then(response => response.json()) .then(data => pyBridge.py_call_js(data)); ``` 3. **Java ↔ Python** 使用Socket或HTTP通信: ```java // Java服务端示例 @RestController public class ApiController { @PostMapping("/java-api") public ResponseEntity<?> handleRequest(@RequestBody Map<String, String> request) { String result = "Java处理: " + request.get("action"); return ResponseEntity.ok(result); } } ``` ### 二、完整工作流程 1. **PyQt5加载网页** ```python browser = QWebEngineView() browser.load(QUrl("http://localhost:5000")) # 加载本地或远程网页 ``` 2. **网页触发交互** ```html <button onclick="callJava()">调用Java服务</button> <script> function callJava() { fetch('/java-api', { method: 'POST' }) .then(res => res.text()) .then(data => pyBridge.py_call_js(data)); } </script> ``` 3. **Python处理返回数据** ```python class Bridge(QObject): @pyqtSlot(str) def display_result(self, result): print("最终结果:", result) # 更新PyQt5界面 self.label.setText(result) ``` ### 三、关键技术点 1. **跨域问题解决** - Java端添加CORS支持: ```java @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("*"); } }; } ``` 2. **数据类型转换** | 方向 | 技术 | 数据格式 | |---|---|---| | PyQt5↔JS | JSON | 自动转换基础类型 | | JS↔Java | HTTP | JSON/XML | | Java↔Python | Socket | 字节流需手动序列化 | 3. **异步处理** ```python # Python端使用信号机制 class Bridge(QObject): resultReceived = pyqtSignal(str) @pyqtSlot(str) def handle_js(self, data): self.resultReceived.emit(data) ``` ### 四、应用场景示例 1. **图书馆管理系统** - PyQt5桌面端展示图书列表 - JavaScript实现动态搜索 - Java后端处理数据库查询 - Python整合数据生成报表[^3] 2. **金融分析工具** - PyQt5展示实时图表 - JavaScript计算前端指标 - Java风控引擎处理交易 - Python进行机器学习预测 > **注意**:实际开发中需确保各服务端口不冲突(建议Python用5000,Java用8080),并使用`QWebEngineView`的`loadFinished`信号确保页面完全加载后再初始化通信[^4]。 --- ### 相关问题 1. 如何在PyQt5中捕获JavaScript的console输出? 2. 如何实现Java和Python之间的二进制数据传输? 3. 在跨平台应用中如何处理不同操作系统的路径差异? 4. 如何确保PyQt5与网页通信时的数据安全性? [^1]: Django框架可快速构建Python Web服务作为中间层 [^2]: Java后端采用RESTful API设计确保接口规范性 [^3]: 系统集成参考多层架构设计模式 [^4]: QWebEngineView的异步加载机制需要特殊处理
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值