首页 > 解决方案 > 如何创建 Drawer 实例并将其附加到 MainWindow

问题描述

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

我有一个QMainWindow实例,我希望向其中添加一个QDrawer对象并实现与此示例类似的效果。

不幸的是,似乎PySide2只提供了QMenu,QTooltip和从类QDialog继承的小部件,并且无处可寻。但是,在 QML 文件中使用标签就可以了。难道不应该也可以以编程方式创建一个实例吗?PopupQDrawerDrawerQDrawer

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

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

标签: pythonqtpyside2drawer

解决方案


一种可能的解决方案是使用 Qt Widgets 实现 Drawer,主要功能是动画宽度的变化,例如使用 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_())

推荐阅读