Qt-快速上手-QFileDialog

QFileDialog

Qt 文件选择对话框,提供打开/保存文件、选择目录等能力。

头文件:#include <QFileDialog> | qmake:QT += widgets


一、类概览

cpp 复制代码
/**
 * @class QFileDialog
 * @brief 提供一个允许用户选择文件或目录的对话框。
 *
 * QFileDialog 继承自 QDialog,是 Qt 中最常用的文件交互组件。
 * 它既可以通过静态方法快速弹出原生对话框,也可以实例化后
 * 精细定制外观与行为。
 *
 * @par 继承关系
 * QObject → QWidget → QDialog → QFileDialog
 *
 * @par 典型用法
 * @code
 *   // 方式一:静态便捷方法(最常用,一行搞定)
 *   QString path = QFileDialog::getOpenFileName(this, "打开文件");
 *
 *   // 方式二:实例化并精细配置
 *   QFileDialog dlg(this, "选择图片", QDir::homePath(),
 *                   "图片 (*.png *.jpg *.bmp)");
 *   dlg.setFileMode(QFileDialog::ExistingFiles);
 *   if (dlg.exec() == QDialog::Accepted) {
 *       QStringList files = dlg.selectedFiles();
 *   }
 * @endcode
 */

二、核心枚举

2.1 FileMode --- 文件选择模式

cpp 复制代码
/**
 * @enum QFileDialog::FileMode
 * @brief 控制用户可以选择什么类型的文件系统条目。
 *
 * @var QFileDialog::AnyFile
 *      文件名可以是任意内容,即使文件不存在也能返回。
 *      适用于"另存为"场景。
 * @var QFileDialog::ExistingFile
 *      只能选择单个已存在的文件。
 * @var QFileDialog::Directory
 *      只能选择目录。此时文件名也显示目录名。
 * @var QFileDialog::ExistingFiles
 *      可以选择零个或多个已存在的文件(多选模式)。
 */

2.2 AcceptMode --- 对话框用途

cpp 复制代码
/**
 * @enum QFileDialog::AcceptMode
 * @brief 区分对话框是用于"打开"还是"保存"。
 *
 * @var QFileDialog::AcceptOpen  打开模式(默认)
 * @var QFileDialog::AcceptSave  保存模式,会触发覆盖确认
 */

2.3 ViewMode --- 视图样式

cpp 复制代码
/**
 * @enum QFileDialog::ViewMode
 * @brief 文件列表的展示方式。
 *
 * @var QFileDialog::Detail  详细列表(含大小、日期等列,默认)
 * @var QFileDialog::List    仅图标+名称的紧凑列表
 */

2.4 Option --- 行为选项(可按位或组合)

cpp 复制代码
/**
 * @enum QFileDialog::Option
 * @brief 精细控制对话框行为的标志位,使用 setOptions() 设置。
 *
 * @var QFileDialog::ShowDirsOnly
 *      只显示目录,隐藏文件(配合 Directory 模式使用)。
 * @var QFileDialog::DontResolveSymlinks
 *      不解析符号链接,返回链接本身路径。
 * @var QFileDialog::DontConfirmOverwrite
 *      保存时若文件已存在,不弹确认框直接返回。
 * @var QFileDialog::DontUseNativeDialog
 *      强制使用 Qt 自绘对话框,而非系统原生对话框。
 *      (需要自定义信号/侧边栏时必须开启此选项)
 * @var QFileDialog::ReadOnly
 *      对话框只读,禁止在其中创建目录或重命名。
 * @var QFileDialog::HideNameFilterDetails
 *      过滤器下拉框中只显示描述,隐藏通配符细节。
 * @var QFileDialog::DontUseCustomDirectoryIcons
 *      不使用目录的自定义图标,提升性能。
 */

2.5 DialogLabel --- 可自定义的标签

