Hubungkan formulir WebKit WebView ke panggilan balik Python?

31

Saya sedang menulis aplikasi Python dan WebKit kecil; Saya menggunakan WebKit sebagai UI untuk aplikasi saya.

Apa yang ingin saya lakukan adalah membuat elemen interaktif di WebKit (yaitu kotak kombo atau set wilayah yang dapat diklik) dan ketika pengguna berinteraksi dengan elemen-elemen ini saya dapat memanggil panggilan balik Python untuk melakukan beberapa pemrosesan dan kemudian memperbarui tampilan WebKit dengan informasi baru.

Ini adalah contoh dari apa yang ingin saya lakukan:

  1. Pengguna disajikan dengan kotak kombo opsi (kotak kombo ditampilkan, saya berasumsi, menggunakan formulir HTML di WebKit).
  2. Ketika opsi kotak kombo dipilih, on_combo_selected()dipanggil dalam skrip Python saya yang kemudian mengambil beberapa data.
  3. Data diteruskan ke WebKit dan tampilan diperbarui.

Bagaimana saya bisa melakukan ini?

jonobacon
sumber

Jawaban:

31

Cara berkomunikasi dari widget WebKit yang disematkan ke program Python yang mengendalikan

GTK atau Qt:

  • diatur window.statusdari JavaScript; menjebak acara terkait dengan Python
  • diatur document.titledari JavaScript; menjebak acara terkait dengan Python
  • redirect halaman ke URL khusus (katakanlah, x-my-app:thing1/thing2/thing3); perangkap navigation-policy-decision-requestedacara di Python dan lihat URL yang dinavigasi, dan atasi jika itu skema URL khusus Anda

Hanya qt:

Metode yang secara teoretis harus bekerja tetapi dalam praktiknya tidak, sangat baik

  • Menayangkan acara DOM khusus pada elemen HTML (yang akan menyertakan objek dokumen) dari JavaScript; menjebak peristiwa itu di Python dengan menavigasi DOM WebKit dari Python dan mendengarkan acara. Ini berfungsi, tetapi saya tidak dapat menemukan cara agar Python dapat membaca data khusus dari acara tersebut, yang berarti Anda tidak dapat meneruskan informasi selain dari acara yang dipecat.

Cara berkomunikasi dari Python ke JavaScript

  • gunakan webview.execute_script(js_code). Perhatikan bahwa jika Anda meneruskan nilai variabel dengan JS, itu ide yang baik untuk menyandikan JSON; dengan cara itu Anda bisa sedikit khawatir tentang melarikan diri, dan JS dapat membaca JSON secara asli

Berikut ini beberapa contoh kode 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()
sil
sumber
18

Sudah lama sejak saya bermain dengan itu tetapi inilah yang saya lakukan:

Gunakan sesuatu seperti

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

dalam HTML Anda. Jadi ketika pengguna memilih item a mycombo-URI dengan nilai yang dipilih dipanggil. Untuk menangkap ini hubungkan handler ke navigation-requestedsinyal WebView Anda :

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

Di penangan sinyal Anda, Anda memeriksa apakah permintaan untuk mycomboURI. Jika demikian panggil 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

Untuk memperbarui WebView Anda gunakan execute_scriptfungsinya untuk menjalankan beberapa kode JavaScript yang melakukan pembaruan, seperti:

self.webview.execute_script("document.title='Updated!';")
Florian Diesch
sumber
1
Adakah yang tahu cara mengambil tajuk pos req?
Flimm