Skip to content

Commit 24418ec

Browse files
committed
Add qt.py example (PyQt, PySide) (Issue cztomczak#234).
Minor updates to other examples. Update compile.py, run kivy_.py and qt.py examples by default.
1 parent bfc0a25 commit 24418ec

File tree

8 files changed

+345
-10
lines changed

8 files changed

+345
-10
lines changed

examples/gtk2.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Example of embedding CEF Python browser using PyGTK library (GTK 2).
2-
# Tested with GTK 2.24 and CEF Python v54+.
3-
4-
# Known issue on Linux: Keyboard focus problem (Issue #284)
2+
# Tested with GTK 2.24 and CEF Python v54+, only on Linux.
3+
# Known issue on Linux: Keyboard focus problem (Issue #284).
54

65
from cefpython3 import cefpython as cef
76
import pygtk
87
import gtk
98
import gobject
109
import sys
10+
import os
1111

1212
# In CEF you can run message loop in two ways (see API docs for more details):
1313
# 1. By calling cef.MessageLoop() instead of an application-provided
@@ -70,6 +70,9 @@ def __init__(self):
7070
self.main_window.connect('destroy', self.on_exit)
7171
self.main_window.set_size_request(width=800, height=600)
7272
self.main_window.set_title('GTK 2 example (PyGTK)')
73+
icon = os.path.join(os.path.dirname(__file__), "resources", "gtk.png")
74+
if os.path.exists(icon):
75+
self.main_window.set_icon_from_file(icon)
7376
self.main_window.realize()
7477

7578
self.vbox = gtk.VBox(False, 0)

examples/gtk3.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
# ! CURRENTLY BROKEN ! with v54+ (Issue #261).
12
# Example of embedding CEF Python browser using PyGObject library (GTK 3).
2-
# Tested with GTK 3.10 and CEF Python v53+.
3+
# Tested with GTK 3.10 and CEF Python v53.1+, only on Linux.
34

45
from cefpython3 import cefpython as cef
56
# noinspection PyUnresolvedReferences

examples/hello_world.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Hello world example. Doesn't depend on any third party GUI framework.
2-
# Tested with CEF Python v53+.
2+
# Tested with CEF Python v53.1+, only on Linux.
33

44
from cefpython3 import cefpython as cef
55
import sys

examples/qt.py

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
# Example of embedding CEF Python browser using PyQt/PySide libraries.
2+
# This example has two widgets: a navigation bar and a browser.
3+
#
4+
# Tested with PyQt 4.10.4 (4.8.6), PySide 1.2.1 (4.8.6)
5+
# and CEF Python v55.2+, only on Linux.
6+
#
7+
# Known issue on Linux: Keyboard focus sometimes doesn't work, type cursor
8+
# is blinking, but you can' type anything. In such
9+
# case clicking on url and then back inside browser
10+
# fixes it. There are multiple keyboard focus
11+
# issues in upstream CEF, see Issue #284 for details.
12+
13+
import os
14+
import sys
15+
import platform
16+
from cefpython3 import cefpython as cef
17+
18+
# PyQt imports
19+
if "pyqt" in sys.argv:
20+
from PyQt4.QtGui import *
21+
from PyQt4.QtCore import *
22+
# PySide imports
23+
elif "pyside" in sys.argv:
24+
import PySide
25+
from PySide import QtCore
26+
# noinspection PyUnresolvedReferences
27+
from PySide.QtGui import *
28+
# noinspection PyUnresolvedReferences
29+
from PySide.QtCore import *
30+
else:
31+
print("USAGE:")
32+
print(" qt.py pyqt")
33+
print(" qt.py pyside")
34+
sys.exit(1)
35+
36+
# Constants
37+
LINUX = (platform.system() == "Linux")
38+
WINDOWS = (platform.system() == "Windows")
39+
WIDTH = 800
40+
HEIGHT = 600
41+
42+
# OS differences
43+
CefWidgetParent = QWidget
44+
if LINUX:
45+
# noinspection PyUnresolvedReferences
46+
CefWidgetParent = QX11EmbedContainer
47+
48+
49+
def main():
50+
check_versions()
51+
sys.excepthook = cef.ExceptHook # To shutdown all CEF processes on error
52+
cef.Initialize()
53+
app = CefApplication(sys.argv)
54+
main_window = MainWindow()
55+
main_window.show()
56+
app.exec_()
57+
app.stopTimer()
58+
del main_window # Just to be safe, see below
59+
del app # Must destroy before calling Shutdown
60+
cef.Shutdown()
61+
62+
63+
def check_versions():
64+
print("[qt.py] CEF Python {ver}".format(ver=cef.__version__))
65+
print("[qt.py] Python {ver}".format(ver=sys.version[:6]))
66+
# PyQt version
67+
if "pyqt" in sys.argv:
68+
print("[qt.py] PyQt {v1} ({v2})".format(
69+
v1=PYQT_VERSION_STR, v2=qVersion()))
70+
# PySide version
71+
elif "pyside" in sys.argv:
72+
print("[qt.py] PySide {v1} ({v2})".format(
73+
v1=PySide.__version__, v2=QtCore.__version__))
74+
# CEF Python version requirement
75+
assert cef.__version__ >= "55.2", "CEF Python v55.2+ required to run this"
76+
77+
78+
class MainWindow(QMainWindow):
79+
80+
def __init__(self):
81+
super(MainWindow, self).__init__(None)
82+
self.cef_widget = None
83+
self.navigation_bar = None
84+
self.setupLayout()
85+
# Title
86+
if "pyqt" in sys.argv:
87+
self.setWindowTitle("PyQt example")
88+
elif "pyside" in sys.argv:
89+
self.setWindowTitle("PySide example")
90+
self.setFocusPolicy(Qt.StrongFocus)
91+
92+
def setupLayout(self):
93+
self.resize(WIDTH, HEIGHT)
94+
self.cef_widget = CefWidget(self)
95+
self.navigation_bar = NavigationBar(self.cef_widget)
96+
layout = QGridLayout()
97+
layout.addWidget(self.navigation_bar, 0, 0)
98+
layout.addWidget(self.cef_widget, 1, 0)
99+
layout.setContentsMargins(0, 0, 0, 0)
100+
layout.setSpacing(0)
101+
frame = QFrame()
102+
frame.setLayout(layout)
103+
self.setCentralWidget(frame)
104+
# Browser can be embedded only after layout was set up
105+
self.cef_widget.embedBrowser()
106+
107+
def setupNavbar(self):
108+
QLineEdit("Test")
109+
110+
def focusInEvent(self, event):
111+
if WINDOWS:
112+
# noinspection PyUnresolvedReferences
113+
cef.WindowUtils.OnSetFocus(int(self.centralWidget().winId()),
114+
0, 0, 0)
115+
print("[qt.py] focusInEvent")
116+
if self.cef_widget.browser:
117+
self.cef_widget.browser.SetFocus(True)
118+
119+
def focusOutEvent(self, event):
120+
print("[qt.py] focusOutEvent")
121+
122+
def closeEvent(self, event):
123+
# Close browser (force=True) and free CEF reference
124+
if self.cef_widget.browser:
125+
self.cef_widget.browser.CloseBrowser(True)
126+
self.cef_widget.browser = None # free ref
127+
128+
129+
class NavigationBar(QFrame):
130+
131+
def __init__(self, cef_widget):
132+
super(NavigationBar, self).__init__()
133+
self.cef_widget = cef_widget
134+
135+
# Init layout
136+
layout = QGridLayout()
137+
layout.setContentsMargins(0, 0, 0, 0)
138+
layout.setSpacing(0)
139+
140+
# Back button
141+
self.back = self.createButton("back")
142+
# noinspection PyUnresolvedReferences
143+
self.back.clicked.connect(self.onBack)
144+
layout.addWidget(self.back, 0, 0)
145+
146+
# Forward button
147+
self.forward = self.createButton("forward")
148+
# noinspection PyUnresolvedReferences
149+
self.forward.clicked.connect(self.onForward)
150+
layout.addWidget(self.forward, 0, 1)
151+
152+
# Reload button
153+
self.reload = self.createButton("reload")
154+
# noinspection PyUnresolvedReferences
155+
self.reload.clicked.connect(self.onReload)
156+
layout.addWidget(self.reload, 0, 2)
157+
158+
# Url input
159+
self.url = QLineEdit("")
160+
# noinspection PyUnresolvedReferences
161+
self.url.returnPressed.connect(self.onGoUrl)
162+
layout.addWidget(self.url, 0, 3)
163+
164+
# Layout
165+
self.setLayout(layout)
166+
self.updateState()
167+
168+
def onBack(self):
169+
if self.cef_widget.browser:
170+
self.cef_widget.browser.GoBack()
171+
172+
def onForward(self):
173+
if self.cef_widget.browser:
174+
self.cef_widget.browser.GoForward()
175+
176+
def onReload(self):
177+
if self.cef_widget.browser:
178+
self.cef_widget.browser.Reload()
179+
180+
def onGoUrl(self):
181+
if self.cef_widget.browser:
182+
self.cef_widget.browser.LoadUrl(self.url.text())
183+
184+
def updateState(self):
185+
browser = self.cef_widget.browser
186+
if not browser:
187+
self.back.setEnabled(False)
188+
self.forward.setEnabled(False)
189+
self.reload.setEnabled(False)
190+
self.url.setEnabled(False)
191+
return
192+
self.back.setEnabled(browser.CanGoBack())
193+
self.forward.setEnabled(browser.CanGoForward())
194+
self.reload.setEnabled(True)
195+
self.url.setEnabled(True)
196+
197+
def createButton(self, name):
198+
resources = os.path.join(os.path.abspath(os.path.dirname(__file__)),
199+
"resources")
200+
pixmap = QPixmap(os.path.join(resources, "{0}.png".format(name)))
201+
icon = QIcon(pixmap)
202+
button = QPushButton()
203+
button.setIcon(icon)
204+
button.setIconSize(pixmap.rect().size())
205+
return button
206+
207+
208+
class CefWidget(CefWidgetParent):
209+
210+
def __init__(self, parent=None):
211+
super(CefWidget, self).__init__(parent)
212+
self.parent = parent
213+
self.browser = None
214+
self.show()
215+
216+
def embedBrowser(self):
217+
self.width = 0
218+
self.height = 0
219+
window_info = cef.WindowInfo()
220+
window_info.SetAsChild(int(self.winId()))
221+
self.browser = cef.CreateBrowserSync(window_info,
222+
url="https://www.google.com/")
223+
self.browser.SetClientHandler(LoadHandler(self.parent.navigation_bar))
224+
self.browser.SetClientHandler(FocusHandler(self))
225+
226+
def moveEvent(self, _):
227+
# pos = event.pos()
228+
# self.x = pos.x()
229+
# self.y = pos.y()
230+
self.x = 0
231+
self.y = 0
232+
if self.browser:
233+
if WINDOWS:
234+
# noinspection PyUnresolvedReferences
235+
cef.WindowUtils.OnSize(int(self.winId()), 0, 0, 0)
236+
elif LINUX:
237+
# noinspection PyUnresolvedReferences
238+
self.browser.SetBounds(self.x, self.y, self.width, self.height)
239+
240+
def resizeEvent(self, event):
241+
size = event.size()
242+
self.width = size.width()
243+
self.height = size.height()
244+
if self.browser:
245+
if WINDOWS:
246+
# noinspection PyUnresolvedReferences
247+
cef.WindowUtils.OnSize(int(self.winId()), 0, 0, 0)
248+
elif LINUX:
249+
# noinspection PyUnresolvedReferences
250+
self.browser.SetBounds(self.x, self.y, self.width, self.height)
251+
252+
253+
class CefApplication(QApplication):
254+
255+
def __init__(self, args):
256+
super(CefApplication, self).__init__(args)
257+
self.timer = self.createTimer()
258+
self.setupIcon()
259+
260+
def createTimer(self):
261+
timer = QTimer()
262+
# noinspection PyUnresolvedReferences
263+
timer.timeout.connect(self.onTimer)
264+
timer.start(10)
265+
return timer
266+
267+
def onTimer(self):
268+
# For best performance, a proper way of doing message loop should
269+
# probably be:
270+
# 1. In createTimer() call self.timer.start(0)
271+
# 2. In onTimer() call MessageLoopWork() only when
272+
# QtGui.QApplication.instance()->hasPendingEvents() returns False.
273+
# But... there is a bug in Qt, hasPendingEvents() always returns true.
274+
# TODO: The bug above was noticed in Qt 4.8 on Windows. Other versions
275+
# and/or other OSes may not be affected, so check it.
276+
cef.MessageLoopWork()
277+
278+
def stopTimer(self):
279+
# Stop the timer after Qt's message loop has ended
280+
self.timer.stop()
281+
282+
def setupIcon(self):
283+
icon_file = os.path.join(os.path.abspath(os.path.dirname(__file__)),
284+
"resources", "{0}.png".format(sys.argv[1]))
285+
if os.path.exists(icon_file):
286+
self.setWindowIcon(QIcon(icon_file))
287+
288+
289+
class LoadHandler(object):
290+
291+
def __init__(self, navigation_bar):
292+
self.navigation_bar = navigation_bar
293+
294+
def OnLoadingStateChange(self, *_):
295+
self.navigation_bar.updateState()
296+
297+
def OnLoadStart(self, browser, *_):
298+
self.navigation_bar.url.setText(browser.GetUrl())
299+
300+
301+
class FocusHandler(object):
302+
"""FocusHandler must be set for the browser, otherwise keyboard
303+
focus issues occur. If there are still focus issues see Issue #284."""
304+
305+
def __init__(self, cef_widget):
306+
self.cef_widget = cef_widget
307+
308+
def OnTakeFocus(self, *args):
309+
pass
310+
# print("[qt.py] FocusHandler.OnTakeFocus, next={next}"
311+
# .format(next=args[1]))
312+
313+
def OnSetFocus(self, *args):
314+
pass
315+
# source_enum = {cef.FOCUS_SOURCE_NAVIGATION: "navigation",
316+
# cef.FOCUS_SOURCE_SYSTEM: "system"}
317+
# print("[qt.py] FocusHandler.OnSetFocus, source={source}"
318+
# .format(source=source_enum[args[1]]))
319+
# return False
320+
321+
def OnGotFocus(self, browser):
322+
# print("[qt.py] FocusHandler.OnGotFocus")
323+
browser.SetFocus(True)
324+
325+
326+
if __name__ == '__main__':
327+
main()

examples/resources/pyqt.png

20.3 KB
Loading

examples/resources/pyside.png

26.8 KB
Loading

examples/tkinter_.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# Example of embedding CEF Python browser using Tkinter toolkit.
22
# This example has two widgets: a navigation bar and a browser.
3-
# Tested with Tk 8.6 and CEF Python v53+.
4-
3+
#
4+
# Tested with Tk 8.6 and CEF Python v53.1+, only on Linux.
5+
#
56
# Known issue on Linux: When typing url, mouse must be over url
67
# entry widget otherwise keyboard focus is lost (Issue #255
7-
# and Issue #284)
8+
# and Issue #284).
89

910
from cefpython3 import cefpython as cef
1011
try:

0 commit comments

Comments
 (0)