cpp 复制代码
/**
 * @enum QFileDialog::DialogLabel
 * @brief setLabelText() 可以修改的界面文字元素。
 *
 * @var QFileDialog::LookIn   "查找范围"标签
 * @var QFileDialog::FileName "文件名"标签
 * @var QFileDialog::FileType "文件类型"标签
 * @var QFileDialog::Accept   确认按钮文字(默认"打开"/"保存")
 * @var QFileDialog::Reject   取消按钮文字
 */

三、静态便捷方法(最常用)

这些方法内部会创建一个模态对话框并阻塞等待用户操作,

返回选中的路径(取消时返回空字符串/空列表)。

3.1 getOpenFileName --- 选择单个文件打开

cpp 复制代码
/**
 * @brief 弹出"打开文件"对话框,返回用户选择的单个文件绝对路径。
 *
 * @param parent        父窗口,对话框居中于该窗口。
 * @param caption       对话框标题栏文字。
 * @param dir           初始目录(为空则使用当前工作目录)。
 * @param filter        文件过滤器,如 "文本文件 (*.txt);;所有文件 (*)"。
 * @param selectedFilter 输出参数,返回用户实际选中的过滤器。
 * @param options       行为选项组合。
 * @return QString      选中文件的绝对路径;用户取消则返回空 QString。
 *
 * @par 示例
 * @code
 *   QString file = QFileDialog::getOpenFileName(
 *       this, "打开配置", QDir::homePath(),
 *       "JSON (*.json);;所有文件 (*.*)");
 *   if (!file.isEmpty()) {
 *       // 处理 file
 *   }
 * @endcode
 */
QString QFileDialog::getOpenFileName(
    QWidget *parent = nullptr,
    const QString &caption = QString(),
    const QString &dir = QString(),
    const QString &filter = QString(),
    QString *selectedFilter = nullptr,
    Options options = Options());

3.2 getOpenFileNames --- 选择多个文件

cpp 复制代码
/**
 * @brief 弹出"打开文件"对话框,允许多选,返回文件路径列表。
 *
 * @return QStringList 选中文件的绝对路径列表;取消则为空列表。
 *
 * @par 示例
 * @code
 *   QStringList files = QFileDialog::getOpenFileNames(
 *       this, "选择图片", "", "图片 (*.png *.jpg *.jpeg)");
 *   for (const QString &f : files) {
 *       qDebug() << "选中:" << f;
 *   }
 * @endcode
 */
QStringList QFileDialog::getOpenFileNames(
    QWidget *parent = nullptr,
    const QString &caption = QString(),
    const QString &dir = QString(),
    const QString &filter = QString(),
    QString *selectedFilter = nullptr,
    Options options = Options());

3.3 getSaveFileName --- 选择保存路径

cpp 复制代码
/**
 * @brief 弹出"另存为"对话框,返回用户指定的保存路径。
 *
 * 若目标文件已存在,默认会弹出覆盖确认(可用 DontConfirmOverwrite 关闭)。
 *
 * @par 示例
 * @code
 *   QString savePath = QFileDialog::getSaveFileName(
 *       this, "保存报告", QDir::homePath() + "/report.txt",
 *       "文本文件 (*.txt)");
 * @endcode
 */
QString QFileDialog::getSaveFileName(
    QWidget *parent = nullptr,
    const QString &caption = QString(),
    const QString &dir = QString(),
    const QString &filter = QString(),
    QString *selectedFilter = nullptr,
    Options options = Options());

3.4 getExistingDirectory --- 选择已有目录

cpp 复制代码
/**
 * @brief 弹出目录选择对话框,返回选中的目录绝对路径。
 *
 * @param options 默认包含 ShowDirsOnly,即只显示目录。
 *
 * @par 示例
 * @code
 *   QString dir = QFileDialog::getExistingDirectory(
 *       this, "选择导出目录", QDir::homePath());
 * @endcode
 */
