#qt #dialog #qml #webgl
#qt #диалоговое окно #qml #webgl
Вопрос:
Описание проблемы
При создании приложения QML в Windows для рабочего стола, содержащего FileDialog, отображается диалоговое окно файла Windows по умолчанию. Этот работает как ожидалось, возвращая путь к выбранному файлу или папке с префиксом (file:///) перед путем. Проблема возникает только после того, как WebGL вступает в игру.
Сборка для платформы WebGL и подключение через браузер приведет к тому, что по умолчанию диалоговое окно файла будет иметь значение DefaultFileDialog, которое ведет себя совершенно иначе при выборе (вложенных) каталогов. Допустим, мы начинаем с этого пути в диалоговом окне (обрезан, чтобы сосредоточиться на рентабельности инвестиций):
После выбора подкаталога (одним щелчком мыши):
Другой щелчок вводит этот каталог и заменяет путь на:
Если в подкаталоге выбран другой вариант, мы окончательно потеряем букву диска:
Я ожидаю, что этот путь будет работать в Linux, что может быть причиной, по которой я не смог найти никакой дополнительной информации об этом поведении. Дополнительные шаги в подкаталогах не нарушают дальнейший путь:
Мой поиск до сих пор
Я погуглил, искал 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(amp;engine, amp;QQmlApplicationEngine::objectCreated,
amp;app, [url](QObject *obj, const QUrl amp;objUrl) {
if (!obj amp;amp; 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
}
}
}
Комментарии:
1. Я полагаю, вы можете найти DefaultFileDialog. qml в дереве исходных текстов qtdeclarative вы можете просто скопировать его в папку вашего проекта и изменить его, удалив любой код, который также вызывает нежелательное поведение.
2. Это подход, который я пытаюсь применить после разговора со службой поддержки Qt. Скрестив пальцы, я получаю решение, которое они предоставили для работы 🙂
Ответ №1:
Я почти уверен, что, поскольку платформа WebGL использует схему, отличную от структуры каталогов файловой системы Windows, вы получите странные папки. Вы можете использовать схему file://
для преобразования URL-адресов в указатели на файлы на локальном компьютере, вы можете использовать folder
свойство вместе с file:///C:/Users/что угодно или сделать следующее…
Чтобы получить расположение базовой файловой системы операционной системы, вы можете использовать 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
}
}
Комментарии:
1. Спасибо за предоставление этого ответа. К сожалению, это не помогает мне в этом случае, поскольку начальное местоположение в порядке, но как только я нахожусь в диалоговом окне, возвращаемое значение, сохраненное в
folder
, непригодно для использования (поскольку буква диска удаляется при запуске для WebGL из-за того, что DefaultFileDialog используется вместо диалогового окна системного файла, я полагаю). Итак, я начинаю с действительного пути, но теряю его, работая сам по подкаталогам, как показано на скриншотах-2. Не могли бы вы просто сделать причудливое объединение или что-то в этом роде с возвращаемым именем файла? как
QString newfile = QString("C:/%1").arg(oldfile);
тогда сделатьnewfile.replace("/", QDir::Separator());
, чтобы переключить косые черты??3. Это было бы решением, если бы я мог гарантировать две вещи: 1. Я всегда работаю на диске C 2. Буква диска всегда удаляется. Я отредактирую вопрос, чтобы явно указать требование к букве диска. Спасибо!
Ответ №2:
С помощью поддержки 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.