Phoenix
Phoenix copied to clipboard
wx.html2: event EVT_WEBVIEW_SCRIPT_RESULT and RunScriptAsync method
Operating system: Any wxPython version & source: 4.1.2? Python version & source: Any supported
Description of the problem:
Hi, are there any plans for implementing the RunScriptAsync method and its event to handle it?
Thank you
Code Example (click to expand)
self.Bind(wx.html2.EVT_WEBVIEW_SCRIPT_RESULT, self.OnWebViewScriptResult, self.wv)
# example call js function
self.wv.RunScriptAsync("function f(a){return a;}f('Hello World!');")
def OnWebViewScriptResult(self, evt):
if evt.IsError():
log.info("Async script execution failed: %s", evt.GetString())
else:
log.error("Async script result received; value = %s", evt.GetString())
At the moment, wxPython is based on wxWidgets 3.1.5(ish). It would be added once it moves forward from that.
Are there any plans on the timing for next release?
Thank you
I tried the latest version and I have the following error:
Code Example (click to expand)
self.Bind(wx.html2.EVT_WEBVIEW_SCRIPT_RESULT, self.OnWebViewScriptResult, self.wv)
# example call js function
self.wv.RunScriptAsync("function f(a){return a;}f('Hello World!');")
def OnWebViewScriptResult(self, evt):
if evt.IsError():
log.info("Async script execution failed: %s", evt.GetString())
else:
log.error("Async script result received; value = %s", evt.GetString())
module 'wx.html2' has no attribute 'EVT_WEBVIEW_SCRIPT_RESULT'
4.2.0 msw (phoenix) wxWidgets 3.2.
what is the state of RunScriptAsync ?
Thank you
@dmazzella You can install a snapshot build of wxPython for using RunScriptAsync. They are listed here: https://wxpython.org/Phoenix/snapshot-builds
You can easily install a snapshot build via the pip package installer. For example:
pip install https://wxpython.org/Phoenix/snapshot-builds/wxPython-4.2.1a1.dev5496+7c4d21d7-cp39-cp39-win_amd64.whl
I have been using RunScriptAsync for a few months now. It runs very well. It's a pity that you can only set one AddScriptMessageHandler at the moment, but maybe that will change...
Good luck with your project =)
A basic demo:
Code Example (click to expand)
import wx
import wx.html2
class MyBrowser(wx.Dialog):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.browser = wx.html2.WebView.New(self, style=wx.NO_BORDER)
self.browser.AddScriptMessageHandler("message_handler")
self.Bind(wx.html2.EVT_WEBVIEW_LOADED, self.OnWebViewLoaded, self.browser)
self.Bind(wx.html2.EVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, self.OnWebViewMessage, self.browser)
self.Bind(wx.EVT_CLOSE, lambda evt: self.DestroyLater())
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.browser, 1, wx.EXPAND)
self.SetSizer(sizer)
def OnWebViewLoaded(self, evt):
self.browser.RunScriptAsync("document.getElementById('paragraph').innerText='Hello from Python!'")
def OnWebViewMessage(self, evt):
print(f"Message received: {evt.GetString()}")
if __name__ == "__main__":
app = wx.App()
dialog = MyBrowser(None, id=-1, style=wx.DEFAULT_FRAME_STYLE, size=(600, 400))
dialog.browser.SetPage(
"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<h1>Demo</h1>
<p id="paragraph">Lorem ipsum.</p>
<script>
window.message_handler.postMessage("Hello from JavaScript!");
</script>
</body>
</html>
""",
"",
)
dialog.Show()
app.MainLoop()
Yes, when we updated wxWidgets versions, we overlooked setting up the EVT_WEBVIEW_SCRIPT_RESULT event. Should be an easy fix.
@dmazzella I was a little curious... You can easily add the missing lines yourself in the meantime until there is a new release. Only two lines of code need to be added. Search for the following two files in this path:
(The path of the wxPython pip installation (on Windows 10) should look something like this)
C:\Users\<YOUR NAME>\AppData\Local\Programs\Python\Python39\Lib\site-packages\wx\
"html2.py" (line 37):
EVT_WEBVIEW_SCRIPT_RESULT = wx.PyEventBinder( wxEVT_WEBVIEW_SCRIPT_RESULT, 1)
"html2.pyi" (line 814):
EVT_WEBVIEW_SCRIPT_RESULT = wx.PyEventBinder( wxEVT_WEBVIEW_SCRIPT_RESULT, 1)
Now this script runs smoothly:
Code Example (click to expand)
import wx
import wx.html2
class MyBrowser(wx.Dialog):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.browser = wx.html2.WebView.New(self, style=wx.NO_BORDER)
self.browser.AddScriptMessageHandler("message_handler")
self.Bind(wx.html2.EVT_WEBVIEW_LOADED, self.OnWebViewLoaded, self.browser)
self.Bind(wx.html2.EVT_WEBVIEW_SCRIPT_RESULT, self.OnWebViewScriptResult, self.browser)
self.Bind(wx.html2.EVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, self.OnWebViewMessage, self.browser)
self.Bind(wx.EVT_CLOSE, lambda evt: self.DestroyLater())
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.browser, 1, wx.EXPAND)
self.SetSizer(sizer)
def OnWebViewLoaded(self, evt):
self.browser.RunScriptAsync("document.getElementById('paragraph').innerText='Hello from Python!'")
self.browser.RunScriptAsync("function f(a){return a;}f('Hello World!');")
def OnWebViewScriptResult(self, evt):
if evt.IsError():
print(f"Async script execution failed: {evt.GetString()}")
else:
print(f"Async script result received; value = {evt.GetString()}")
def OnWebViewMessage(self, evt):
print(f"Message received: {evt.GetString()}")
if __name__ == "__main__":
app = wx.App()
dialog = MyBrowser(None, id=-1, style=wx.DEFAULT_FRAME_STYLE, size=(600, 400))
dialog.browser.SetPage(
"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<h1>Demo</h1>
<p id="paragraph">Lorem ipsum.</p>
<script>
window.message_handler.postMessage("Hello from JavaScript!");
</script>
</body>
</html>
""",
"",
)
dialog.Show()
app.MainLoop()