QString QFileDialog::getExistingDirectory(
    QWidget *parent = nullptr,
    const QString &caption = QString(),
    const QString &dir = QString(),
    Options options = ShowDirsOnly);

Qt 5.12+ 还提供了对应的 URL 版本:

getOpenFileUrl() / getOpenFileUrls() / getSaveFileUrl() /

getExistingDirectoryUrl(),用于支持远程文件系统。


四、实例化常用成员方法

当静态方法不够用(需要多选 + 自定义信号 + 侧边栏等)时,

先创建 QFileDialog 对象,配置后调用 exec()。

4.1 选择模式与接受模式

cpp 复制代码
void setFileMode(FileMode mode);   ///< 设置文件选择模式
FileMode fileMode() const;         ///< 获取当前文件模式

void setAcceptMode(AcceptMode mode); ///< 设置打开/保存模式
AcceptMode acceptMode() const;       ///< 获取当前接受模式

4.2 文件过滤器

cpp 复制代码
/**
 * @brief 设置单个文件过滤器。
 * @param filter 格式为 "描述 (通配符)",多个用 ;; 分隔。
 *
 * 例:"C++源文件 (*.cpp *.h);;Python (*.py);;所有文件 (*)"
 */
void setNameFilter(const QString &filter);

void setNameFilters(const QStringList &filters); ///< 设置多个过滤器
QStringList nameFilters() const;                 ///< 获取所有过滤器

void selectNameFilter(const QString &filter);    ///< 默认选中某个过滤器
QString selectedNameFilter() const;              ///< 获取当前选中的过滤器

4.3 目录与默认后缀

cpp 复制代码
void setDirectory(const QString &directory); ///< 设置初始目录
void setDirectory(const QDir &directory);    ///< 重载,接受 QDir
QDir directory() const;                      ///< 获取当前目录

/**
 * @brief 设置默认后缀。
 *
 * 当用户输入的文件名没有后缀时,自动追加此后缀。
 * 保存对话框中非常实用。
 */
void setDefaultSuffix(const QString &suffix);
QString defaultSuffix() const;

4.4 获取选中结果

cpp 复制代码
/**
 * @brief 返回用户选中的文件/目录的本地绝对路径列表。
 *
 * 应在 exec() 返回 Accepted 之后调用。
 * 单选模式下列表长度为 1。
 */
QStringList selectedFiles() const;

QList<QUrl> selectedUrls() const; ///< URL 版本,支持远程路径

4.5 视图与外观

cpp 复制代码
void setViewMode(ViewMode mode);  ///< Detail 或 List
ViewMode viewMode() const;

/**
 * @brief 修改对话框中指定标签的显示文字。
 *
 * 常用于把"打开"按钮改成"导入"、"选择"等。
 */
void setLabelText(DialogLabel label, const QString &text);
QString labelText(DialogLabel label) const;

4.6 选项与侧边栏

cpp 复制代码
void setOptions(Options options);       ///< 批量设置选项
Options options() const;                ///< 获取当前选项
void setOption(Option option, bool on = true); ///< 单独开关一个选项
bool testOption(Option option) const;   ///< 检测某个选项是否开启

/**
 * @brief 设置左侧"常用位置"侧边栏。
 * @note 必须同时设置 DontUseNativeDialog 才会生效。
 */
void setSidebarUrls(const QList<QUrl> &urls);
QList<QUrl> sidebarUrls() const;

4.7 预选中文件

cpp 复制代码
/**
 * @brief 在对话框打开时预先选中/填入指定文件名。
 *
 * 常用于"另存为"时给出默认文件名。
 */
void selectFile(const QString &filename);

五、常用信号

使用信号时必须设置 DontUseNativeDialog,

因为原生对话框不会发出这些 Qt 信号。

