本页内容

文件系统资源管理器

一款利用自定义Qt Quick Controls 展示文件系统中文本文件的桌面QML应用。

文件系统资源管理器界面

“文件系统资源管理器”示例采用了一种现代布局,由三个主要组件构成:左侧基于图标的侧边栏、一个可调整大小的TreeView (通过QFileSystemModel 加载文件系统),以及用于显示所选文本文件的TextArea 。 经过定制的快速控件和无边框窗口,搭配专用的窗口装饰,确保在所有操作系统上保持统一的外观和操作体验。从命令行启动此应用程序时,您可以将初始目录作为参数提供。TreeView 将使用该初始目录来设置显示目录结构的起始点。

运行示例

您可以通过以下方式运行示例:

现代布局与结构

首先,该示例通过一个单例 QML 对象来控制全局颜色。此设计旨在确保对应用程序外观进行结构化的控制。

pragma Singleton

QtObject {
    readonly property color background: "#292828"
    readonly property color surface1: "#171819"
    readonly property color surface2: "#090A0C"
    readonly property color text: "#D4BE98"
    readonly property color textFile: "#E1D2B7"
    readonly property color disabledText: "#2C313A"
    readonly property color selection: "#4B4A4A"
    readonly property color active: "#292828"
    readonly property color inactive: "#383737"
    readonly property color folder: "#383737"
    readonly property color icon: "#383737"
    readonly property color iconIndicator: "#D5B35D"
    readonly property color color1: "#A7B464"
    readonly property color color2: "#D3869B"
}

该示例在ApplicationWindow 中使用FramelessWindowHint 标志来创建自定义装饰,而非依赖操作系统的窗口装饰。为了实现与窗口等效的交互,该示例重写了自定义MenuBar 的contentItem 属性,并显示信息文本以及拖动或关闭应用程序的交互选项。内联组件(Inline Components)简化了这一过程。

            component InteractionButton: Rectangle {
                id: interactionButton

                signal action()
                property alias hovered: hoverHandler.hovered

                Layout.fillHeight: true
                Layout.preferredWidth: height

                color: hovered ? Colors.background : "transparent"
                HoverHandler {
                    id: hoverHandler
                }
                TapHandler {
                    id: tapHandler
                    onTapped: interactionButton.action()
                }
            }

            InteractionButton {
                id: minimize

                onAction: root.dragWindow.showMinimized()
                Rectangle {
                    anchors.centerIn: parent
                    color: parent.hovered ? Colors.iconIndicator : Colors.icon
                    height: 2
                    width: parent.height - 14
                }
            }

            InteractionButton {
                id: maximize
    ...

左侧的侧边栏顶部包含可选中的导航按钮,底部包含单次点击按钮。通过使用ButtonGroup 和容器,可确保在任何给定时刻仅有一个条目处于活动状态。随后,可以利用当前位置的属性别名,结合StackLayout ,提供不同的视图。

通过这种技术,您可以添加另一个按钮以及StackLayout 内的对应元素,从而扩展功能。

                StackLayout {
                    anchors.fill: parent
                    currentIndex: sidebar.currentTabIndex

                    // Shows the help text.
                    Text {
                        text: qsTr("This example shows how to use and visualize the file system.\n\n"
                                 + "Customized Qt Quick Components have been used to achieve this look.\n\n"
                                 + "You can edit the files but they won't be changed on the file system.\n\n"
                                 + "Click on the folder icon to the left to get started.")
                        wrapMode: TextArea.Wrap
                        color: Colors.text
                    }

                    // Shows the files on the file system.
                    FileSystemView {
                        id: fileSystemView
                        color: Colors.surface1
                        onFileClicked: path => root.currentFilePath = path
                    }
                }

StackLayout 除了包含一些信息文本外,还包含FileSystemView。这个自定义组件用于显示文件和文件夹,并从C++ 模型中获取数据进行填充。随后,您可以选择文件并相应地读取它们。

QString FileSystemModel::readFile(const QString &filePath)
{
    // Don't issue errors for an empty path, as the initial binding
    // will result in an empty path, and that's OK.
    if (filePath.isEmpty())
        return {};

    QFile file(filePath);

    if (file.size() >= 2'000'000)
        return tr("File size is too big.\nYou can read files up to %1 MB.").arg(2);

    static const QMimeDatabase db;
    const QMimeType mime = db.mimeTypeForFile(QFileInfo(file));

    // Check if the mimetype is supported and return the content.
    const auto mimeTypesForFile = mime.parentMimeTypes();
    for (const auto &m : mimeTypesForFile) {
        if (m.contains("text", Qt::CaseInsensitive)
                || mime.comment().contains("text", Qt::CaseInsensitive)) {
            if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
                return tr("Error opening the File!");

            QTextStream stream(&file);
            return stream.readAll();
        }
    }
    return tr("Filetype not supported!");
}

在TreeView 中右键单击文件夹会打开一个Menu 弹出窗口,该窗口允许控制TreeView 的rootIndex 属性。

            MyMenu {
                id: contextMenu
                Action {
                    text: qsTr("Set as root index")
                    onTriggered: {
                        fileSystemTreeView.rootIndex = fileSystemTreeView.index(treeDelegate.row, 0)
                    }
                }
                Action {
                    text: qsTr("Reset root index")
                    onTriggered: fileSystemTreeView.rootIndex = undefined
                }
            }
        }

