【问题标题】:How use QML Drawer with Qt Widgets?如何将 QML Drawer 与 Qt 小部件一起使用?
【发布时间】:2020-05-06 18:26:45
【问题描述】:

我想知道如何使 QApplication UI 成为 PyQt5 项目中 QML Drawer 项的根窗口。

原则上,我可以让它们一起工作,但抽屉一直显示在不同的窗口上,而不是对根窗口应用相同的效果。

作为一个例子,我试图将“Qt Quick Controls 2 - Gallery”的功能包含到项目中。

查看以下代码了解更多详情:

# mainwindow.py

class MainWindow:

   def __init__(self):
      self.qtApplication = QtWidgets.QApplication([])
      qtPbObj = QtWidgets.QPushButton
      QtWidgets.QPushButton = hoverButton

      self.mw = QtWidgets.QMainWindow()
      self.mw.setWindowFlags(Qt.FramelessWindowHint | self.mw.windowFlags())
      self.qtMainWindowUi = main_ui.Ui_MainWindow()
      self.qtMainWindowUi.setupUi(self.mw)
      QtWidgets.QPushButton = qtPbObj

       ...

      engine = QQmlApplicationEngine()

      context = engine.rootContext()
      file = os.path.join(DIR_PATH, "main.qml")
      url = QUrl.fromLocalFile(file)    
      engine.load(url)

      engine.setParent(self.qtApplication.instance())

      if not engine.rootObjects():
         logger.error("No object could be loaded from sourced QML file")
         self.qtApplication.exit(-1)

      rootWindow = engine.rootObjects()[0]

使用的QML文件可以在here找到。


更新:

在项目中,在实现 setupUiframeless 功能的同时,我希望 QML Drawer 功能仅在单击“≡”时可用,以便它与 MainWindow central_widget 重叠:

附上一些截图来更好地解释实际状态:

实际用户界面:

理想的解决方案:

