Skip to content

Commit a6c0a0a

Browse files
committed
Create wxpython.py example (cztomczak#269)
1 parent 5fefeec commit a6c0a0a

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

examples/resources/wxpython.png

11.3 KB
Loading

examples/wxpython.py

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# Example of embedding CEF Python browser using wxPython library.
2+
# This example has a top menu and a browser widget without navigation bar.
3+
4+
# To install wxPython on Linux type "sudo apt-get install python-wxtools".
5+
6+
# Tested with wxPython 2.8 on Linux, wxPython 3.0 on Windows/Mac
7+
# and CEF Python v55.3.
8+
9+
import wx
10+
from cefpython3 import cefpython as cef
11+
import platform
12+
import sys
13+
import os
14+
15+
# Constants
16+
LINUX = (platform.system() == "Linux")
17+
WINDOWS = (platform.system() == "Windows")
18+
WIDTH = 800
19+
HEIGHT = 600
20+
21+
22+
def main():
23+
check_versions()
24+
sys.excepthook = cef.ExceptHook # To shutdown all CEF processes on error
25+
cef.Initialize()
26+
app = CefApp(False)
27+
app.MainLoop()
28+
del app # Must destroy before calling Shutdown
29+
cef.Shutdown()
30+
31+
32+
def check_versions():
33+
print("[wxpython.py] CEF Python {ver}".format(ver=cef.__version__))
34+
print("[wxpython.py] Python {ver}".format(ver=sys.version[:6]))
35+
print("[wxpython.py] wx {ver}".format(ver=wx.version()))
36+
# CEF Python version requirement
37+
assert cef.__version__ >= "55.3", "CEF Python v55.3+ required to run this"
38+
39+
40+
class MainFrame(wx.Frame):
41+
42+
def __init__(self):
43+
wx.Frame.__init__(self, parent=None, id=wx.ID_ANY,
44+
title='wxPython example', size=(WIDTH, HEIGHT))
45+
self.browser = None
46+
47+
self.setup_icon()
48+
self.create_menu()
49+
self.Bind(wx.EVT_CLOSE, self.OnClose)
50+
51+
# Set wx.WANTS_CHARS style for the keyboard to work.
52+
# This style also needs to be set for all parent controls.
53+
self.browser_panel = wx.Panel(self, style=wx.WANTS_CHARS)
54+
self.browser_panel.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
55+
self.browser_panel.Bind(wx.EVT_SIZE, self.OnSize)
56+
57+
# Must show so that handle is available when embedding browser
58+
self.Show()
59+
self.embed_browser()
60+
61+
def setup_icon(self):
62+
icon_file = os.path.join(os.path.abspath(os.path.dirname(__file__)),
63+
"resources", "wxpython.png")
64+
if os.path.exists(icon_file):
65+
icon = wx.IconFromBitmap(wx.Bitmap(icon_file, wx.BITMAP_TYPE_PNG))
66+
self.SetIcon(icon)
67+
68+
def create_menu(self):
69+
filemenu = wx.Menu()
70+
filemenu.Append(1, "Open")
71+
exit_ = filemenu.Append(2, "Exit")
72+
self.Bind(wx.EVT_MENU, self.OnClose, exit_)
73+
aboutmenu = wx.Menu()
74+
aboutmenu.Append(1, "CEF Python")
75+
menubar = wx.MenuBar()
76+
menubar.Append(filemenu, "&File")
77+
menubar.Append(aboutmenu, "&About")
78+
self.SetMenuBar(menubar)
79+
80+
def embed_browser(self):
81+
window_info = cef.WindowInfo()
82+
window_info.SetAsChild(self.browser_panel.GetHandle())
83+
self.browser = cef.CreateBrowserSync(window_info,
84+
url="https://www.google.com/")
85+
self.browser.SetClientHandler(FocusHandler())
86+
87+
def OnSetFocus(self, _):
88+
if not self.brower:
89+
return
90+
if WINDOWS:
91+
# noinspection PyUnresolvedReferences
92+
cef.WindowUtils.OnSetFocus(self.GetHandleForBrowser(), 0, 0, 0)
93+
self.browser.SetFocus(True)
94+
95+
def OnSize(self, _):
96+
if not self.browser:
97+
return
98+
if WINDOWS:
99+
# noinspection PyUnresolvedReferences
100+
cef.WindowUtils.OnSize(self.GetHandleForBrowser(), 0, 0, 0)
101+
elif LINUX:
102+
(x, y) = (0, 0)
103+
(width, height) = self.browser_panel.GetSizeTuple()
104+
# noinspection PyUnresolvedReferences
105+
self.browser.SetBounds(x, y, width, height)
106+
107+
def OnClose(self, event):
108+
# In cefpython3.wx.chromectrl example calling browser.CloseBrowser()
109+
# and/or self.Destroy() in OnClose is causing crashes when
110+
# embedding multiple browser tabs. The solution is to call only
111+
# browser.ParentWindowWillClose. Behavior of this example
112+
# seems different as it extends wx.Frame, while ChromeWindow
113+
# from chromectrl extends wx.Window. Calling CloseBrowser
114+
# and Destroy does not cause crashes, but is not recommended.
115+
# Call ParentWindowWillClose and event.Skip() instead. See
116+
# also Issue #107: https://github.com/cztomczak/cefpython/issues/107
117+
self.browser.ParentWindowWillClose()
118+
event.Skip()
119+
120+
# Clear all browser references for CEF to shutdown cleanly
121+
del self.browser
122+
123+
124+
class FocusHandler(object):
125+
126+
def __init__(self):
127+
pass
128+
129+
def OnTakeFocus(self, **kwargs):
130+
# print("[wxpython.py] FocusHandler.OnTakeFocus, next={next}"
131+
# .format(next=kwargs["next_component"]]))
132+
pass
133+
134+
def OnSetFocus(self, **kwargs):
135+
# source_enum = {cef.FOCUS_SOURCE_NAVIGATION: "navigation",
136+
# cef.FOCUS_SOURCE_SYSTEM: "system"}
137+
# print("[wxpython.py] FocusHandler.OnSetFocus, source={source}"
138+
# .format(source=source_enum[kwargs["source"]]))
139+
# return False
140+
pass
141+
142+
def OnGotFocus(self, browser, **_):
143+
# Temporary fix for focus issues on Linux (Issue #284).
144+
# If this is not applied then when switching to another
145+
# window (alt+tab) and then back to this example, keyboard
146+
# focus becomes broken, you can't type anything, even
147+
# though a type cursor blinks in web view.
148+
print("[wxpython.py] FocusHandler.OnGotFocus:"
149+
" keyboard focus fix (#284)")
150+
browser.SetFocus(True)
151+
152+
153+
class CefApp(wx.App):
154+
155+
def __init__(self, redirect):
156+
self.timer = None
157+
self.timer_id = 1
158+
super(CefApp, self).__init__(redirect=redirect)
159+
160+
def OnInit(self):
161+
self.create_timer()
162+
frame = MainFrame()
163+
self.SetTopWindow(frame)
164+
frame.Show()
165+
return True
166+
167+
def create_timer(self):
168+
# See also "Making a render loop":
169+
# http://wiki.wxwidgets.org/Making_a_render_loop
170+
# Another way would be to use EVT_IDLE in MainFrame.
171+
self.timer = wx.Timer(self, self.timer_id)
172+
self.timer.Start(10) # 10ms
173+
wx.EVT_TIMER(self, self.timer_id, self.on_timer)
174+
175+
def on_timer(self, _):
176+
cef.MessageLoopWork()
177+
178+
def OnExit(self):
179+
self.timer.Stop()
180+
181+
182+
if __name__ == '__main__':
183+
main()

0 commit comments

Comments
 (0)