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

31

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

Я хочу создать интерактивный элемент в WebKit (а именно, поле со списком или набор областей, по которым можно кликать), и когда пользователь взаимодействует с этими элементами, я могу вызвать обратный вызов Python для некоторой обработки, а затем обновить представление WebKit с помощью новая информация.

Вот пример того, что я хочу сделать:

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

Как я могу это сделать?

jonobacon
источник

Ответы:

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 с выбранным значением. Чтобы поймать это, подключите обработчик к сигналу вашего WebView navigation-requested:

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

Чтобы обновить ваш WebView, используйте его execute_scriptфункцию для запуска некоторого кода JavaScript, который выполняет обновления, например:

self.webview.execute_script("document.title='Updated!';")
Флориан Диш
источник
1
Есть идеи, как получить заголовки постов req?
Flimm