如何创建抽屉实例并将其附加到 MainWindow

How to create a Drawer instance and attach it to MainWindow

我正在努力向我的应用程序添加侧边菜单。

我有一个 QMainWindow 实例,我希望向其添加一个 QDrawer 对象并实现类似于 this sample.

的效果

不幸的是,PySide2 似乎只提供 QMenuQTooltipQDialog 小部件,它们继承自 Popup class, QDrawer 无处可寻。但是,在 QML 文件中使用 Drawer 标签效果很好。难道还不能以编程方式创建 QDrawer 的实例吗?

作为另一次尝试,我尝试从 QML 文件加载一个 Drawer 实例并将其附加到我的 QMainWindow。不幸的是,我不太明白我应该指定什么作为父级,我应该将它包装在什么中,我应该使用什么参数等等 - 任何建议将不胜感激(尽管我更愿意以编程方式创建和配置它)。

我的目标是创建一个 QMainWindow,带有工具栏、中央小部件和 QDrawer 实例作为侧面导航菜单(例如 this 示例)。您能否分享一些示例或解释该怎么做?

一个可能的解决方案是使用 Qt Widgets 实现抽屉,主要功能是使用 QXAnimation 为宽度的变化设置动画,另一个任务是设置锚点,使其占据必要的高度。一个简单的示例如下面的代码所示:

import os

from PySide2 import QtCore, QtGui, QtWidgets


class Drawer(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFixedWidth(0)
        self.setContentsMargins(0, 0, 0, 0)
        # self.setFixedWidth(0)
        self._maximum_width = 0

        self._animation = QtCore.QPropertyAnimation(self, b"width")
        self._animation.setStartValue(0)
        self._animation.setDuration(1000)
        self._animation.valueChanged.connect(self.setFixedWidth)
        self.hide()

    @property
    def maximum_width(self):
        return self._maximum_width

    @maximum_width.setter
    def maximum_width(self, w):
        self._maximum_width = w
        self._animation.setEndValue(self.maximum_width)

    def open(self):
        self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
        self._animation.start()
        self.show()

    def close(self):
        self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
        self._animation.start()


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowFlag(QtCore.Qt.FramelessWindowHint)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)

        self.tool_button = QtWidgets.QToolButton(
            checkable=True, iconSize=QtCore.QSize(36, 36)
        )

        content_widget = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
        content_widget.setText("Content")
        content_widget.setStyleSheet("background-color: green")

        lay = QtWidgets.QVBoxLayout(central_widget)
        lay.setSpacing(0)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.tool_button)
        lay.addWidget(content_widget)

        self.resize(640, 480)

        self.drawer = Drawer(self)
        self.drawer.move(0, self.tool_button.sizeHint().height())
        self.drawer.maximum_width = 200
        self.drawer.raise_()

        content_lay = QtWidgets.QVBoxLayout()
        content_lay.setContentsMargins(0, 0, 0, 0)
        label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
        label.setText("Content\nDrawer")
        label.setStyleSheet("background-color: red")
        content_lay.addWidget(label)
        self.drawer.setLayout(content_lay)

        self.tool_button.toggled.connect(self.onToggled)

        self.onToggled(self.tool_button.isChecked())

        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.onCustomContextMenuRequested)

    @QtCore.Slot()
    def onCustomContextMenuRequested(self):
        menu = QtWidgets.QMenu()
        quit_action = menu.addAction(self.tr("Close"))
        action = menu.exec_(QtGui.QCursor.pos())
        if action == quit_action:
            self.close()

    @QtCore.Slot(bool)
    def onToggled(self, checked):
        if checked:
            self.tool_button.setIcon(
                self.style().standardIcon(QtWidgets.QStyle.SP_MediaStop)
            )
            self.drawer.open()
        else:
            self.tool_button.setIcon(
                self.style().standardIcon(QtWidgets.QStyle.SP_MediaPlay)
            )
            self.drawer.close()

    def resizeEvent(self, event):
        self.drawer.setFixedHeight(self.height() - self.drawer.pos().y())
        super().resizeEvent(event)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())