CEFPython嵌入PyQt5应用运行失败,求代码问题排查
错误点汇总及修复方案
已知错误列表
- 导航栏初始化时browser对象为空:在
ChromiumBrowserWindow.init_window方法中,你创建NavigationBar的时机早于web_view.init_browser()的执行时机,此时self.web_view.browser为None,导航栏所有交互功能都无法生效。 - CEF窗口未嵌入Qt界面:你创建了承载CEF内容的
QWindow对象,但没有将其封装为Qt可识别的组件加入WebViewWidget的布局中,CEF窗口和你的应用界面完全分离,无法正常显示。 - 方法名拼写错误:
WebViewWidget.set_handlers方法中调用的SetClientHanlder拼写错误,正确方法名为SetClientHandler,运行到此处会直接抛出属性异常。 - 缺少尺寸同步逻辑:未重写
WebViewWidget的resizeEvent方法,主窗口尺寸变化时CEF内容区域不会同步调整大小,会出现显示错位、空白等问题。 - 导航栏构造未传入父组件:
NavigationBar的构造方法中调用父类构造时未传入parent参数,可能导致导航栏渲染异常。 - 导航栏按钮无文本兜底:如果本地不存在对应的svg图标文件,导航栏按钮会完全透明不可见。
修复后代码
主程序代码
import sys from PyQt5.QtCore import QTimer, QRect from PyQt5.QtGui import QWindow from PyQt5.QtWidgets import * from cefpython3 import cefpython as cef from navbar import NavigationBar class ChromiumApplication(QApplication): def __init__(self): super().__init__([]) self.timer = self.create_timer() def create_timer(self): timer = QTimer() timer.timeout.connect(self.on_timeout) timer.start(10) return timer def on_timeout(self): cef.MessageLoopWork() class ChromiumBrowserWindow(QMainWindow): DEFAULT_TITLE = "Chromium Browser" DEFAULT_WIDTH = 800 DEFAULT_HEIGHT = 600 def __init__(self): super().__init__() self.chrome = None self.web_view = None self.setWindowTitle(self.DEFAULT_TITLE) self.init_window() self.show() def init_window(self): self.resize(self.DEFAULT_WIDTH, self.DEFAULT_HEIGHT) self.web_view = WebViewWidget(parent=self) # 先初始化浏览器,再创建导航栏传入有效的browser对象 self.web_view.init_browser() self.chrome = NavigationBar(parent=self, browser=self.web_view.browser) layout = QGridLayout() layout.addWidget(self.chrome, 0, 0) layout.setColumnStretch(0, 1) layout.addWidget(self.web_view, 1, 0) layout.setRowStretch(1, 2) layout.setContentsMargins(0, 0, 0, 0) frame = QFrame() frame.setLayout(layout) self.setCentralWidget(frame) def closeEvent(self, event): if self.web_view.browser is not None: self.web_view.browser.CloseBrowser(True) self.web_view.browser = None event.accept() class WebViewWidget(QWidget): DEFAULT_URL = "https://www.google.com" HANDLERS = [] def __init__(self, parent=None): super().__init__(parent) self.parent = parent self.browser = None self.browser_window = None # 新增布局用于承载CEF窗口容器 self.layout = QVBoxLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) def init_browser(self): self.browser_window = QWindow() # 将QWindow封装为QWidget组件加入布局 browser_container = QWidget.createWindowContainer(self.browser_window, self) self.layout.addWidget(browser_container) window_config = cef.WindowInfo() rect_pos_and_size = [0, 0, self.width(), self.height()] window_config.SetAsChild(self.get_window_handle(), rect_pos_and_size) self.browser = cef.CreateBrowserSync(window_config, url=self.DEFAULT_URL) self.set_handlers() def get_window_handle(self): return int(self.browser_window.winId()) def set_handlers(self): for handler in self.HANDLERS: # 修正拼写错误 self.browser.SetClientHandler(handler(self)) # 新增尺寸同步逻辑 def resizeEvent(self, event): if self.browser: self.browser.SetBounds(0, 0, self.width(), self.height()) super().resizeEvent(event) if __name__ == "__main__": sys.excepthook = cef.ExceptHook cef.Initialize() app = ChromiumApplication() window = ChromiumBrowserWindow() app.exec() app.timer.stop() cef.Shutdown()
导航栏组件代码
from PyQt5.QtWidgets import ( QApplication, QFrame, QHBoxLayout, QPushButton, QLineEdit, ) class NavigationBar(QFrame): def __init__(self, parent=None, browser=None): # 传入parent参数 super().__init__(parent) self.parent = parent self.browser = browser self.back_btn = self.create_button("Back") self.back_btn.clicked.connect(self.on_back) self.forward_btn = self.create_button("Forward") self.forward_btn.clicked.connect(self.on_forward) self.refresh_btn = self.create_button("Refresh") self.refresh_btn.clicked.connect(self.on_refresh) self.url_bar = self.create_url_bar() self.url_bar.returnPressed.connect(self.on_search) self.frame_layout = QHBoxLayout() self.init_layout() def create_button(self, name): button_icon_path = f"./{name}.svg" button = QPushButton(name) # 新增文字兜底,无图标也能看见按钮 button.setStyleSheet(f""" QPushButton {{ background-image: url("{button_icon_path}"); background-repeat: no-repeat; background-position: center; background-color: rgba(0, 0, 0, 0.1); border: 10px; border-radius: 8px; padding: 10px; color: #fff; }} QPushButton:hover {{ background-color: rgba(0, 0, 0, 0.5); }} QPushButton:pressed {{ background-color: none; }} """) return button def create_url_bar(self): search = QLineEdit() search.setStyleSheet("""QLineEdit { min-width: 300px; padding: 10px; margin-left: 50px; margin-right: 30px; border-width: 10px; border-radius: 8px; background-color: rgba(0, 0, 0, 0.2); color: white; } QLineEdit:hover { background-color: #454549; } """) return search def init_layout(self): self.setStyleSheet(""" background: #2A292E; max-height: 40px; """) self.frame_layout.addWidget(self.back_btn, 0) self.frame_layout.addWidget(self.forward_btn, 0) self.frame_layout.addWidget(self.refresh_btn, 0) self.frame_layout.addWidget(self.url_bar, 1) self.setLayout(self.frame_layout) def on_back(self): if self.browser is not None: self.browser.GoBack() def on_forward(self): if self.browser is not None: self.browser.GoForward() def on_refresh(self): if self.browser is not None: self.browser.Reload() def on_search(self): if self.browser is not None: url = self.url_bar.text() self.browser.LoadUrl(url) if __name__ == "__main__": app = QApplication([]) nav = NavigationBar() nav.show() app.exec()
内容的提问来源于stack exchange,提问作者Sujal Singh
相关产品推荐
相关产品推荐

