Kết nối biểu mẫu WebKit WebView với một cuộc gọi lại Python?


31

Tôi đang viết một ứng dụng Python và WebKit nhỏ; Tôi đang sử dụng WebKit làm giao diện người dùng cho ứng dụng của mình.

Điều tôi muốn làm là tạo một phần tử tương tác trong WebKit (cụ thể là hộp tổ hợp hoặc tập hợp các vùng có thể nhấp) và khi người dùng tương tác với các phần tử này, tôi có thể gọi một cuộc gọi lại Python để xử lý và sau đó cập nhật chế độ xem WebKit với thông tin mới.

Đây là một ví dụ về những gì tôi muốn làm:

  1. Người dùng được cung cấp một hộp tùy chọn kết hợp (hộp tổ hợp được hiển thị, tôi giả sử, sử dụng biểu mẫu HTML trong WebKit).
  2. Khi tùy chọn hộp tổ hợp được chọn, on_combo_selected()được gọi trong tập lệnh Python của tôi, sau đó lấy một số dữ liệu.
  3. Dữ liệu được truyền tới WebKit và chế độ xem được cập nhật.

Tôi có thể làm cái này như thế nào?

Câu trả lời:


31

Các cách để giao tiếp từ một tiện ích WebKit được nhúng đến chương trình Python kiểm soát

Gtk hoặc Qt:

  • được đặt window.statustừ JavaScript; bẫy sự kiện tương ứng trong Python
  • được đặt document.titletừ JavaScript; bẫy sự kiện tương ứng trong Python
  • chuyển hướng trang đến một URL tùy chỉnh (giả sử x-my-app:thing1/thing2/thing3); bẫy navigation-policy-decision-requestedsự kiện trong Python và xem URL đang được điều hướng đến và xử lý nó nếu đó là lược đồ URL tùy chỉnh của bạn

Chỉ Qt:

Các phương pháp mà về mặt lý thuyết nên hoạt động nhưng trong thực tế thì không, rất tốt

  • Bắn một sự kiện DOM tùy chỉnh trên một phần tử HTML (bao gồm đối tượng tài liệu) từ JavaScript; bẫy sự kiện đó trong Python bằng cách điều hướng WebKit DOM từ Python và lắng nghe các sự kiện. Điều này hoạt động, nhưng tôi không thể tìm ra cách để Python có thể đọc dữ liệu tùy chỉnh từ sự kiện, điều đó có nghĩa là bạn không thể truyền thông tin ngoài sự kiện đã phát sinh.

Các cách để giao tiếp từ Python sang JavaScript

  • sử dụng webview.execute_script(js_code). Lưu ý rằng nếu bạn chuyển các giá trị biến đổi với JS, thì nên mã hóa JSON; theo cách đó bạn có thể bớt lo lắng một chút về việc thoát và JS có thể đọc JSON nguyên bản

Dưới đây là một số ví dụ về mã 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()

18

Đã được một thời gian kể từ khi tôi chơi với nó nhưng đây là những gì tôi đã làm:

Sử dụng một cái gì đó như

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

trong HTML của bạn. Vì vậy, khi người dùng chọn một mục, một mycombo-URI với giá trị được chọn sẽ được gọi. Để nắm bắt điều này, hãy kết nối một trình xử lý với navigation-requestedtín hiệu WebView của bạn :

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

Trong trình xử lý tín hiệu của bạn, bạn kiểm tra xem yêu cầu có dành cho mycomboURI không. Nếu vậy hãy gọi 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

Để cập nhật WebView của bạn, hãy sử dụng execute_scriptchức năng của nó để chạy một số mã JavaScript thực hiện các bản cập nhật, như:

self.webview.execute_script("document.title='Updated!';")

1
Bất kỳ ý tưởng làm thế nào để lấy tiêu đề bài viết từ req?
Flimm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.