From c92f2484c02c47f0ed51cabb27f447676a26f9fc Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Tue, 22 Oct 2019 19:23:39 -0700 Subject: [PATCH] Show how to use the MemoryFSHandler and a custom WebViewHandler --- samples/html2/HTML2_WebView.py | 161 ------------------- samples/html2/logo.png | Bin 0 -> 24533 bytes samples/html2/webview_sample.html | 29 ++++ samples/html2/webview_sample.py | 251 ++++++++++++++++++++++++++++++ 4 files changed, 280 insertions(+), 161 deletions(-) delete mode 100644 samples/html2/HTML2_WebView.py create mode 100644 samples/html2/logo.png create mode 100644 samples/html2/webview_sample.html create mode 100644 samples/html2/webview_sample.py diff --git a/samples/html2/HTML2_WebView.py b/samples/html2/HTML2_WebView.py deleted file mode 100644 index 07f0e99d..00000000 --- a/samples/html2/HTML2_WebView.py +++ /dev/null @@ -1,161 +0,0 @@ -import sys -import wx -import wx.html2 as webview - -#---------------------------------------------------------------------- - -class TestPanel(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent) - - self.current = "http://wxPython.org" - self.frame = self.GetTopLevelParent() - self.titleBase = self.frame.GetTitle() - - sizer = wx.BoxSizer(wx.VERTICAL) - btnSizer = wx.BoxSizer(wx.HORIZONTAL) - self.wv = webview.WebView.New(self) - self.Bind(webview.EVT_WEBVIEW_NAVIGATING, self.OnWebViewNavigating, self.wv) - self.Bind(webview.EVT_WEBVIEW_NAVIGATED, self.OnWebViewNavigated, self.wv) - self.Bind(webview.EVT_WEBVIEW_LOADED, self.OnWebViewLoaded, self.wv) - self.Bind(webview.EVT_WEBVIEW_TITLE_CHANGED, self.OnWebViewTitleChanged, self.wv) - - btn = wx.Button(self, -1, "Open", style=wx.BU_EXACTFIT) - self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn) - btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) - - btn = wx.Button(self, -1, "<--", style=wx.BU_EXACTFIT) - self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn) - btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoBack, btn) - - btn = wx.Button(self, -1, "-->", style=wx.BU_EXACTFIT) - self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn) - btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoForward, btn) - - btn = wx.Button(self, -1, "Stop", style=wx.BU_EXACTFIT) - self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn) - btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) - - btn = wx.Button(self, -1, "Refresh", style=wx.BU_EXACTFIT) - self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn) - btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) - - txt = wx.StaticText(self, -1, "Location:") - btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2) - - self.location = wx.ComboBox( - self, -1, "", style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER) - self.location.AppendItems(['http://wxPython.org', - 'http://wxwidgets.org', - 'http://google.com']) - - #for url in ['http://wxPython.org', - # 'http://wxwidgets.org', - # 'http://google.com']: - # item = webview.WebViewHistoryItem(url, url) - # self.wv.LoadHistoryItem(item) - - self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location) - self.location.Bind(wx.EVT_TEXT_ENTER, self.OnLocationEnter) - btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2) - - - sizer.Add(btnSizer, 0, wx.EXPAND) - sizer.Add(self.wv, 1, wx.EXPAND) - self.SetSizer(sizer) - - self.wv.LoadURL(self.current) - - - - # WebView events - def OnWebViewNavigating(self, evt): - # this event happens prior to trying to get a resource - if evt.GetURL() == 'http://www.microsoft.com/': - if wx.MessageBox("Are you sure you want to visit Microsoft?", - style=wx.YES_NO|wx.ICON_QUESTION) == wx.NO: - # This is how you can cancel loading a page. - evt.Veto() - - - def OnWebViewNavigated(self, evt): - self.frame.SetStatusText("Loading %s..." % evt.GetURL()) - - - def OnWebViewLoaded(self, evt): - # The full document has loaded - self.current = evt.GetURL() - self.location.SetValue(self.current) - self.frame.SetStatusText("Loaded") - - - def OnWebViewTitleChanged(self, evt): - # Set the frame's title to include the document's title - self.frame.SetTitle("%s -- %s" % (self.titleBase, evt.GetString())) - - - # Control bar events - def OnLocationSelect(self, evt): - url = self.location.GetStringSelection() - print('OnLocationSelect: %s\n' % url) - self.wv.LoadURL(url) - - def OnLocationEnter(self, evt): - url = self.location.GetValue() - self.location.Append(url) - self.wv.LoadURL(url) - - - def OnOpenButton(self, event): - dlg = wx.TextEntryDialog(self, "Open Location", - "Enter a full URL or local path", - self.current, wx.OK|wx.CANCEL) - dlg.CentreOnParent() - - if dlg.ShowModal() == wx.ID_OK: - self.current = dlg.GetValue() - self.wv.LoadURL(self.current) - - dlg.Destroy() - - def OnPrevPageButton(self, event): - for i in self.wv.GetBackwardHistory(): - print("%s %s" % (i.Url, i.Title)) - self.wv.GoBack() - - def OnNextPageButton(self, event): - for i in self.wv.GetForwardHistory(): - print("%s %s" % (i.Url, i.Title)) - self.wv.GoForward() - - def OnCheckCanGoBack(self, event): - event.Enable(self.wv.CanGoBack()) - - def OnCheckCanGoForward(self, event): - event.Enable(self.wv.CanGoForward()) - - def OnStopButton(self, evt): - self.wv.Stop() - - def OnRefreshPageButton(self, evt): - self.wv.Reload() - - -#---------------------------------------------------------------------- - - -def main(): - app = wx.App() - frm = wx.Frame(None, title="html2.WebView sample", size=(700,500)) - frm.CreateStatusBar() - pnl = TestPanel(frm) - frm.Show() - app.MainLoop() - - -#---------------------------------------------------------------------- - -if __name__ == '__main__': - main() diff --git a/samples/html2/logo.png b/samples/html2/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9d108abbee85241b101958875915b656193f2515 GIT binary patch literal 24533 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 Eg3MaaqyPW_ literal 0 HcmV?d00001 diff --git a/samples/html2/webview_sample.html b/samples/html2/webview_sample.html new file mode 100644 index 00000000..3652d3be --- /dev/null +++ b/samples/html2/webview_sample.html @@ -0,0 +1,29 @@ + + +Home + + +