cpp 复制代码
void currentChanged(const QString &path);     ///< 当前高亮条目变化
void currentUrlChanged(const QUrl &url);      ///< URL 版本
void fileSelected(const QString &file);       ///< 确认选择单个文件
void filesSelected(const QStringList &files); ///< 确认选择多个文件
void urlSelected(const QUrl &url);            ///< URL 版本
void urlsSelected(const QList<QUrl> &urls);   ///< URL 版本

六、练习

所有练习均使用 Qt Widgets,QT += widgets。

编译命令示例:qmake && make 或在 Qt Creator 中直接运行。


练习 1:基础版 --- 文本编辑器的打开与保存

目标 :掌握 getOpenFileName 和 getSaveFileName 的基本用法。

文件:mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QTextEdit>
#include <QFileDialog>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    setWindowTitle("练习1 - 简易文本编辑器");
    resize(600, 400);

    auto *edit = new QTextEdit(this);
    setCentralWidget(edit);

    auto *fileMenu = menuBar()->addMenu("文件(&F)");

    auto *openAct = fileMenu->addAction("打开(&O)");
    openAct->setShortcut(QKeySequence::Open);
    connect(openAct, &QAction::triggered, this, [this, edit](){
        QString path = QFileDialog::getOpenFileName(
            this, "打开文本文件", QDir::homePath(),
            "文本文件 (*.txt *.md);;所有文件 (*.*)");
        if (path.isEmpty()) return;

        QFile file(path);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QMessageBox::warning(this, "错误", "无法打开文件");
            return ;
        }
        QTextStream stream(&file);
        edit->setText(stream.readAll());
        setWindowTitle("练习1 - " + path);
        file.close();
    });

    auto *saveAct = fileMenu->addAction("保存(&S)");
    saveAct->setShortcut(QKeySequence::Save);
    connect(saveAct, &QAction::triggered, this, [this, edit](){
        QString path = QFileDialog::getSaveFileName(
            this, "保存文本文件", QDir::homePath() + "/untitled.txt",
            "文本文件 (*.txt);;Markdown (*.md)");
        if (path.isEmpty()) return;

        QFile file(path);
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
            QMessageBox::warning(this, "错误", "保存文件失败");
            return ;
        }

        QTextStream stream(&file);
        stream << edit->toPlainText();
        setWindowTitle("练习1 - " + path);
        file.close();
    });

    fileMenu->addSeparator();
    auto *quitAct = fileMenu->addAction("退出(&Q)");
    quitAct->setShortcut(QKeySequence::Quit);
    connect(quitAct, &QAction::triggered, this, &QWidget::close);
}

MainWindow::~MainWindow()
{
    delete ui;
}

要点:

  • 静态方法返回空字符串表示用户取消,必须判断。
  • getSaveFileName 的 dir 参数可以直接包含默认文件名。
  • 过滤器格式:"描述1 (*.ext1);;描述2 (*.ext2)",用 ;; 分隔。

练习 2:多选文件 + 目录选择

目标 :掌握 getOpenFileNames 多选、getExistingDirectory 选目录,

以及 selectedFiles() 的使用。

cpp 复制代码
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QTextEdit>
#include <QFileDialog>
#include <QMessageBox>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QListWidget>
#include <QString>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    setWindowTitle("练习2 - 多选与目录选择");
    resize(500, 400);

    auto *layout = new QVBoxLayout(ui->centralwidget);

    // 界面组件
    auto *btnFiles = new QPushButton("选择多个图片文件", this);
    auto *btnDir   = new QPushButton("选择一个目录", this);
    auto *label    = new QLabel("尚未选择", this);
    auto *list     = new QListWidget(this);

    // 添加进layout
    layout->addWidget(btnFiles);
    layout->addWidget(btnDir);
    layout->addWidget(label);
    layout->addWidget(list);

    // 多选文件
    connect(btnFiles, &QPushButton::clicked, this, [this, list, label](){
        QStringList files = QFileDialog::getOpenFileNames(
            this, "选择图片", QDir::homePath(),
            "图片 (*.png *.jpg *.jpeg *.bmp *.gif);;所有文件 (*)");
        list->clear();
        list->addItems(files);
        label->setText(QString("共选中 %1 个文件").arg(files.size()));
    });

    // 选择目录
    connect(btnDir, &QPushButton::clicked, this, [this, list, label](){
        QString dir = QFileDialog::getExistingDirectory(
            this, "选择目录", QDir::homePath(),
            QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
        if (dir.isEmpty()) return ;

        list->clear();
        QDir d(dir);
        list->addItems(d.entryList(QDir::Files | QDir::NoDotAndDotDot));
        label->setText(QString("目录: %1 (含 %2 个文件)").arg(dir).arg(list->count()));
    });

}

