如何将WebKit WebView表单连接到Python回调函数?

我正在编写一个小型的Python和WebKit应用程序;我正在使用WebKit作为我的应用程序的用户界面。
我想要做的是在WebKit中创建一个交互式元素(比如一个下拉框或一组可点击的区域),当用户与这些元素进行交互时,我可以调用一个Python回调函数来进行一些处理,然后更新WebKit视图以显示新的信息。
以下是我想要实现的示例:
  1. 用户被呈现出一个选项的下拉框(我假设使用WebKit中的HTML表单来显示下拉框)。
  2. 当选择下拉框选项时,会在我的Python脚本中调用on_combo_selected()函数,然后获取一些数据。
  3. 数据传递给WebKit,视图得到更新。
我该如何实现这个功能?
2个回答

从嵌入式 WebKit 小部件到控制 Python 程序的通信方式

Gtk 或 Qt:

  • 通过 JavaScript 设置 window.status,在 Python 中捕获相应事件
  • 通过 JavaScript 设置 document.title,在 Python 中捕获相应事件
  • 将页面重定向到自定义 URL(例如,x-my-app:thing1/thing2/thing3),在 Python 中捕获 navigation-policy-decision-requested 事件并查看正在导航到的 URL,根据需要处理自定义 URL 方案

仅限于 Qt:

理论上应该有效但实际上效果不佳的方法

  • 在JavaScript中,通过在HTML元素上触发自定义DOM事件(包括文档对象),然后通过从Python中导航WebKit DOM并监听事件来捕获该事件。这种方法可以实现,但是我找不到一种让Python能够读取事件中的自定义数据的方法,这意味着除了事件已经触发之外,无法传递其他信息。

从Python向JavaScript传递信息的方法

  • 使用webview.execute_script(js_code)。请注意,如果您要将变量值与JS一起传递,请将其进行JSON编码;这样您就不用太担心转义问题,而且JS可以原生地读取JSON。

以下是一些Gtk代码示例:

from gi.repository import Gtk,WebKit
import json

w = Gtk.Window()
v = WebKit.WebView()
sw = Gtk.ScrolledWindow()
w.add(sw)
sw.add(v)
w.set_size_request(400,300)
w.connect("destroy", lambda q: Gtk.main_quit())
def window_title_change(v, param):
    if not v.get_title():
        return
    if v.get_title().startswith("msgtopython:::"):
        message = v.get_title().split(":::",1)[1]
        # Now, send a message back to JavaScript
        return_message = "You chose '%s'. How interesting." % message
        v.execute_script("jscallback(%s)" % json.dumps(return_message))
v.connect("notify::title", window_title_change)
v.load_html_string("""<!doctype html>
<html>
<head>
<title>A demo</title>
<style>
body { font-family: Ubuntu, sans-serif; }
h1 { font-size: 1.3em; }
</style>
<body>
<h1>A tiny JavaScript demonstration</h1>
<form>
<p>What's your favourite thing about Jono? <select>
    <option>------choose one------</option>
    <option>his beard</option>
    <option>his infectious sense of humour</option>
    <option>his infectious diseases</option>
    <option>his guitar ability</option>
    <option>his wife</option>
</select></p>
</form>
<p id="out"></p>

<script>
document.querySelector("select").addEventListener("change", function() {
    var chosenOption = this.options[this.selectedIndex].text;
    // Now send that text back to Python by setting the title
    document.title = "msgtopython:::" + chosenOption;
}, false);
function jscallback(msg) {
    document.getElementById("out").innerHTML = msg;
}
</script>

</body>
</html>
""", "file:///")
w.show_all()
Gtk.main()

我已经有一段时间没有和那个玩了,但这是我做的:

使用类似的东西

<form>
    <select  onchange="location.href='mycombo://'+this.value">
      <option>foo</option>
      <option>bar</option>
      <option>baz</option>
    </select>
</form>

在你的HTML中。因此,当用户选择一个项目时,将调用带有所选值的mycombo-URI。为了捕捉到这一点,将处理程序连接到您的WebView的navigation-requested信号:

self.webview.connect("navigation-requested", self.on_navigation_requested)

在你的信号处理程序中,你检查请求是否为mycombo URI。如果是,则调用on_combo_selected函数:
def on_navigation_requested(self, view, frame, req, data=None):
    uri = req.get_uri()
    scheme, path=uri.split(':', 1)
    if scheme == 'mycombo':
        self.on_combo_selected(path) 
        return True
    else:
        return False

要更新您的WebView,请使用其execute_script函数运行一些JavaScript代码来进行更新,例如:
self.webview.execute_script("document.title='Updated!';")

1有没有办法从 req 中获取帖子的头部信息? - Flimm