赞
踩
QML 中虽然也提供了 FileDialog 组件,但是使用体验远不如 QtWidgets 中的 QFileDialog,故做了简单的封装,使得可以在 QML 中使用 QFileDialog 来选择文件或者文件夹。
因为[Qt文档]提示不应直接在 QML 逻辑中启用自己的事件循环,所以我是通过信号槽来弹出和传递返回结果,操作流程和 QML 的 FileDialog 类似。
Demo 链接:
https://github.com/gongjianbo/MyTestCode/tree/master/Qml/FileDialogWrap
主要代码:
- #pragma once
- #include <QObject>
- #include <QUrl>
- #include <QSettings>
- #include <QFileDialog>
-
- /**
- * @brief 包装QFileDialog在QML中使用
- * @author 龚建波
- * @date 2022-12-31
- * @details
- * 参考:https://doc.qt.io/qt-5/qtquick-performance.html
- * 文档指出我们不应该在qml逻辑中执行自己的事件循环,所以通过信号槽异步调用对话框exec
- * 而操作结果也只能通过信号传递,不能像cpp代码那样exec后面直接获取结果
- */
- class FileDialogWrap : public QObject
- {
- Q_OBJECT
- Q_PROPERTY(int mode READ getMode WRITE setMode NOTIFY modeChanged)
- Q_PROPERTY(QString title READ getTitle WRITE setTitle NOTIFY titleChanged)
- Q_PROPERTY(QStringList nameFilters READ getNameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
- Q_PROPERTY(QUrl currentUrl READ getCurrentUrl NOTIFY currentUrlChanged)
- Q_PROPERTY(QList<QUrl> currentUrls READ getCurrentUrls NOTIFY currentUrlsChanged)
- public:
- enum WorkMode {
- SelectFile, //单选文件
- SelectFiles, //多选文件
- SelectDir, //选择目录
- SaveFile //保存文件
- };
- Q_ENUM(WorkMode)
- public:
- explicit FileDialogWrap(QObject *parent = nullptr);
- ~FileDialogWrap();
-
- //工作模式,枚举WorkMode
- int getMode() const;
- void setMode(int mode);
-
- //标题设置
- QString getTitle() const;
- void setTitle(const QString &title);
-
- //后缀过滤
- QStringList getNameFilters() const;
- void setNameFilters(const QStringList &filters);
-
- //单选结果
- QUrl getCurrentUrl() const;
- void setCurrentUrl(const QUrl &url);
-
- //多选结果
- QList<QUrl> getCurrentUrls() const;
- void setCurrentUrls(const QList<QUrl> &urls);
-
- Q_INVOKABLE void open();
- Q_INVOKABLE void close();
- //打开前选中某个路径,带文件名则作为选中的文件名
- Q_INVOKABLE void selectUrl(const QUrl &url);
-
- //桌面路径
- Q_INVOKABLE static QString desktopPath();
- Q_INVOKABLE static QUrl desktopUrl();
- //设置ini配置路径,qml初始化之前cpp中设置
- static void initSetting(const QString &filepath, const QSettings::Format &format = QSettings::IniFormat);
-
- private:
- QString getDefaultPath();
- void setDefaultPath(const QString &dirpath);
-
- private slots:
- void openDialog();
-
- signals:
- void __openRequest();
- void __closeRequest();
- void accepted();
- void rejected();
-
- void modeChanged();
- void titleChanged();
- void nameFiltersChanged();
- void currentUrlChanged();
- void currentUrlsChanged();
-
- private:
- //ini配置文件路径
- inline static QString iniPath;
- inline static QSettings::Format iniFormat{QSettings::IniFormat};
- //对话框
- QFileDialog *dialog;
- //模式,选择文件还是目录等
- int workMode{FileDialogWrap::SelectFile};
- //文件名过滤
- QStringList nameFilters{"All (*.*)"};
- //单选结果,当前选中路径
- QUrl currentUrl;
- //多选结果
- QList<QUrl> currentUrls;
- //selectUrl可设置,下次弹出时生效
- QUrl nextUrl;
- };

- #include "FileDialogWrap.h"
- #include <QCoreApplication>
- #include <QStandardPaths>
- #include <QFileInfo>
- #include <QDebug>
-
- FileDialogWrap::FileDialogWrap(QObject *parent)
- : QObject{parent}
- , dialog{new QFileDialog}
- {
- setTitle(QCoreApplication::applicationName());
- connect(this, &FileDialogWrap::__openRequest, this, &FileDialogWrap::openDialog, Qt::QueuedConnection);
- connect(this, &FileDialogWrap::__closeRequest, this, [=](){
- dialog->reject();
- }, Qt::QueuedConnection);
- }
-
- FileDialogWrap::~FileDialogWrap()
- {
- dialog->deleteLater();
- }
-
- int FileDialogWrap::getMode() const
- {
- return workMode;
- }
-
- void FileDialogWrap::setMode(int mode)
- {
- if (mode != workMode) {
- workMode = mode;
- emit modeChanged();
- }
- }
-
- QString FileDialogWrap::getTitle() const
- {
- return dialog->windowTitle();
- }
-
- void FileDialogWrap::setTitle(const QString &title)
- {
- if (title != getTitle()) {
- dialog->setWindowTitle(title);
- emit titleChanged();
- }
- }
-
- QStringList FileDialogWrap::getNameFilters() const
- {
- return nameFilters;
- }
-
- void FileDialogWrap::setNameFilters(const QStringList &filters)
- {
- if (filters != nameFilters) {
- nameFilters = filters;
- emit nameFiltersChanged();
- }
- }
-
- QUrl FileDialogWrap::getCurrentUrl() const
- {
- return currentUrl;
- }
-
- void FileDialogWrap::setCurrentUrl(const QUrl &url)
- {
- if (url != currentUrl) {
- currentUrl = url;
- emit currentUrlChanged();
- }
- }
-
- QList<QUrl> FileDialogWrap::getCurrentUrls() const
- {
- return currentUrls;
- }
-
- void FileDialogWrap::setCurrentUrls(const QList<QUrl> &urls)
- {
- if (urls != currentUrls) {
- currentUrls = urls;
- emit currentUrlsChanged();
- }
- }
-
- void FileDialogWrap::open()
- {
- if (dialog->isVisible())
- return;
- emit __openRequest();
- }
-
- void FileDialogWrap::close()
- {
- if (!dialog->isVisible())
- return;
- emit __closeRequest();
- }
-
- void FileDialogWrap::selectUrl(const QUrl &url)
- {
- nextUrl = url;
- }
-
- QString FileDialogWrap::desktopPath()
- {
- return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
- }
-
- QUrl FileDialogWrap::desktopUrl()
- {
- return QUrl::fromLocalFile(desktopPath());
- }
-
- void FileDialogWrap::initSetting(const QString &filepath, const QSettings::Format &format)
- {
- iniPath = filepath;
- iniFormat = format;
- }
-
- QString FileDialogWrap::getDefaultPath()
- {
- //QFileDialog默认实现在构造时恢复,析构时保存
- //QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
- //settings.beginGroup(QLatin1String("FileDialog"));
- //记录上一次选择的路径
- QSettings setting(iniPath, QSettings::IniFormat);
- QString dirpath = setting.value("LastPath").toString();
- if (dirpath.isEmpty()) {
- //默认桌面路径
- dirpath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
- }
- qDebug()<<"get default"<<dirpath;
- return dirpath;
- }
-
- void FileDialogWrap::setDefaultPath(const QString &dirpath)
- {
- QSettings setting(iniPath, QSettings::IniFormat);
- setting.setValue("LastPath", dirpath);
- qDebug()<<"set default"<<dirpath;
- }
-
- void FileDialogWrap::openDialog()
- {
- switch (workMode) {
- case SelectFile:
- {
- dialog->setFileMode(QFileDialog::ExistingFile);
- }
- break;
- case SelectFiles:
- {
- dialog->setFileMode(QFileDialog::ExistingFiles);
- }
- break;
- case SelectDir:
- {
- dialog->setOption(QFileDialog::ShowDirsOnly);
- //参考源码中的写法
- QT_WARNING_PUSH
- QT_WARNING_DISABLE_DEPRECATED
- dialog->setFileMode(QFileDialog::DirectoryOnly);
- QT_WARNING_POP
-
- }
- break;
- case SaveFile:
- {
- dialog->setFileMode(QFileDialog::AnyFile);
- dialog->setAcceptMode(QFileDialog::AcceptSave);
- }
- break;
- default: break;
- }
-
- dialog->setNameFilters(nameFilters);
- //设置了url就用设置的,否则用上次保存的目录
- //selectUrl设置nextUrl
- if (nextUrl.isValid()) {
- QFileInfo info(nextUrl.toLocalFile());
- if (info.isDir()) {
- dialog->setDirectory(info.absoluteFilePath());
- } else {
- dialog->setDirectory(info.absolutePath());
- dialog->selectFile(info.fileName());
- }
- nextUrl.clear();
- } else {
- dialog->setDirectory(getDefaultPath());
- }
-
- const int ret = dialog->exec();
- if (ret == QDialog::Rejected) {
- emit rejected();
- return;
- }
- auto &&urls = dialog->selectedUrls();
- if (urls.isEmpty()) {
- setCurrentUrl(QUrl());
- setDefaultPath(desktopPath());
- } else {
- QUrl first_url = urls.first();
- setCurrentUrl(first_url);
- //保存目录到配置文件
- QFileInfo info(first_url.toLocalFile());
- if (info.isDir()) {
- setDefaultPath(info.absoluteFilePath());
- } else {
- setDefaultPath(info.absolutePath());
- }
- }
- setCurrentUrls(urls);
- emit accepted();
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。