html2.WebView Sample

+

This is a super simple launch page for the html2.WebView sample.

+ +
+

Normal web pages and real web sites work just as expected: +

+

+ +
+

+Resources can also be loaded from custom file systems: +

+

+

+ + diff --git a/samples/html2/webview_sample.py b/samples/html2/webview_sample.py new file mode 100644 index 00000000..420a87f4 --- /dev/null +++ b/samples/html2/webview_sample.py @@ -0,0 +1,251 @@ +import sys +import os +from six import BytesIO + +import wx +import wx.html2 as webview + +HERE = os.path.abspath(os.path.dirname(__file__)) +BASE = 'file://{}/'.format(HERE.replace('\\', '/')) +URL = BASE + 'webview_sample.html' +LOGO = os.path.join(HERE, 'logo.png') + +#print(wx.version()) + +#-------------------------------------------------------------------------- + +class SampleFrame(wx.Frame): + def __init__(self, parent, url=URL): + wx.Frame.__init__(self, parent, title="html2.WebView Sample", size=(800,900)) + # add a statusbar + self.CreateStatusBar() + + # Add a menubar with just a quit item + mb = wx.MenuBar() + menu = wx.Menu() + menu.Append(wx.ID_EXIT, '&Quit') + mb.Append(menu, "File") + self.SetMenuBar(mb) + self.Bind(wx.EVT_MENU, self.OnQuit, id=wx.ID_EXIT) + + # Create the main panel + pnl = WebViewPanel(self, url) + + # Menu event handler to close the frame + def OnQuit(self, evt): + self.Close(force=True) + +#-------------------------------------------------------------------------- + +class WebViewPanel(wx.Panel): + def __init__(self, parent, url): + wx.Panel.__init__(self, parent) + + self.current = url + self.frame = self.GetTopLevelParent() + self.titleBase = self.frame.GetTitle() + + sizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + self.wv = webview.WebView.New(self) + + # Register a handler for the memory: file system + self.wv.RegisterHandler(webview.WebViewFSHandler("memory")) + + # And also one for the custom: file system implemented by the + # CustomWebViewHandler class below + self.wv.RegisterHandler(CustomWebViewHandler()) + + self.Bind(webview.EVT_WEBVIEW_NAVIGATING, self.OnWebViewNavigating, self.wv) + self.Bind(webview.EVT_WEBVIEW_NAVIGATED, self.OnWebViewNavigated, self.wv) + self.Bind(webview.EVT_WEBVIEW_LOADED, self.OnWebViewLoaded, self.wv) + self.Bind(webview.EVT_WEBVIEW_TITLE_CHANGED, self.OnWebViewTitleChanged, self.wv) + + btn = wx.Button(self, -1, "Open", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "⬅︎", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoBack, btn) + + btn = wx.Button(self, -1, "➡︎", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoForward, btn) + + btn = wx.Button(self, -1, "Stop", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "Refresh", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + txt = wx.StaticText(self, -1, "Location:") + btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2) + + self.location = wx.ComboBox( + self, -1, "", style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER) + self.location.AppendItems(['http://wxPython.org', + 'http://wxwidgets.org', + 'http://google.com']) + + + self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location) + self.location.Bind(wx.EVT_TEXT_ENTER, self.OnLocationEnter) + btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2) + + + sizer.Add(btnSizer, 0, wx.EXPAND) + sizer.Add(self.wv, 1, wx.EXPAND) + self.SetSizer(sizer) + + self.wv.LoadURL(self.current) + + + # WebView events + def OnWebViewNavigating(self, evt): + # this event happens prior to trying to get a resource + if evt.GetURL() == 'https://www.microsoft.com/': + if wx.MessageBox("Are you sure you want to visit Microsoft?", + style=wx.YES_NO|wx.ICON_QUESTION) == wx.NO: + # This is how you can cancel loading a page. + evt.Veto() + + + def OnWebViewNavigated(self, evt): + self.frame.SetStatusText("Loading %s..." % evt.GetURL()) + + + def OnWebViewLoaded(self, evt): + # The full document has loaded + self.current = evt.GetURL() + self.location.SetValue(self.current) + self.frame.SetStatusText("Loaded") + + + def OnWebViewTitleChanged(self, evt): + # Set the frame's title to include the document's title + self.frame.SetTitle("%s -- %s" % (self.titleBase, evt.GetString())) + + + # Control bar events + def OnLocationSelect(self, evt): + url = self.location.GetStringSelection() + self.wv.LoadURL(url) + + def OnLocationEnter(self, evt): + url = self.location.GetValue() + self.location.Append(url) + self.wv.LoadURL(url) + + + def OnOpenButton(self, event): + dlg = wx.TextEntryDialog(self, "Open Location", + "Enter a full URL or local path", + self.current, wx.OK|wx.CANCEL) + dlg.CentreOnParent() + + if dlg.ShowModal() == wx.ID_OK: + self.current = dlg.GetValue() + self.wv.LoadURL(self.current) + + dlg.Destroy() + + def OnPrevPageButton(self, event): + #for i in self.wv.GetBackwardHistory(): + # print("%s %s" % (i.Url, i.Title)) + self.wv.GoBack() + + def OnNextPageButton(self, event): + #for i in self.wv.GetForwardHistory(): + # print("%s %s" % (i.Url, i.Title)) + self.wv.GoForward() + + def OnCheckCanGoBack(self, event): + event.Enable(self.wv.CanGoBack()) + + def OnCheckCanGoForward(self, event): + event.Enable(self.wv.CanGoForward()) + + def OnStopButton(self, evt): + self.wv.Stop() + + def OnRefreshPageButton(self, evt): + self.wv.Reload() + + + +#-------------------------------------------------------------------------- + +def SetupMemoryFiles(): + # Set up an in-memory file system with virtual "files" that can be + # loaded into the webview just like network or local file sources. + # These "files" can be access using a protocol specifier of "memory:" + wx.FileSystem.AddHandler(wx.MemoryFSHandler()) + wx.MemoryFSHandler.AddFile( + "page1.htm", + "File System Example" + "" + "

