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:
on_combo_selected()
est appelée dans mon script Python, qui récupère ensuite des données.Comment puis-je faire ceci?
Façons de communiquer à partir d'un widget WebKit incorporé avec le programme Python de contrôle
Gtk ou Qt:
window.status
à partir de JavaScript; piège l'événement correspondant en Pythondocument.title
à partir de JavaScript; piège l'événement correspondant en Pythonx-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:
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 http://pysnippet.blogspot.com/2010/01/calling-python-from-javascript-in-pyqts.html pour un exemple.)Méthodes qui devraient théoriquement fonctionner mais ne fonctionnent pas très bien dans la pratique
Façons de communiquer de Python en JavaScript
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()
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!';")