Connectez le formulaire WebKit WebView à un rappel Python?

31

J'écris une petite application Python et 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 un traitement Vue WebKit avec de nouvelles informations.

Voici un exemple de ce que je veux faire:

  1. L'utilisateur se voit proposer une combo d'options (combo, je suppose, avec un formulaire HTML dans WebKit).
  2. Lorsque l’option de la liste déroulante est sélectionnée, on_combo_selected() est appelé dans mon script Python, qui saisit ensuite certaines données.
  3. Les données sont transmises à WebKit et la vue est mise à jour.

Comment puis-je le faire?

    
posée jonobacon 21.01.2012 - 21:28
la source

2 réponses

30

Façons de communiquer depuis un widget WebKit intégré vers 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 ); piège l'événement navigation-policy-decision-requested dans Python et examine l'URL vers laquelle il navigue, et traite-le s'il s'agit de votre schéma d'URL personnalisé

Qt uniquement:

  • utilisez frame.addToJavaScriptWindowObject pour ajouter un objet Python (spécialement conçu) à l'espace de noms global JavaScript; appeler des méthodes à partir de JavaScript. (Voir lien pour un exemple.)

Les méthodes qui devraient théoriquement fonctionner mais en pratique ne le font pas très bien

  • Lancer un événement DOM personnalisé sur un élément HTML (qui inclurait l’objet du document) à partir de JavaScript; piège 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 peux pas trouver un moyen de permettre à Python de lire des données personnalisées à partir de l'événement, ce qui signifie que vous ne pouvez pas transmettre d'informations autres que l'événement ayant été déclenché.

Façons de communiquer de Python à JavaScript

  • utilise 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; Ainsi, JS peut lire JSON de manière native

Voici un exemple 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()
    
réponse donnée sil 22.01.2012 - 22:04
la source
18

Ça fait un moment que je n'ai pas joué 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 ceci, 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 oui, 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 pour exécuter du code JavaScript qui effectue les mises à jour, comme:

self.webview.execute_script("document.title='Updated!';")
    
réponse donnée Florian Diesch 21.01.2012 - 22:37
la source

Lire d'autres questions sur les étiquettes