SplitView 可让您动态调整StackLayout 与编辑器之间的空间分配。编辑器包含TextArea ,用于显示已打开的文件并提供编辑文本文件所需的所有功能。此外,编辑器还提供行号功能,该功能可在Menu 中开启或关闭。

            Editor {
                id: editor
                showLineNumbers: root.showLineNumbers
                currentFilePath: root.currentFilePath
                SplitView.fillWidth: true
                SplitView.fillHeight: true
            }

自定义组件

为了更好地理解自定义过程,请先阅读《自定义控件》一文。本示例使用了可重用且经过自定义的组件。

例如,MyMenu 组件对Menu控件的background 属性、其委托的contentItem 属性以及background 属性进行了自定义。

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQuick
import QtQuick.Controls.Basic
import FileSystemModule

Menu {
    id: root

    delegate: MenuItem {
        id: menuItem
        contentItem: Item {
            Text {
                anchors.verticalCenter: parent.verticalCenter
                anchors.left: parent.left
                anchors.leftMargin: 5

                text: menuItem.text
                color: enabled ? Colors.text : Colors.disabledText
            }
            Rectangle {
                id: indicator

                anchors.verticalCenter: parent.verticalCenter
                anchors.right: parent.right
                width: 6
                height: parent.height

                visible: menuItem.highlighted
                color: Colors.color2
            }
        }
        background: Rectangle {
            implicitWidth: 210
            implicitHeight: 35
            color: menuItem.highlighted ? Colors.active : "transparent"
        }
    }
    background: Rectangle {
        implicitWidth: 210
        implicitHeight: 35
        color: Colors.surface2
    }
}

另一个示例是在FileSystemView 中对ScrollIndicator 进行自定义,其中使用了自定义动画。在此示例中,覆盖了contentItem 。

        ScrollIndicator.vertical: ScrollIndicator {
            active: true
            implicitWidth: 15

            contentItem: Rectangle {
                implicitWidth: 6
                implicitHeight: 6

                color: Colors.color1
                opacity: fileSystemTreeView.movingVertically ? 0.5 : 0.0

                Behavior on opacity {
                    OpacityAnimator {
                        duration: 500
                    }
                }
            }
        }

Python 版本

如果您对该示例的 Python 版本感兴趣,可以在此处找到。该版本展示了Qt for Python 的用法,并演示了如何利用它来创建相同的应用程序。

此外,还有一篇详细的教程,提供了逐步指导,说明如何为该示例添加新功能。如果您希望进一步探索并学习如何在“文件系统资源管理器”现有功能的基础上进行扩展,这篇教程将对您有所帮助。

源文件

示例项目 @ code.qt.io

另请参阅 所有 Qt 示例和Qt Quick Controls 示例。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.