I'm using wx.html2.WebView to load a Website in a Dialog, which is working fine.
Problem: If the Website can't be reached for any reason, the output will be Could not connect: Connection refused
.
Desired behaviour: Try to reload the URL after x seconds on every fail.
import wx
import wx.html2
import time
URL = "http://mydomain.tld"
class MyBrowser(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.browser = wx.html2.WebView.New(self)
self.browser.Bind(wx.html2.EVT_WEBVIEW_ERROR, self.on_webview_error)
def on_webview_error(self, evt):
# Printing works
print("Error: can't load page, try again in 3 seconds.")
# Sleeping works
time.sleep(3)
# Reloading doesn't work
self.browser.LoadURL(URL) # OR self.browser.Reload()
# Weird: Error is rendered now
if __name__ == '__main__':
app = wx.App()
dialog = MyBrowser(None, -1)
dialog.browser.LoadURL(URL)
dialog.Show()
app.MainLoop()
The problem occurs in on_webview_error(self, evt)
. My guess is that I'm using the function not correctly, especially because the error message is rendered after the reloading.
Any idea?
Thanks in advance!
There is something strange going on there!
The only way that I could force it to work was to redefine the WebView
each time. I may be being over zealous with the Destroy
each time as well.
This works but may not necessarily be exactly what you are after.
import wx
import wx.html2
import time
URL = "http://mydomain.tld"
class MyBrowser(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.url = URL
self.browser = wx.html2.WebView.New(self, -1, size=(900,600))
self.browser.Bind(wx.html2.EVT_WEBVIEW_ERROR, self.on_webview_error)
self.browser.Bind(wx.html2.EVT_WEBVIEW_LOADED, self.on_webview_load)
self.retries = 0
self.max_retries = 10
def on_webview_error(self, evt):
self.URL = evt.GetURL()
print(self.URL)
self.retries += 1
if self.retries > self.max_retries: # Give up
self.Destroy()
print("Error {} of {} attempts to load {}, trying again in 3 seconds.".format(self.retries,self.max_retries,self.URL))
if self.retries > 5: # Try alternate
self.URL = "http://wxPython.org"
print("Swapping to alternate Url "+self.URL)
self.browser.Destroy()
time.sleep(3)
self.browser = wx.html2.WebView.New(self, -1, size=(900,600))
self.browser.Bind(wx.html2.EVT_WEBVIEW_ERROR, self.on_webview_error)
self.browser.Bind(wx.html2.EVT_WEBVIEW_LOADED, self.on_webview_load)
self.browser.LoadURL(self.URL)
def on_webview_load(self, evt):
print(self.URL, "Load complete")
if __name__ == '__main__':
app = wx.App()
dialog = MyBrowser(None, -1)
dialog.browser.LoadURL(URL)
dialog.Show()
app.MainLoop()
In wxPython you always have a main thread that is the one responsible for drawing and updating the GUI. In your MWE the line time.sleep(3)
allows you to wait for 3 seconds before trying to reload the page again. However, this has the side effect of sending the main thread of the programm to sleep before being able to update the GUI and show the error message. If you move the time.sleep(3) line to a different thread the GUI may be updated without any problem. Here is a solution:
import wx
import wx.html2
import time
import _thread
from pubsub import pub
URL = "https://mydomain.tld"
class MyBrowser(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.browser = wx.html2.WebView.New(self)
self.browser.Bind(wx.html2.EVT_WEBVIEW_ERROR, self.on_webview_error)
self.counter = 0
pub.subscribe(self.loadwww, 'Try Again')
pub.subscribe(self.loadalt, 'Give UP')
def loadwww(self):
self.browser.LoadURL("https://mydomain.tld")
def loadalt(self):
self.browser.LoadURL("https://www.google.com")
def on_webview_error(self, evt):
self.counter += 1
_thread.start_new_thread(self.wait, (3,))
def wait(self, sec):
if self.counter <= 5:
print(self.counter)
print("Error: can't load page, try again in 3 seconds.")
time.sleep(sec)
wx.CallAfter(pub.sendMessage, 'Try Again')
else:
wx.CallAfter(pub.sendMessage, 'Give UP')
if __name__ == '__main__':
app = wx.App()
dialog = MyBrowser(None, -1)
dialog.browser.LoadURL(URL)
dialog.Show()
app.MainLoop()