MainWindow::~MainWindow()
{
    delete ui;
}

要点:

  • getOpenFileNames 返回 QStringList,空列表表示取消。
  • getExistingDirectory 默认带 ShowDirsOnly,可追加其他 Option。
  • QDir::entryList() 可列出目录内容,与文件对话框配合做预览。

练习 3:实例化精细定制 --- 带默认后缀、自定义按钮文字、侧边栏

目标:掌握实例化 QFileDialog 后的高级配置。

cpp 复制代码
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QTextEdit>
#include <QFileDialog>
#include <QMessageBox>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QListWidget>
#include <QString>
#include <QPlainTextEdit>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    setWindowTitle("练习3 - 精细定制保存对话框");
    resize(500, 300);

    auto *layout = new QVBoxLayout(ui->centralwidget);
    auto *btn    = new QPushButton("导出为 JSON", this);
    auto *log    = new QPlainTextEdit(this);
    log->setReadOnly(true);
    layout->addWidget(btn);
    layout->addWidget(log);

    connect(btn, &QPushButton::clicked, this, [this, log](){
        QFileDialog dlg(this, "导出配置", QDir::homePath());
        dlg.setFileMode(QFileDialog::AnyFile);
        dlg.setAcceptMode(QFileDialog::AcceptSave);

        // 默认后缀(用户只输文件名时自动补 .json)
        dlg.setDefaultSuffix("json");

        // 过滤器
        dlg.setNameFilters({
            "JSON 配置 (*.json)",
            "所有文件 (*)"
        });
        dlg.selectNameFilter("JSON 配置 (*.json)");

        // 自定义按钮文字
        dlg.setLabelText(QFileDialog::Accept, "导出");
        dlg.setLabelText(QFileDialog::Reject, "取消");
        dlg.setLabelText(QFileDialog::FileName, "配置名称");

        // 预填默认文件名
        dlg.selectFile("my_config");

        // 自定义侧边栏(必须 DontUseNativeDialog)
        dlg.setOption(QFileDialog::DontUseNativeDialog, true);
        dlg.setSidebarUrls({
                            QUrl::fromLocalFile(QDir::homePath()),
                            QUrl::fromLocalFile(QDir::homePath() + "/Desktop"),
                            QUrl::fromLocalFile("/tmp"),
        });

        if (dlg.exec() == QDialog::Accepted) {
            QStringList files = dlg.selectedFiles();
            if (!files.isEmpty()) {
                log->appendPlainText("导出路径: " + files.first());
                log->appendPlainText("使用过滤器: " + dlg.selectedNameFilter());
            }
        } else {
            log->appendPlainText("用户取消了导出");
        }
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

要点:

  • setDefaultSuffix("json") 让用户输入 my_config 自动变成 my_config.json。
  • setLabelText(Accept, "导出") 把确认按钮从"保存"改成"导出"。
  • setSidebarUrls() 必须配合 DontUseNativeDialog 才生效。
  • selectFile() 用于预填文件名。

练习 4:实时预览 --- 利用 currentChanged 信号

目标:掌握 QFileDialog 的信号机制,实现选中文件时实时显示信息。

mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLabel>
#include <QDir>
#include <QFileDialog>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow() override;

private:
    Ui::MainWindow *ui;
    QLabel *infoLable_ = nullptr;

private slots:
    void openDialog() {
        // 注意:使用信号必须设置 DontUseNativeDialog
        QFileDialog dlg(this, "选择文件", QDir::homePath());
        dlg.setOption(QFileDialog::DontUseNativeDialog, true);
        dlg.setFileMode(QFileDialog::ExistingFile);
        dlg.setNameFilters({
                            "所有文件 (*)",
                            "文本 (*.txt *.md)",
                            "图片 (*.png *.jpg)"
        });

        // 实时预览:当前高亮条目变化时更新信息
        connect(&dlg, &QFileDialog::currentChanged, this, &MainWindow::onCurrentChanged);

        if (dlg.exec() == QDialog::Accepted) {
            infoLable_->setText("最终选择: " + dlg.selectedFiles().first());
        }
    }


    void onCurrentChanged(const QString &path) {
        QFileInfo fi(path);
        if (!fi.exists()) {
            infoLable_->setText("路径不存在: " + path);
            return ;
        }
        QString text;
        text += QString("名称: %1\n").arg(fi.fileName());
        text += QString("类型: %1\n").arg(fi.isDir() ? "目录" : "文件");
        if (fi.isFile()) {
            text += QString("大小: %1 KB\n").arg(fi.size()/1024.0, 0, 'f', 2);
        }
        text += QString("修改时间: %1\n").arg(fi.lastModified().toString("yyyy-MM-dd hh:mm:ss"));
        text += QString("绝对路径: %1").arg(fi.absoluteFilePath());
        infoLable_->setText(text);
    }
};
#endif // MAINWINDOW_H

mainwindow.cpp

c++ 复制代码
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QVBoxLayout>
#include <QPushButton>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    setWindowTitle("练习4 - 实时文件预览");
    resize(450, 200);

    auto *layout = new QVBoxLayout(ui->centralwidget);
    auto *btn = new QPushButton("打开文件对话框(带实时预览)", this);
    infoLable_ = new QLabel("请选择文件...", this);
    infoLable_->setWordWrap(true);
    infoLable_->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    infoLable_->setFrameShape(QFrame::StyledPanel);
    infoLable_->setMinimumHeight(120);

    layout->addWidget(btn);
    layout->addWidget(infoLable_);

    connect(btn, &QPushButton::clicked, this, &MainWindow::openDialog);
}

