Підключити форму WebKit WebView до зворотного дзвінка Python?


31

Я пишу невеликий додаток Python та WebKit; Я використовую WebKit як інтерфейс користувача для свого додатка.

Що я хочу зробити, це створити інтерактивний елемент у WebKit (а саме - поле для комбінації або набір регіонів, на яких можна натиснути), і коли користувач взаємодіє з цими елементами, я можу викликати зворотний виклик Python, щоб зробити деяку обробку, а потім оновити подання WebKit за допомогою нова інформація.

Ось приклад того, що я хочу зробити:

  1. Користувачеві представлено комбінований вікно параметрів (відображається комбінований ящик, я припускаю, використовуючи HTML-форму в WebKit).
  2. Коли вибрано параметр комбінованого вікна, on_combo_selected()в моєму сценарії Python викликається який потім захоплює деякі дані.
  3. Дані передаються WebKit, а представлення оновлюється.

Як я можу це зробити?

Відповіді:


31

Способи спілкування від вбудованого віджета WebKit до керуючої програми Python

Gtk або Qt:

  • набір window.statusвід JavaScript; пастка відповідної події в Python
  • набір document.titleвід JavaScript; пастка відповідної події в Python
  • перенаправити сторінку на власну URL-адресу (скажімо, x-my-app:thing1/thing2/thing3); відловлювати navigation-policy-decision-requestedподію в Python та переглядати URL-адресу, до якої перебуває, і вирішувати це, якщо це ваша спеціальна схема URL-адрес

Qt:

Методи, які теоретично повинні працювати, але на практиці це не дуже добре

  • Запустити спеціальну подію DOM на елемент HTML (який би включав об’єкт документа) з JavaScript; вловлювати цю подію в Python, переміщаючись по DOM WebKit від Python та слухаючи події. Це працює, але я не можу знайти спосіб, щоб 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()

18

Минув час, коли я грав із цим, але ось що я зробив:

Використовуйте щось подібне

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

у вашому HTML. Отже, коли користувач вибирає елемент, викликається mycombo-URI з обраним значенням. Щоб зафіксувати це, підключіть обробник до navigation-requestedсигналу вашого WebView :

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

У своєму обробнику сигналу ви перевіряєте, чи запит призначений для mycomboURI. Якщо так, дзвоніть 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

Щоб оновити веб-перегляд, використовуйте його execute_scriptфункцію для запуску деякого коду JavaScript, який виконує оновлення, наприклад:

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

1
Будь-яка ідея, як отримати заголовки публікацій req?
Flimm
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.