QML/WebGL - 如何阻止 DefaultFileDialog 在 Windows 上返回不可用的路径?
QML/WebGL - How to stop DefaultFileDialog from returning unusable paths on Windows?
问题描述
在 Windows 上为包含 FileDialog 的桌面构建 QML 应用程序时,会显示默认的 Windows 文件对话框。这一个按预期工作,返回到所选文件或文件夹的路径,该文件或文件夹在路径前具有前缀 (file:///)。只有当 WebGL 发挥作用时,问题才会出现。
为 WebGL 平台构建并通过浏览器连接会将文件对话框默认为 DefaultFileDialog,它在选择(子)目录时表现截然不同。假设我们从对话框中的这条路径开始(剪裁以关注 ROI):
选择子目录后(单击):
再次单击进入该目录并将路径替换为:
如果在子目录中进行另一个选择,我们最终丢失了盘符:
路径是我希望在 Linux 上工作的东西,这可能是我找不到有关此行为的任何其他信息的原因。进入子目录的其他步骤不会进一步破坏路径:
我目前的搜索
我有 google 它,搜索 Stack Overflow 并尝试通过正则表达式解决这个问题,但到目前为止,运气不好。
问题
有没有办法阻止 DefaultFileDialog 实例优化 我的路径选择在 Windows 上变得无用?理想情况下,我希望在不是 运行 WebGL 应用程序时保留系统文件对话框,但这对我来说不是硬性要求。
编辑:@mike510a 揭示了我遗漏的其他要求:
- 驱动器号可以是任何有效的,因为在对话框中,驱动器可以更改。因此,硬编码驱动器号以替换对话框中丢失的驱动器号是行不通的。
- 由于在接受文件或文件夹之前采取的步骤数量未知,因此不能假设驱动器号已经从返回的 QString 中删除。
示例代码
修改由 QtCreator 创建的项目(在我的例子中是 4.13.2,空 QtQuick 项目)。
# autogenerated
QT += quick
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
app.setOrganizationName("Something"); // modified to avoid QML warning
app.setOrganizationDomain("Something.else"); // modified to avoid QML warning
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Dialogs 1.2
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
Window {
width: 640
height: 480
minimumHeight: 320
minimumWidth: 480
visible: true
title: qsTr("Hello World")
color: "grey"
RowLayout {
anchors.fill: parent
Label {
text: "File path:"
Layout.column: 0
}
TextEdit {
id: pathTextEdit
readOnly: true
clip: true
Layout.column: 1
Layout.fillWidth: true
Rectangle {
z: -1
anchors.fill: parent
radius: 3
color: "white"
}
}
Button {
text: "Select file"
Layout.column: 2
onClicked: {
pathSelection.visible = true
}
}
}
FileDialog {
id: pathSelection
visible: false
width: 300
height: 300
selectFolder: true
onAccepted: {
pathTextEdit.text = folder
}
}
}
我很确定因为 WebGL 平台使用与 Windows 文件系统目录结构不同的架构,所以您会得到奇怪的文件夹。您可以使用架构 file://
将 URLS 转换为指向本地计算机上文件的指针,您可以将 folder
属性 与 file:///C:/Users/whatever 一起使用或执行以下操作...
要获取操作系统的底层文件系统位置,您可以使用 folder
属性 和值 shortcuts.home
,如下所述:https://doc.qt.io/qt-5/qml-qtquick-dialogs-filedialog.html
FileDialog {
id: pathSelection
visible: false
width: 300
height: 300
selectFolder: true
// point to an operating system location and you should get
// a usable URL
folder: shortcuts.home
onAccepted: {
pathTextEdit.text = folder
}
}
在 Qt 支持的帮助下,可以找到解决方案。导致该行为的问题在 DefaultFileDialog.qml 中找到,更具体地说,在函数 dirDown
中。可以通过替换
来修复
root.folder = "file://" + path
和
root.folder = root.pathToUrl(path)
然后重建 Qt。整个补丁是这样写的:
--- a/src/dialogs/DefaultFileDialog.qml
+++ b/src/dialogs/DefaultFileDialog.qml
@@ -115,7 +115,7 @@ AbstractFileDialog {
function dirDown(path) {
view.selection.clear()
- root.folder = "file://" + path
+ root.folder = root.pathToUrl(path)
}
function dirUp() {
view.selection.clear()
此补丁已提交以包含在 Qt 5.15.3 中。
问题描述
在 Windows 上为包含 FileDialog 的桌面构建 QML 应用程序时,会显示默认的 Windows 文件对话框。这一个按预期工作,返回到所选文件或文件夹的路径,该文件或文件夹在路径前具有前缀 (file:///)。只有当 WebGL 发挥作用时,问题才会出现。
为 WebGL 平台构建并通过浏览器连接会将文件对话框默认为 DefaultFileDialog,它在选择(子)目录时表现截然不同。假设我们从对话框中的这条路径开始(剪裁以关注 ROI):
选择子目录后(单击):
再次单击进入该目录并将路径替换为:
如果在子目录中进行另一个选择,我们最终丢失了盘符:
路径是我希望在 Linux 上工作的东西,这可能是我找不到有关此行为的任何其他信息的原因。进入子目录的其他步骤不会进一步破坏路径:
我目前的搜索
我有 google 它,搜索 Stack Overflow 并尝试通过正则表达式解决这个问题,但到目前为止,运气不好。
问题
有没有办法阻止 DefaultFileDialog 实例优化 我的路径选择在 Windows 上变得无用?理想情况下,我希望在不是 运行 WebGL 应用程序时保留系统文件对话框,但这对我来说不是硬性要求。
编辑:@mike510a 揭示了我遗漏的其他要求:
- 驱动器号可以是任何有效的,因为在对话框中,驱动器可以更改。因此,硬编码驱动器号以替换对话框中丢失的驱动器号是行不通的。
- 由于在接受文件或文件夹之前采取的步骤数量未知,因此不能假设驱动器号已经从返回的 QString 中删除。
示例代码
修改由 QtCreator 创建的项目(在我的例子中是 4.13.2,空 QtQuick 项目)。
# autogenerated
QT += quick
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
app.setOrganizationName("Something"); // modified to avoid QML warning
app.setOrganizationDomain("Something.else"); // modified to avoid QML warning
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Dialogs 1.2
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
Window {
width: 640
height: 480
minimumHeight: 320
minimumWidth: 480
visible: true
title: qsTr("Hello World")
color: "grey"
RowLayout {
anchors.fill: parent
Label {
text: "File path:"
Layout.column: 0
}
TextEdit {
id: pathTextEdit
readOnly: true
clip: true
Layout.column: 1
Layout.fillWidth: true
Rectangle {
z: -1
anchors.fill: parent
radius: 3
color: "white"
}
}
Button {
text: "Select file"
Layout.column: 2
onClicked: {
pathSelection.visible = true
}
}
}
FileDialog {
id: pathSelection
visible: false
width: 300
height: 300
selectFolder: true
onAccepted: {
pathTextEdit.text = folder
}
}
}
我很确定因为 WebGL 平台使用与 Windows 文件系统目录结构不同的架构,所以您会得到奇怪的文件夹。您可以使用架构 file://
将 URLS 转换为指向本地计算机上文件的指针,您可以将 folder
属性 与 file:///C:/Users/whatever 一起使用或执行以下操作...
要获取操作系统的底层文件系统位置,您可以使用 folder
属性 和值 shortcuts.home
,如下所述:https://doc.qt.io/qt-5/qml-qtquick-dialogs-filedialog.html
FileDialog {
id: pathSelection
visible: false
width: 300
height: 300
selectFolder: true
// point to an operating system location and you should get
// a usable URL
folder: shortcuts.home
onAccepted: {
pathTextEdit.text = folder
}
}
在 Qt 支持的帮助下,可以找到解决方案。导致该行为的问题在 DefaultFileDialog.qml 中找到,更具体地说,在函数 dirDown
中。可以通过替换
root.folder = "file://" + path
和
root.folder = root.pathToUrl(path)
然后重建 Qt。整个补丁是这样写的:
--- a/src/dialogs/DefaultFileDialog.qml
+++ b/src/dialogs/DefaultFileDialog.qml
@@ -115,7 +115,7 @@ AbstractFileDialog {
function dirDown(path) {
view.selection.clear()
- root.folder = "file://" + path
+ root.folder = root.pathToUrl(path)
}
function dirUp() {
view.selection.clear()
此补丁已提交以包含在 Qt 5.15.3 中。