MainWindow::~MainWindow()
{
    delete ui;
}

要点:

  • 使用 currentChanged 信号必须设置 DontUseNativeDialog。
  • QFileInfo 可以获取文件大小、修改时间、是否目录等元信息。
  • 信号在用户高亮(单击/键盘移动)时就触发,不是确认后才触发。
相关推荐
小道士写程序15 分钟前
Windows Rust 环境安装指导
开发语言·windows·rust
传奇开心果编程17 分钟前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
Tisfy28 分钟前
两台旧电脑修复 —— 绕过WinXP密码登录、备份和恢复Win7数据、安装Win10
windows·数据恢复·系统重装
传奇开心果编程36 分钟前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer
supabc1231 小时前
Celium:连接 Windows、Mac、Linux 与 Android,让远程访问和设备管理更简单
android·linux·windows·macos·远程访问·网络管理·celium
2401_872418781 小时前
Windows服务器:错误 403 - 禁止访问:本地 FTP 上传文件到网站服务器后提示无访问权限
运维·服务器·windows
Quz12 小时前
QML PathView:吸附对齐与环形轮播
qt
时间的拾荒人13 小时前
Qt 多线程详解:从 QThread 到实战
开发语言·qt·面试
YCOSA202513 小时前
Windows11_InsiderPreview_EnterpriseVL_x64_zh-cn_29680_1000.iso 官方直链
windows
小杍随笔14 小时前
Trae CN迁移后插件失效修复方案
microsoft