Skip to content

Commit ac9514a

Browse files
committed
Added wxPython subpackage for the cefpython1 package,
the author of this subpackage is Greg Kacy.
1 parent 4df5552 commit ac9514a

13 files changed

Lines changed: 536 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
This is a wxPython subpackage for the cefpython1 package
2+
that provides an easy to use API for the wxPython GUI library.
3+
4+
Author: Greg Kacy <greg.kacy@@gmail.com>
5+
License: BSD 3-clause
6+

cefpython/cef1/wx-subpackage/__init__.py

Whitespace-only changes.
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
# Additional and wx specific layer of abstraction for the cefpython
2+
# __author__ = "Greg Kacy <grkacy@gmail.com>"
3+
4+
#--------------------------------------------------------------------------------
5+
6+
import platform
7+
if platform.architecture()[0] != "32bit":
8+
raise Exception("Only 32bit architecture is supported")
9+
10+
import os
11+
import sys
12+
try:
13+
# Import local PYD file (portable zip).
14+
if sys.hexversion >= 0x02070000 and sys.hexversion < 0x03000000:
15+
import cefpython_py27 as cefpython
16+
elif sys.hexversion >= 0x03000000 and sys.hexversion < 0x04000000:
17+
import cefpython_py32 as cefpython
18+
else:
19+
raise Exception("Unsupported python version: %s" % sys.version)
20+
except ImportError:
21+
# Import from package (installer).
22+
from cefpython1 import cefpython
23+
24+
import wx
25+
import wx.lib.buttons as buttons
26+
27+
from cefpython1.wx.utils import GetApplicationPath
28+
29+
#-------------------------------------------------------------------------------
30+
31+
# Default timer interval when timer used to service CEF message loop
32+
DEFAULT_TIMER_MILLIS = 10
33+
34+
#-------------------------------------------------------------------------------
35+
36+
class NavigationBar(wx.Panel):
37+
def __init__(self, parent, *args, **kwargs):
38+
wx.Panel.__init__(self, parent, *args, **kwargs)
39+
40+
self.bitmapDir = os.path.join(os.path.dirname(
41+
os.path.abspath(__file__)), "images")
42+
43+
self._InitComponents()
44+
self._LayoutComponents()
45+
self._InitEventHandlers()
46+
47+
def _InitComponents(self):
48+
self.backBtn = buttons.GenBitmapButton(self, -1,
49+
wx.Bitmap(os.path.join(self.bitmapDir, "Arrow Left.png"),
50+
wx.BITMAP_TYPE_PNG), style=wx.BORDER_NONE)
51+
self.forwardBtn = buttons.GenBitmapButton(self, -1,
52+
wx.Bitmap(os.path.join(self.bitmapDir, "Arrow Right.png"),
53+
wx.BITMAP_TYPE_PNG), style=wx.BORDER_NONE)
54+
self.reloadBtn = buttons.GenBitmapButton(self, -1,
55+
wx.Bitmap(os.path.join(self.bitmapDir, "Button Load.png"),
56+
wx.BITMAP_TYPE_PNG), style=wx.BORDER_NONE)
57+
58+
self.url = wx.TextCtrl(self, id=-1, style=0)
59+
60+
self.historyPopup = wx.Menu()
61+
62+
def _LayoutComponents(self):
63+
sizer = wx.BoxSizer(wx.HORIZONTAL)
64+
sizer.Add(self.backBtn, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|
65+
wx.ALL, 0)
66+
sizer.Add(self.forwardBtn, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|
67+
wx.ALL, 0)
68+
sizer.Add(self.reloadBtn, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|
69+
wx.ALL, 0)
70+
71+
sizer.Add(self.url, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 12)
72+
73+
self.SetSizer(sizer)
74+
self.Fit()
75+
76+
def _InitEventHandlers(self):
77+
self.backBtn.Bind(wx.EVT_CONTEXT_MENU, self.OnButtonContext)
78+
79+
def __del__(self):
80+
self.historyPopup.Destroy()
81+
82+
def GetBackButton(self):
83+
return self.backBtn
84+
85+
def GetForwardButton(self):
86+
return self.forwardBtn
87+
88+
def GetReloadButton(self):
89+
return self.reloadBtn
90+
91+
def GetUrlCtrl(self):
92+
return self.url
93+
94+
def InitHistoryPopup(self):
95+
self.historyPopup = wx.Menu()
96+
97+
def AddToHistory(self, url):
98+
self.historyPopup.Append(-1, url)
99+
100+
def OnButtonContext(self, event):
101+
self.PopupMenu(self.historyPopup)
102+
103+
104+
class ChromeWindow(wx.Window):
105+
"""
106+
Standalone CEF component. The class provides facilites for interacting
107+
with wx message loop
108+
"""
109+
def __init__(self, parent, url="", useTimer=False,
110+
timerMillis=DEFAULT_TIMER_MILLIS, size=(-1, -1),
111+
*args, **kwargs):
112+
wx.Window.__init__(self, parent, id=wx.ID_ANY, size=size,
113+
*args, **kwargs)
114+
self.url = url
115+
windowInfo = cefpython.WindowInfo()
116+
windowInfo.SetAsChild(self.GetHandle())
117+
self.browser = cefpython.CreateBrowserSync(windowInfo,
118+
browserSettings={}, navigateUrl=url)
119+
120+
self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
121+
self.Bind(wx.EVT_SIZE, self.OnSize)
122+
if useTimer:
123+
self.timerID = 1
124+
self._CreateTimer(timerMillis)
125+
else:
126+
self.Bind(wx.EVT_IDLE, self.OnIdle)
127+
self._useTimer = useTimer
128+
129+
def __del__(self):
130+
'''cleanup stuff'''
131+
if self._useTimer:
132+
self.timer.Stop()
133+
else:
134+
self.Unbind(wx.EVT_IDLE)
135+
self.browser.CloseBrowser()
136+
137+
def _CreateTimer(self, millis):
138+
self.timer = wx.Timer(self, self.timerID)
139+
self.timer.Start(millis) #
140+
wx.EVT_TIMER(self, self.timerID, self.OnTimer)
141+
142+
def OnTimer(self, event):
143+
"""Service CEF message loop when useTimer is True"""
144+
cefpython.MessageLoopWork()
145+
146+
def OnIdle(self, event):
147+
"""Service CEF message loop when useTimer is False"""
148+
cefpython.MessageLoopWork()
149+
event.Skip()
150+
151+
def OnSetFocus(self, event):
152+
cefpython.WindowUtils.OnSetFocus(self.GetHandle(), 0, 0, 0)
153+
event.Skip()
154+
155+
def OnSize(self, event):
156+
"""Handle the the size event"""
157+
cefpython.WindowUtils.OnSize(self.GetHandle(), 0, 0, 0)
158+
event.Skip()
159+
160+
def GetBrowser(self):
161+
"""Returns the CEF's browser object"""
162+
return self.browser
163+
164+
def LoadUrl(self, url, onLoadStart=None, onLoadEnd=None):
165+
if onLoadStart or onLoadEnd:
166+
self.GetBrowser().SetClientHandler(
167+
CallbackClientHandler(onLoadStart, onLoadEnd))
168+
self.GetBrowser().GetMainFrame().LoadUrl(url)
169+
170+
171+
class ChromeCtrl(wx.Panel):
172+
def __init__(self, parent, url="", useTimer=False,
173+
timerMillis=DEFAULT_TIMER_MILLIS, hasNavBar=True,
174+
*args, **kwargs):
175+
wx.Panel.__init__(self, parent, *args, **kwargs)
176+
177+
self.chromeWindow = ChromeWindow(self, url=str(url), useTimer=useTimer)
178+
sizer = wx.BoxSizer(wx.VERTICAL)
179+
self.navigationBar = None
180+
if hasNavBar:
181+
self.navigationBar = self.CreateNavigationBar()
182+
sizer.Add(self.navigationBar, 0, wx.EXPAND|wx.ALL, 0)
183+
self._InitEventHandlers()
184+
185+
sizer.Add(self.chromeWindow, 1, wx.EXPAND, 0)
186+
187+
self.SetSizer(sizer)
188+
self.Fit()
189+
190+
ch = DefaultClientHandler(self)
191+
self.SetClientHandler(ch)
192+
if self.navigationBar:
193+
self.UpdateButtonsState()
194+
195+
def _InitEventHandlers(self):
196+
self.navigationBar.backBtn.Bind(wx.EVT_BUTTON, self.OnLeft)
197+
self.navigationBar.forwardBtn.Bind(wx.EVT_BUTTON, self.OnRight)
198+
self.navigationBar.reloadBtn.Bind(wx.EVT_BUTTON, self.OnReload)
199+
200+
def GetNavigationBar(self):
201+
return self.navigationBar
202+
203+
def SetNavigationBar(self, navigationBar):
204+
sizer = self.GetSizer()
205+
if self.navigationBar:
206+
# remove previous one
207+
sizer.Replace(self.navigationBar, navigationBar)
208+
self.navigationBar.Hide()
209+
del self.navigationBar
210+
else:
211+
sizer.Insert(0, navigationBar, 0, wx.EXPAND)
212+
self.navigationBar = navigationBar
213+
sizer.Fit(self)
214+
215+
def CreateNavigationBar(self):
216+
np = NavigationBar(self)
217+
return np
218+
219+
def SetClientHandler(self, handler):
220+
self.chromeWindow.GetBrowser().SetClientHandler(handler)
221+
222+
def OnLeft(self, event):
223+
if self.chromeWindow.GetBrowser().CanGoBack():
224+
self.chromeWindow.GetBrowser().GoBack()
225+
self.UpdateButtonsState()
226+
227+
def OnRight(self, event):
228+
if self.chromeWindow.GetBrowser().CanGoForward():
229+
self.chromeWindow.GetBrowser().GoForward()
230+
self.UpdateButtonsState()
231+
232+
def OnReload(self, event):
233+
self.chromeWindow.GetBrowser().Reload()
234+
self.UpdateButtonsState()
235+
236+
def UpdateButtonsState(self):
237+
self.navigationBar.backBtn.Enable(
238+
self.chromeWindow.GetBrowser().CanGoBack())
239+
self.navigationBar.forwardBtn.Enable(
240+
self.chromeWindow.GetBrowser().CanGoForward())
241+
242+
def OnLoadStart(self, browser, frame):
243+
if self.navigationBar:
244+
self.UpdateButtonsState()
245+
self.navigationBar.GetUrlCtrl().SetValue(
246+
browser.GetMainFrame().GetUrl())
247+
self.navigationBar.AddToHistory(browser.GetMainFrame().GetUrl())
248+
249+
250+
class DefaultClientHandler(object):
251+
def __init__(self, parentCtrl):
252+
self.parentCtrl = parentCtrl
253+
254+
def OnLoadStart(self, browser, frame):
255+
self.parentCtrl.OnLoadStart(browser, frame)
256+
257+
def OnLoadEnd(self, browser, frame, httpStatusCode):
258+
self.parentCtrl.OnLoadEnd(browser, frame, httpStatusCode)
259+
260+
def OnLoadError(self, browser, frame, errorCode, failedUrl, errorText):
261+
# TODO
262+
print "ERROR LOADING URL : %" % failedUrl
263+
264+
class CallbackClientHandler(object):
265+
def __init__(self, onLoadStart=None, onLoadEnd=None):
266+
self.onLoadStart = onLoadStart
267+
self.onLoadEnd = onLoadEnd
268+
269+
def OnLoadStart(self, browser, frame):
270+
if self.onLoadStart and frame.GetUrl() != "about:blank":
271+
self.onLoadStart(browser, frame)
272+
273+
def OnLoadEnd(self, browser, frame, httpStatusCode):
274+
if self.onLoadEnd and frame.GetUrl() != "about:blank":
275+
self.onLoadEnd(browser, frame, httpStatusCode)
276+
277+
def OnLoadError(self, browser, frame, errorCode, failedUrl, errorText):
278+
# TODO
279+
print "ERROR LOADING URL : %" % failedUrl
280+
281+
#-------------------------------------------------------------------------------
282+
283+
def Initialize(settings=None):
284+
"""Initializes CEF, We should do it before initializing wx
285+
If no settings passed a default is used
286+
"""
287+
sys.excepthook = ExceptHook
288+
if not settings:
289+
settings = {
290+
"log_severity": cefpython.LOGSEVERITY_INFO,
291+
"log_file": GetApplicationPath("debug.log"),
292+
"release_dcheck_enabled": True # Enable only when debugging.
293+
}
294+
cefpython.Initialize(settings)
295+
296+
def Shutdown():
297+
"""Shuts down CEF, should be called by app exiting code"""
298+
cefpython.Shutdown()
299+
300+
def ExceptHook(t, value, traceObject):
301+
import traceback, os, time
302+
# This hook does the following: in case of exception display it,
303+
# write to error.log, shutdown CEF and exit application.
304+
error = "\n".join(traceback.format_exception(t, value, traceObject))
305+
with open(GetApplicationPath("error.log"), "a") as f:
306+
f.write("\n[%s] %s\n" % (time.strftime("%Y-%m-%d %H:%M:%S"), error))
307+
print("\n"+error+"\n")
308+
##cefpython.QuitMessageLoop()
309+
##cefpython.Shutdown()
310+
# So that "finally" does not execute.
311+
##os._exit(1)
1.32 KB
Loading
1.28 KB
Loading
1.39 KB
Loading
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Simple sample ilustrating the usage of CEFWindow class
2+
# __author__ = "Greg Kacy <grkacy@gmail.com>"
3+
4+
import os
5+
import wx
6+
7+
import cefpython1.wx.chromectrl as chrome
8+
9+
class MainFrame(wx.Frame):
10+
def __init__(self):
11+
wx.Frame.__init__(self, parent=None, id=wx.ID_ANY,
12+
title='cefwx example1', size=(600,400))
13+
14+
self.cefWindow = chrome.ChromeWindow(self,
15+
#url=os.path.join(os.path.dirname(os.path.abspath(__file__)),
16+
# "../cefsimple.html"))
17+
url=os.path.join(os.path.dirname(os.path.abspath(__file__)),
18+
"../withpopup.html"))
19+
20+
sizer = wx.BoxSizer()
21+
sizer.Add(self.cefWindow, 1, wx.EXPAND, 0)
22+
self.SetSizer(sizer)
23+
24+
self.Bind(wx.EVT_CLOSE, self.OnClose)
25+
26+
def OnClose(self, event):
27+
self.Destroy()
28+
29+
if __name__ == '__main__':
30+
chrome.Initialize()
31+
print('wx.version=%s' % wx.version())
32+
app = wx.PySimpleApp()
33+
MainFrame().Show()
34+
app.MainLoop()
35+
del app # Let wx.App destructor do the cleanup before calling cefpython.Shutdown().
36+
chrome.Shutdown()
37+
38+

0 commit comments

Comments
 (0)