Page 1

" + "

" + "

This file was loaded directly from a virtual in-memory filesystem.

" + "

Here's another page: Page 2.

") + wx.MemoryFSHandler.AddFile( + "page2.htm", + "File System Example" + "" + "

Page 2

" + "

Page 1 was better.

") + wx.MemoryFSHandler.AddFile( + "test.css", + "h1 {color: red;}") + wx.MemoryFSHandler.AddFile('logo.png', wx.Bitmap(LOGO), wx.BITMAP_TYPE_PNG) + +#-------------------------------------------------------------------------- + +class CustomWebViewHandler(webview.WebViewHandler): + # This shows how to make a custom handler for providing content to the + # WebView for a specific scheme ("custom:" in this case). This handler + # class simply needs to implement the GetFile method, which will be called + # whenever a resource with a matching scheme is to be loaded, and it needs + # to respond by returning a wx.FSFile object. This means that, unlike the + # wx.MemoryFSHandler, content can be generated on the fly rather than + # needing to be preloaded into a filesystem. + # + + def __init__(self): + wx.html2.WebViewHandler.__init__(self, 'custom') + self.count = 0 + + def GetFile(self, uri): + # We'll just provide the same content for every URI in this example, but + # normally you would generate or fetch appropriate content that is + # referenced by the given URI. + self.count += 1 + content = """\ + Custom Handler Example +

Custom Handler Example

+

This page is provided dynamically from the CustomWebViewHandler class.

+

It has been loaded {} times.

+ """.format(self.count) + stream = BytesIO(content.encode('utf-8')) + fsfile = wx.FSFile(stream, uri, 'page1.html', 'text/html', wx.DateTime.Now()) + return fsfile + +#-------------------------------------------------------------------------- + +def main(): + app = wx.App() + SetupMemoryFiles() + frm = SampleFrame(None) + frm.Show() + app.MainLoop() + + +#-------------------------------------------------------------------------- + +if __name__ == '__main__': + main()