CEFPython 无法嵌入到 pyqt5 应用程序中

CEFPython unable to embed inside pyqt5 application

我是 Cefpython 和 PyQt5 的新手。我试图按照 cefpython 存储库中的教程进行操作。 我试图将 cefpython 嵌入到 pyqt 应用程序中,但没有取得任何成功,这里有什么问题吗?

import sys

from PyQt5.QtCore import QTimer
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)
        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)

        self.web_view.init_browser()

    def closeEvent(self, event):
        if self.web_view.browser is not None:
            self.web_view.browser.CloseBrowser(True)  # force=True
            self.web_view.browser = None  # required to close cleanly


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
        self.timer = None

    def init_browser(self):
        self.browser_window = QWindow()
        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.SetClientHanlder(handler(self))


if __name__ == "__main__":
    sys.excepthook = cef.ExceptHook
    cef.Initialize()
    app = ChromiumApplication()
    window = ChromiumBrowserWindow()
    app.exec()
    app.timer.stop()
    cef.Shutdown()

我知道问题出在我的代码上,因为 cefpython 提供的示例在我的机器上运行完美。我不知道我在这里做错了什么,任何建议都会有所帮助!

编辑:(导航栏代码)

from PyQt5.QtWidgets import (
    QApplication,
    QFrame,
    QHBoxLayout,
    QPushButton,
    QLineEdit,
)


class NavigationBar(QFrame):
    def __init__(self, parent=None, browser=None):
        super().__init__()
        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()
        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;
        }}
        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()

问题是用于渲染浏览器的 QWindow 被隐藏了。解决方案是使用 QWidget::createWindowContainer() 创建一个 QWidget 并使用布局添加它。

import sys

from cefpython3 import cefpython as cef


from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QWindow
from PyQt5.QtWidgets import QApplication, QFrame, QGridLayout, QMainWindow, QVBoxLayout, QWidget

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()
        self.chrome = NavigationBar(parent=self, browser=self.web_view.browser)

        frame = QFrame()
        self.setCentralWidget(frame)
        layout = QGridLayout(frame)
        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)

    def closeEvent(self, event):
        if self.web_view.browser is not None:
            self.web_view.browser.CloseBrowser(True)
            del self.web_view.browser


class WebViewWidget(QWidget):
    DEFAULT_URL = "https://www.google.com"
    HANDLERS = []

    def __init__(self, parent=None):
        super().__init__(parent)
        self._browser = None
        self._browser_widget = None
        lay = QVBoxLayout(self)
        lay.setContentsMargins(0, 0, 0, 0)
        self.init_browser()

    @property
    def browser(self):
        return self._browser

    @browser.deleter
    def browser(self):
        self._browser = None

    def init_browser(self):
        browser_window = QWindow()
        window_config = cef.WindowInfo()
        window_config.SetAsChild(
            int(browser_window.winId()), list(self.rect().getRect())
        )
        self._browser = cef.CreateBrowserSync(window_config, url=self.DEFAULT_URL)
        self._browser_widget = QWidget.createWindowContainer(browser_window)
        self.layout().addWidget(self._browser_widget)
        self.set_handlers()

    def set_handlers(self):
        for handler in self.HANDLERS:
            self.browser.SetClientHanlder(handler(self))

    def resizeEvent(self, event):
        if self.browser and self._browser_widget:
            self.browser.SetBounds(*self._browser_widget.geometry().getRect())
            self.browser.NotifyMoveOrResizeStarted()


if __name__ == "__main__":
    sys.excepthook = cef.ExceptHook
    cef.Initialize()
    app = ChromiumApplication()
    window = ChromiumBrowserWindow()
    app.exec()
    app.timer.stop()
    cef.Shutdown()