在主 window 菜单栏中设置父嵌入小部件

Setting parent embeds widget in main window menu bar

设置小部件的父级以便可以从子级访问 window 图标等属性的正确方法是什么?

我创建了一个小部件来在 QWebEngineView 中显示应用程序文档。我希望小部件使用与父级相同的 window 图标。当父级为 None 时,小部件按预期工作(当然不包括没有 window 图标):

但是,当我设置父级时,文档小部件将自身嵌入主 window 的菜单栏中:

# SETTING PARENT HERE CAUSES GRIEF
self.doc_viewer = DocumentationViewer(self)

我不确定发生了什么。此外,我发现如果我使用 QDialog 而不是 QWidget,则一切正常。我无法解释为什么。

完整代码:

import sys
from PyQt5 import QtCore, QtWidgets, QtGui, QtWebEngineWidgets


class DocumentationViewer(QtWidgets.QWidget):
    def __init__(self, parent=None, index="docs/index.html"):
        super().__init__(parent=parent)

        if parent:
            self.setWindowIcon(parent.windowIcon())

        self.setWindowTitle("Manual")

        self.init_widgets()
        self.init_layout()

        self.index = QtCore.QUrl('file:///' + index)
        self.view.load(self.index)

    def init_widgets(self):
        # history back
        icon = QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_ArrowBack)
        self.history_back_button = QtWidgets.QToolButton()
        self.history_back_button.setIcon(icon)

        # history forward
        icon = QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_ArrowForward)
        self.history_forward_button = QtWidgets.QToolButton()
        self.history_forward_button.setIcon(icon)

        # reload
        icon = QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_ArrowUp)
        self.reload_button = QtWidgets.QToolButton()
        self.reload_button.setIcon(icon)

        # find forward
        icon = QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_MediaSeekForward)
        self.find_forward_button = QtWidgets.QToolButton()
        self.find_forward_button.setIcon(icon)

        # find backward
        icon = QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_MediaSeekBackward)
        self.find_backward_button = QtWidgets.QToolButton()
        self.find_backward_button.setIcon(icon)

        # find box
        self.find = QtWidgets.QLineEdit()
        self.find.setPlaceholderText('Find...')

        self.view = QtWebEngineWidgets.QWebEngineView()

    def init_layout(self):
        navigation_layout = QtWidgets.QHBoxLayout()
        navigation_layout.addWidget(self.reload_button)
        navigation_layout.addWidget(self.history_back_button)
        navigation_layout.addWidget(self.history_forward_button)
        navigation_layout.addWidget(QtWidgets.QWidget(), stretch=1)
        navigation_layout.addWidget(self.find)
        navigation_layout.addWidget(self.find_backward_button)
        navigation_layout.addWidget(self.find_forward_button)

        layout = QtWidgets.QVBoxLayout()
        layout.setContentsMargins(5, 5, 5 ,5)
        layout.addLayout(navigation_layout)
        layout.addWidget(self.view)
        self.setLayout(layout)


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()

        icon = QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_TitleBarMenuButton)
        self.setWindowIcon(icon)

        self.init_widgets()
        self.init_layout()

    def init_widgets(self):

        self.menu = self.menuBar()

        # File menu
        self.exit_action = QtWidgets.QAction('&Exit', self)
        self.exit_action.triggered.connect(self.close)

        self.menu_file = self.menu.addMenu('&File')
        self.menu_file.addAction(self.exit_action)

        # Help menu
        self.manual_action = QtWidgets.QAction("&Manual", self)
        self.manual_action.triggered.connect(self.on_manual_action)

        self.menu_help = self.menu.addMenu('&Help')
        self.menu_help.addAction(self.manual_action)

        # SETTING PARENT HERE CAUSES GRIEF
        self.doc_viewer = DocumentationViewer()

    def init_layout(self):

        layout = QtWidgets.QVBoxLayout()
        layout.setContentsMargins(5, 5, 5, 5)
        layout.addWidget(QtWidgets.QLabel("Main Widget Content"))

        centralWidget = QtWidgets.QWidget()
        centralWidget.setLayout(layout)
        self.setCentralWidget(centralWidget)

    def on_manual_action(self):
        self.doc_viewer.show()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

共有三种选择。

  1. ,继承自QDialog而不是QWidget;

  2. 在小部件构造函数中为 flags 关键字使用 Window 标志(这是 QDialog 实际上自己做的事情),这在确保小部件有自己的 window:

    super().__init__(parent=parent, flags=QtCore.Qt.Window)

  3. 为整个 QApplication 设置一个默认的 window 图标 setWindowIcon()