Как создать общий диалог выбора файла в QT4 для Windows

Я уже некоторое время искал подсказки по этой проблеме, но безрезультатно. Итак, начнем ...

У меня есть приложение, в котором я хочу иметь простую кнопку для открытия диалогового окна файла. В главном окне есть другие кнопки, которые будут читать или создавать / записывать файл (после выполнения соответствующих проверок для выбранной функции). Раньше я без проблем использовал функцию QFileDialog :: getSaveFileName (), но в Windows 7 это не удается, если файл существует И доступен только для чтения. Я переключился на getOpenFileName (), чтобы обойти эту проблему, но теперь диалоговое окно файла не работает, если пользователь пытается выбрать несуществующий файл (не имеет отношения к операции сохранения).

Есть ли способ добавить значок «Создать новый файл» в диалоговое окно файла или добавить его в контекстное меню в диалоговом окне файла? Мне бы очень не хотелось переписывать приложение только из-за (еще одного) изменения поведения Windows.


person GrueMaster    schedule 15.06.2013    source источник
comment
Что вы имеете в виду под неудачей? Ваша программа не работает или что-то не работает в Windows? Если вы ожидаете записи в файл, который уже существует и помечен как только для чтения, я определенно надеюсь, что Windows этого не позволит. Это не неудача, это успех. Вы всегда должны проверять и балансировать, прежде чем пытаться изменить файлы.   -  person RobbieE    schedule 15.06.2013
comment
Под ошибкой я имею в виду, что когда вы нажимаете ОК, диалоговое окно выдает ошибку и не позволяет продолжить. В случае getSaveFileName и файла, доступного только для чтения, ошибка выглядит примерно так: File is read-only, cannot select. В случае нового файла и getOpenFileName возникает ошибка: Файл не существует. В обоих случаях вы вернетесь в диалоговое окно файла и можете либо выбрать файл, который вам не нужен, либо отменить.   -  person GrueMaster    schedule 15.06.2013
comment
Учитывая отсутствие здесь ответов (что очень удивительно), похоже, что мне придется выйти и создать свой собственный диалог с файлом. Мне действительно не нравится иметь два отдельных вызова api диалогового окна файла, которые по сути ничего не делают, а только возвращают имя файла вызывающей функции, но создают ограничения на основе вызова api. Было бы намного лучше с одной функцией с несколькими параметрами, которые могли бы дать одинаковые результаты.   -  person GrueMaster    schedule 21.06.2013
comment
Смысл QFileDialog - предоставить имена файлов и пути к файлам. Он также функционирует как валидатор для базовой операционной системы, чтобы предотвратить глупые вещи, прежде чем вы дойдете до точки чтения или записи файлов. Если вы действительно настаиваете на выполнении нестандартных операций, вы должны ожидать, что вам придется писать потоки параллельного кода.   -  person RobbieE    schedule 22.06.2013


Ответы (2)


QFileDialog::getOpenFileName() следует использовать только для открытия существующих файлов. Если вы вводите имя несуществующего файла, и система жалуется, это нормальное поведение. Он правильно говорит вам, что вы не можете открыть файл, который не существует.

Если вы хотите записать в существующий файл или создать новый файл, вы должны использовать QFileDialog::getSaveFileName()

Если вы пытаетесь записать в существующий файл, который помечен как доступный только для чтения в операционной системе, и вы получаете сообщение об ошибке, говорящее, что файл доступен только для чтения, то ошибка верна. Вам не должно быть разрешено писать в файл, доступный только для чтения, это именно то, что означает Read-Only.

Из того, что вы объяснили, здесь нет ошибок. Все происходит так, как должно быть. Если вы пытаетесь заставить систему делать что-то другое, не делайте этого. Вам лучше попробовать и подумать о том, чтобы делать что-то по-другому.

person RobbieE    schedule 16.06.2013
comment
Отсюда вопрос: как добавить функцию в диалоговое окно файла. Я уже знаю ожидаемое поведение getOpenFileName и getSaveFileName. Мне нужен только getFileName, так как программа в любом случае делает открытие внутри. - person GrueMaster; 17.06.2013

Хорошо, поскольку здесь на самом деле никогда не было ответа, и с тех пор я нашел решение, я подумал, что обновлю его с помощью фрагмента кода, который я использую.

void MainWindow::on_tbBrowse_clicked()
{
    // Use the location of already entered file
    QString fileLocation = leFile->text();
    QFileInfo fileinfo(fileLocation);

    // See if there is a user-defined file extension.
    QString fileType = qgetenv("DiskImagerFiles");
    if (fileType.length() && !fileType.endsWith(";;"))
    {
        fileType.append(";;");
    }
    fileType.append(tr("Disk Images (*.img *.IMG);;*.*"));
    // create a generic FileDialog
    QFileDialog dialog(this, tr("Select a disk image"));
    dialog.setNameFilter(fileType);
    dialog.setFileMode(QFileDialog::AnyFile);
    dialog.setViewMode(QFileDialog::Detail);
    dialog.setConfirmOverwrite(false);
    if (fileinfo.exists())
    {
        dialog.selectFile(fileLocation);
    }
    else
    {
        dialog.setDirectory(myHomeDir);
    }

    if (dialog.exec())
    {
        // selectedFiles returns a QStringList - we just want 1 filename,
        //      so use the zero'th element from that list as the filename
        fileLocation = (dialog.selectedFiles())[0];

        if (!fileLocation.isNull())
        {
            leFile->setText(fileLocation);
            QFileInfo newFileInfo(fileLocation);
            myHomeDir = newFileInfo.absolutePath();
        }
        setReadWriteButtonState();
        updateHashControls();
    }
}

setReadWriteButtonState () включит кнопки в соответствии с состоянием файла:

  • если файл доступен только для чтения, активна только кнопка чтения
  • если файл не существует, активна только кнопка записи

Весь код доступен для просмотра другим пользователям по адресу https://sourceforge.net/projects/win32diskimager/. Я надеюсь, что это поможет следующему человеку, который ищет решение этой проблемы. Просто укажите авторство, если вы используете наш код.

person GrueMaster    schedule 19.07.2019