【问题讨论】:

    标签: python pyqt qml pyqt5


    【解决方案1】:

    我认为您混淆了概念,QWidget 的根不是 QApplication 而是必要的要求。在您的情况下,您必须将 QML 应用程序嵌入到 QWidget 中,为此,other answer 中指出了几种替代方法,但在这种情况下,我将使用 QQuickView 展示解决方案。

    对于上述情况,必须修改以下内容:

    • 由于要使用QQuickView,所以不应该使用ApplicationWindow,但root必须是一个Item,并重新分配ToolBar、StackView和Drawer,以保持GUI结构..

    • 由于我不会使用.qrc,所以必须将“qrc:/pages/...”模型中放置的路径修改为“pages/...”。

    • 无法从 PyQt 访问 QQuickStyle 类,因此必须交替实施建立样式和图标的解决方案。

    综合以上,代码如下:

    ma​​in.py

    import os
    import sys
    
    from PyQt5 import QtCore, QtGui, QtQuick, QtWidgets
    
    DIR_PATH = os.path.dirname(os.path.realpath(__file__))
    ICON_DIR = os.path.join(DIR_PATH, "icons")
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            central_widget = QtWidgets.QWidget()
            self.setCentralWidget(central_widget)
    
            lay = QtWidgets.QHBoxLayout(central_widget)
    
            lay.addWidget(QtWidgets.QLabel("QLabel", alignment=QtCore.Qt.AlignCenter))
    
            file = os.path.join(DIR_PATH, "gallery.qml")
            self.view = QtQuick.QQuickView()
            self.view.statusChanged.connect(self.on_statusChanged)
            self.view.setResizeMode(QtQuick.QQuickView.SizeRootObjectToView)
            engine = self.view.engine()
            context = engine.rootContext()
            context.setContextProperty("availableStyles", availableStyles())
            self.view.setSource(QtCore.QUrl.fromLocalFile(file))
            widget = QtWidgets.QWidget.createWindowContainer(self.view)
            lay.addWidget(widget)
    
        def on_statusChanged(self, status):
            if status == QtQuick.QQuickView.Error:
                for error in self.view.errors():
                    print(error.toString())
                sys.exit(-1)
    
    
    def availableStyles():
        # https://github.com/qt/qtquickcontrols2/blob/5.14/src/quickcontrols2/qquickstyle.cpp#L591
    
        importPaths = [
            QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.Qml2ImportsPath),
            ":/qt-project.org/imports",
            QtCore.QCoreApplication.applicationDirPath(),
            DIR_PATH,
        ]
        path = os.environ.get("QT_QUICK_CONTROLS_STYLE_PATH", "")
        if path:
            importPaths.append(path)
    
        stylePaths = []
        targetPath = "QtQuick/Controls.2"
        for importPath in importPaths:
            d = QtCore.QDir(importPath)
            if d.cd(targetPath):
                stylePaths.append(d.absolutePath())
    
        styles = []
        for path in stylePaths:
            entries = QtCore.QDir(path).entryInfoList(
                QtCore.QDir.Dirs | QtCore.QDir.NoDotAndDotDot
            )
            for entry in entries:
                name = entry.fileName()
                if not name.endswith(".dSYM") and name != "designer":
                    # print(path, name)
                    styles.append(name)
        return list(set(styles))
    
    
    def main():
    
        QtCore.QCoreApplication.setApplicationName("Gallery")
        QtCore.QCoreApplication.setOrganizationName("QtProject")
        QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
        app = QtWidgets.QApplication(sys.argv)
    
        QtGui.QIcon.setThemeSearchPaths(QtGui.QIcon.themeSearchPaths() + [ICON_DIR])
        QtGui.QIcon.setThemeName("gallery")
    
        default_style = "Material"
    
        settings = QtCore.QSettings()
        style = settings.value("style")
        if not style:
            style = default_style
            settings.setValue("style", style)
    
        os.environ["QT_QUICK_CONTROLS_STYLE"] = style
    
        w = MainWindow()
        w.showMaximized()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    gallery.qml

    /****************************************************************************
    **
    ** Copyright (C) 2017 The Qt Company Ltd.
    ** Contact: https://www.qt.io/licensing/
    **
    ** This file is part of the examples of the Qt Toolkit.
    **
    ** $QT_BEGIN_LICENSE:BSD$
    ** Commercial License Usage
    ** Licensees holding valid commercial Qt licenses may use this file in
    ** accordance with the commercial license agreement provided with the
    ** Software or, alternatively, in accordance with the terms contained in
    ** a written agreement between you and The Qt Company. For licensing terms
    ** and conditions see https://www.qt.io/terms-conditions. For further
    ** information use the contact form at https://www.qt.io/contact-us.
    **
    ** BSD License Usage
    ** Alternatively, you may use this file under the terms of the BSD license
    ** as follows:
    **
    ** "Redistribution and use in source and binary forms, with or without
    ** modification, are permitted provided that the following conditions are
    ** met:
    **   * Redistributions of source code must retain the above copyright
    **     notice, this list of conditions and the following disclaimer.
    **   * Redistributions in binary form must reproduce the above copyright
    **     notice, this list of conditions and the following disclaimer in
    **     the documentation and/or other materials provided with the
    **     distribution.
    **   * Neither the name of The Qt Company Ltd nor the names of its
    **     contributors may be used to endorse or promote products derived
    **     from this software without specific prior written permission.
    **
    **
    ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
    **
    ** $QT_END_LICENSE$
    **
    ****************************************************************************/
    
    import QtQuick 2.12
    import QtQuick.Layouts 1.12
    import QtQuick.Controls 2.12
    import QtQuick.Controls.Material 2.12
    import QtQuick.Controls.Universal 2.12
    import QtQuick.Layouts 1.14
    import Qt.labs.settings 1.0
    
    Item {
        id: window
        width: 360
        height: 520
        visible: true
        //title: "Qt Quick Controls 2"
    
        Settings {
            id: settings
            property string style: "Default"
        }
    
        Shortcut {
            sequences: ["Esc", "Back"]
            enabled: stackView.depth > 1
            onActivated: navigateBackAction.trigger()
        }
    
        Action {
            id: navigateBackAction
            icon.name: stackView.depth > 1 ? "back" : "drawer"
            onTriggered: {
                if (stackView.depth > 1) {
                    stackView.pop()
                    listView.currentIndex = -1
                } else {
                    drawer.open()
                }
            }
        }
    
        Shortcut {
            sequence: "Menu"
            onActivated: optionsMenuAction.trigger()
        }
    
        Action {
            id: optionsMenuAction
            icon.name: "menu"
            onTriggered: optionsMenu.open()
        }
    
        Drawer {
            id: drawer
            width: Math.min(window.width, window.height) / 3 * 2
            height: window.height
            interactive: stackView.depth === 1
    
            ListView {
                id: listView
    
                focus: true
                currentIndex: -1
                anchors.fill: parent
    
                delegate: ItemDelegate {
                    width: parent.width
                    text: model.title
                    highlighted: ListView.isCurrentItem
                    onClicked: {
                        listView.currentIndex = index
                        stackView.push(model.source)
                        drawer.close()
                    }
                }
    
                model: ListModel {
                    ListElement { title: "BusyIndicator"; source: "pages/BusyIndicatorPage.qml" }
                    ListElement { title: "Button"; source: "pages/ButtonPage.qml" }
                    ListElement { title: "CheckBox"; source: "pages/CheckBoxPage.qml" }
                    ListElement { title: "ComboBox"; source: "pages/ComboBoxPage.qml" }
                    ListElement { title: "DelayButton"; source: "pages/DelayButtonPage.qml" }
                    ListElement { title: "Dial"; source: "pages/DialPage.qml" }
                    ListElement { title: "Dialog"; source: "pages/DialogPage.qml" }
                    ListElement { title: "Delegates"; source: "pages/DelegatePage.qml" }
                    ListElement { title: "Frame"; source: "pages/FramePage.qml" }
                    ListElement { title: "GroupBox"; source: "pages/GroupBoxPage.qml" }
                    ListElement { title: "PageIndicator"; source: "pages/PageIndicatorPage.qml" }
                    ListElement { title: "ProgressBar"; source: "pages/ProgressBarPage.qml" }
                    ListElement { title: "RadioButton"; source: "pages/RadioButtonPage.qml" }
                    ListElement { title: "RangeSlider"; source: "pages/RangeSliderPage.qml" }
                    ListElement { title: "ScrollBar"; source: "pages/ScrollBarPage.qml" }
                    ListElement { title: "ScrollIndicator"; source: "pages/ScrollIndicatorPage.qml" }
                    ListElement { title: "Slider"; source: "pages/SliderPage.qml" }
                    ListElement { title: "SpinBox"; source: "pages/SpinBoxPage.qml" }
                    ListElement { title: "StackView"; source: "pages/StackViewPage.qml" }
                    ListElement { title: "SwipeView"; source: "pages/SwipeViewPage.qml" }
                    ListElement { title: "Switch"; source: "pages/SwitchPage.qml" }
                    ListElement { title: "TabBar"; source: "pages/TabBarPage.qml" }
                    ListElement { title: "TextArea"; source: "pages/TextAreaPage.qml" }
                    ListElement { title: "TextField"; source: "pages/TextFieldPage.qml" }
                    ListElement { title: "ToolTip"; source: "pages/ToolTipPage.qml" }
                    ListElement { title: "Tumbler"; source: "pages/TumblerPage.qml" }
                }
    
                ScrollIndicator.vertical: ScrollIndicator { }
            }
        }
    
        ColumnLayout{
            anchors.fill: parent
            ToolBar {
                Material.foreground: "white"
                Layout.fillWidth: true
                RowLayout {
                    spacing: 20
                    anchors.fill: parent
    
                    ToolButton {
                        action: navigateBackAction
                    }
    
                    Label {
                        id: titleLabel
                        text: listView.currentItem ? listView.currentItem.text : "Gallery"
                        font.pixelSize: 20
                        elide: Label.ElideRight
                        horizontalAlignment: Qt.AlignHCenter
                        verticalAlignment: Qt.AlignVCenter
                        Layout.fillWidth: true
                    }
    
                    ToolButton {
                        action: optionsMenuAction
    
                        Menu {
                            id: optionsMenu
                            x: parent.width - width
                            transformOrigin: Menu.TopRight
    
                            Action {
                                text: "Settings"
                                onTriggered: settingsDialog.open()
                            }
                            Action {
                                text: "About"
                                onTriggered: aboutDialog.open()
                            }
                        }
                    }
                }
            }
    
    
            StackView {
                id: stackView
                Layout.fillWidth: true
                Layout.fillHeight: true
    
                initialItem: Pane {
                    id: pane
    
                    Image {
                        id: logo
                        width: pane.availableWidth / 2
                        height: pane.availableHeight / 2
                        anchors.centerIn: parent
                        anchors.verticalCenterOffset: -50
                        fillMode: Image.PreserveAspectFit
                        source: "images/qt-logo.png"
                    }
    
                    Label {
                        text: "Qt Quick Controls 2 provides a set of controls that can be used to build complete interfaces in Qt Quick."
                        anchors.margins: 20
                        anchors.top: logo.bottom
                        anchors.left: parent.left
                        anchors.right: parent.right
                        anchors.bottom: arrow.top
                        horizontalAlignment: Label.AlignHCenter
                        verticalAlignment: Label.AlignVCenter
                        wrapMode: Label.Wrap
                    }
    
                    Image {
                        id: arrow
                        source: "images/arrow.png"
                        anchors.left: parent.left
                        anchors.bottom: parent.bottom
                    }
                }
            }
    
            Dialog {
                id: settingsDialog
                x: Math.round((window.width - width) / 2)
                y: Math.round(window.height / 6)
                width: Math.round(Math.min(window.width, window.height) / 3 * 2)
                modal: true
                focus: true
                title: "Settings"
    
                standardButtons: Dialog.Ok | Dialog.Cancel
                onAccepted: {
                    settings.style = styleBox.displayText
                    settingsDialog.close()
                }
                onRejected: {
                    styleBox.currentIndex = styleBox.styleIndex
                    settingsDialog.close()
                }
    
                contentItem: ColumnLayout {
                    id: settingsColumn
                    spacing: 20
    
                    RowLayout {
                        spacing: 10
    
                        Label {
                            text: "Style:"
                        }
    
                        ComboBox {
                            id: styleBox
                            property int styleIndex: -1
                            model: availableStyles
                            Component.onCompleted: {
                                styleIndex = find(settings.style, Qt.MatchFixedString)
                                if (styleIndex !== -1)
                                    currentIndex = styleIndex
                            }
                            Layout.fillWidth: true
                        }
                    }
    
                    Label {
                        text: "Restart required"
                        color: "#e41e25"
                        opacity: styleBox.currentIndex !== styleBox.styleIndex ? 1.0 : 0.0
                        horizontalAlignment: Label.AlignHCenter
                        verticalAlignment: Label.AlignVCenter
                        Layout.fillWidth: true
                        Layout.fillHeight: true
                    }
                }
            }
    
            Dialog {
                id: aboutDialog
                modal: true
                focus: true
                title: "About"
                x: (window.width - width) / 2
                y: window.height / 6
                width: Math.min(window.width, window.height) / 3 * 2
                contentHeight: aboutColumn.height
    
                Column {
                    id: aboutColumn
                    spacing: 20
    
                    Label {
                        width: aboutDialog.availableWidth
                        text: "The Qt Quick Controls 2 module delivers the next generation user interface controls based on Qt Quick."
                        wrapMode: Label.Wrap
                        font.pixelSize: 12
                    }
    
                    Label {
                        width: aboutDialog.availableWidth
                        text: "In comparison to the desktop-oriented Qt Quick Controls 1, Qt Quick Controls 2 "
                              + "are an order of magnitude simpler, lighter and faster, and are primarily targeted "
                              + "towards embedded and mobile platforms."
                        wrapMode: Label.Wrap
                        font.pixelSize: 12
                    }
                }
            }
        }
    }
    
    ├── gallery.qml
    ├── icons
    │   └── gallery
    │       ├── 20x20
    │       │   ├── back.png
    │       │   ├── drawer.png
    │       │   └── menu.png
    │       ├── 20x20@2
    │       │   ├── back.png
    │       │   ├── drawer.png
    │       │   └── menu.png
    │       ├── 20x20@3
    │       │   ├── back.png
    │       │   ├── drawer.png
    │       │   └── menu.png
    │       ├── 20x20@4
    │       │   ├── back.png
    │       │   ├── drawer.png
    │       │   └── menu.png
    │       └── index.theme
    ├── images
    │   ├── arrow@2x.png
    │   ├── arrow@3x.png
    │   ├── arrow@4x.png
    │   ├── arrow.png
    │   ├── arrows@2x.png
    │   ├── arrows@3x.png
    │   ├── arrows@4x.png
    │   ├── arrows.png
    │   ├── qt-logo@2x.png
    │   ├── qt-logo@3x.png
    │   ├── qt-logo@4x.png
    │   └── qt-logo.png
    ├── main.py
    └── pages
        ├── BusyIndicatorPage.qml
        ├── ButtonPage.qml
        ├── CheckBoxPage.qml
        ├── ComboBoxPage.qml
        ├── DelayButtonPage.qml
        ├── DelegatePage.qml
        ├── DialogPage.qml
        ├── DialPage.qml
        ├── FramePage.qml
        ├── GroupBoxPage.qml
        ├── PageIndicatorPage.qml
        ├── ProgressBarPage.qml
        ├── RadioButtonPage.qml
        ├── RangeSliderPage.qml
        ├── ScrollablePage.qml
        ├── ScrollBarPage.qml
        ├── ScrollIndicatorPage.qml
        ├── SliderPage.qml
        ├── SpinBoxPage.qml
        ├── StackViewPage.qml
        ├── SwipeViewPage.qml
        ├── SwitchPage.qml
        ├── TabBarPage.qml
        ├── TextAreaPage.qml
        ├── TextFieldPage.qml
        ├── ToolTipPage.qml
        └── TumblerPage.qml
    

    完整的例子可以在here找到

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-10
      • 1970-01-01
      • 1970-01-01
      • 2014-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多