web-dev-qa-db-fra.com

Connecter le formulaire WebKit WebView à un rappel Python?

J'écris un petit Python et une application WebKit; J'utilise WebKit comme interface utilisateur pour mon application.

Ce que je veux faire est de créer un élément interactif dans WebKit (à savoir une liste déroulante ou un ensemble de régions cliquables) et lorsque l'utilisateur interagit avec ces éléments, je peux appeler un rappel Python pour effectuer certains traitements et puis mettez à jour la vue WebKit avec les nouvelles informations.

Voici un exemple de ce que je veux faire:

  1. L'utilisateur se voit présenter une liste déroulante d'options (la liste déroulante est affichée, je suppose, à l'aide d'un formulaire HTML dans WebKit).
  2. Lorsque l'option de liste déroulante est sélectionnée, on_combo_selected() est appelée dans mon script Python, qui récupère ensuite des données.
  3. Les données sont transmises à WebKit et la vue est mise à jour.

Comment puis-je faire ceci?

31
jonobacon

Façons de communiquer à partir d'un widget WebKit incorporé avec le programme Python de contrôle

Gtk ou Qt:

  • définir window.status à partir de JavaScript; piège l'événement correspondant en Python
  • définir document.title à partir de JavaScript; piège l'événement correspondant en Python
  • redirige la page vers une URL personnalisée (par exemple, x-my-app:thing1/thing2/thing3); intercepter l'événement navigation-policy-decision-requested dans Python et consulter l'URL vers laquelle on navigue, et s'en occuper s'il s'agit de votre modèle d'URL personnalisé

Qt seulement:

Méthodes qui devraient théoriquement fonctionner mais ne fonctionnent pas très bien dans la pratique

  • Déclenchez un événement DOM personnalisé sur un élément HTML (qui inclurait l'objet de document) à partir de JavaScript; capturez cet événement dans Python en naviguant dans le DOM WebKit à partir de Python et en écoutant les événements. Cela fonctionne, mais je ne trouve pas le moyen de permettre à Python de pouvoir lire des données personnalisées à partir de l'événement, ce qui signifie que vous ne pouvez pas transmettre d'autres informations que l'événement ayant été déclenché.

Façons de communiquer de Python en JavaScript

  • utilisez webview.execute_script(js_code). Notez que si vous transmettez des valeurs de variable avec le JS, c'est une bonne idée de les encoder en JSON; De cette façon, vous pouvez vous inquiéter un peu moins de vous échapper et JS peut lire JSON de manière native.

Voici quelques exemples de code 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()
31
sil

Cela fait longtemps que je joue avec ça, mais voici ce que j'ai fait:

Utilisez quelque chose comme

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

dans votre HTML. Ainsi, lorsque l'utilisateur sélectionne un élément, un mycombo-URI avec la valeur sélectionnée est appelé. Pour intercepter cela, connectez un gestionnaire au signal navigation-requested de votre WebView:

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

Dans votre gestionnaire de signal, vous vérifiez si la demande concerne un URI mycombo. Si c'est le cas, appelez 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

Pour mettre à jour votre WebView, utilisez sa fonction execute_script afin d’exécuter du code JavaScript effectuant les mises à jour, par exemple:

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