QFileDialog::selectedUrls()

2025-05-26

もう少し詳しく説明します。

  • selectedFiles()との違い: QFileDialogにはselectedFiles()という似た名前の関数もあります。selectedFiles()QStringList(文字列のリスト)を返し、選択されたファイルやディレクトリのローカルファイルパスを直接提供します。一方、selectedUrls()QList<QUrl>を返し、より汎用的なURL形式で情報を提供します。どちらを使うかは、プログラムの要件によって異なりますが、最近のQtではQUrlベースのselectedUrls()を使用することが推奨される傾向にあります。これは、ファイルパスだけでなく、ネットワーク上のリソースなど、より幅広い「場所」を表現できるためです。

  • 使用例:

    #include <QFileDialog>
    #include <QList>
    #include <QUrl>
    #include <QDebug> // デバッグ出力用
    
    // ... (QApplicationの初期化など)
    
    QFileDialog dialog(this); // ダイアログの作成
    dialog.setFileMode(QFileDialog::ExistingFiles); // 複数の既存ファイルを選択可能にする
    
    if (dialog.exec()) { // ダイアログを表示し、ユーザーがOKをクリックした場合
        QList<QUrl> selectedUrls = dialog.selectedUrls();
        for (const QUrl& url : selectedUrls) {
            qDebug() << "選択されたファイル/ディレクトリのURL: " << url.toString();
            qDebug() << "ローカルパス: " << url.toLocalFile(); // ローカルファイルパスに変換
        }
    }
    

    この例では、QFileDialogを作成し、setFileMode(QFileDialog::ExistingFiles)を使って複数の既存ファイルを選択できるように設定しています。dialog.exec()trueを返した場合(ユーザーが「開く」などをクリックしてダイアログを閉じた場合)、selectedUrls()を呼び出して選択されたURLのリストを取得し、それぞれのURLを表示しています。toLocalFile()は、QUrlをローカルファイルシステムパス(例: /home/user/document.txtC:/Users/user/document.txt)に変換する便利な関数です。

  • 戻り値: QList<QUrl>型の値を返します。これは、QUrlオブジェクトのリスト(配列のようなもの)です。各QUrlは、選択されたファイルまたはディレクトリのパスを表します。

  • selectedUrls()の役割: QFileDialogが表示され、ユーザーが1つまたは複数のファイルやディレクトリを選択して「開く」または「保存」ボタンをクリックすると、その選択結果を取得したい場合があります。selectedUrls()はそのために使用されます。この関数は、選択された各アイテムのURL(QUrlオブジェクト)のリストを返します。

  • QFileDialogとは: QFileDialogは、ユーザーにファイルを開いたり保存したりする場所を選択させるための標準的なダイアログを提供するQtのクラスです。例えば、Windowsのエクスプローラーのような、ファイルやフォルダをツリー形式やリスト形式で表示し、選択できるダイアログを想像してください。



ダイアログがキャンセルされた場合

エラー/問題
ユーザーがファイル選択ダイアログで「キャンセル」ボタンをクリックした、またはダイアログを閉じた場合でも、selectedUrls()を呼び出してしまう。この場合、返されるリストは空になります。

トラブルシューティング
QFileDialogはモーダルダイアログとして使用されることがほとんどです。つまり、exec()メソッドを呼び出し、その戻り値を確認することで、ユーザーが「OK」(開く/保存)をクリックしたか「キャンセル」をクリックしたかを判断できます。

QFileDialog dialog(this);
// ... ダイアログの設定 ...

if (dialog.exec()) { // ユーザーがOKをクリックした場合のみ処理を実行
    QList<QUrl> selectedUrls = dialog.selectedUrls();
    if (!selectedUrls.isEmpty()) {
        // 選択されたURLを処理
        for (const QUrl& url : selectedUrls) {
            qDebug() << "選択されたURL: " << url.toString();
        }
    } else {
        qDebug() << "ファイルが選択されませんでした。";
    }
} else {
    qDebug() << "ダイアログがキャンセルされました。";
}

ポイント
dialog.exec()QDialog::Accepted (通常は1) を返す場合のみ、ファイルが選択されたと判断できます。QDialog::Rejected (通常は0) の場合はキャンセルされたと判断します。

空のリストが返される(ファイルが選択されていない)

エラー/問題
dialog.exec()trueを返したにもかかわらず、selectedUrls()が空のリストを返す場合。これは通常、ファイル選択ダイアログの設定に問題があるか、ユーザーが何も選択せずに「開く」ボタンを押したためです。

トラブルシューティング

  • 初期ディレクトリの確認
    setDirectory()で設定した初期ディレクトリが存在しない、またはアクセス権がない場合、ダイアログが正しく表示されないか、ファイルが表示されないことがあります。

    dialog.setDirectory("/不正な/パス"); // アクセスできないパスや存在しないパス
    
  • フィルター設定の確認
    setNameFilter()setNameFilters()でフィルターを設定している場合、それが原因で目的のファイルが表示されず、結果的に何も選択できないことがあります。

    dialog.setNameFilter(tr("画像ファイル (*.png *.jpg *.jpeg)"));
    // または
    dialog.setNameFilters({"テキストファイル (*.txt)", "すべてのファイル (*.*)"});
    

    フィルターが正しく、かつ期待するファイルが含まれているか確認してください。

  • QFileDialog::FileModeの確認

    • setFileMode(QFileDialog::ExistingFile): 既存の単一ファイルのみ選択可能。
    • setFileMode(QFileDialog::ExistingFiles): 既存の複数ファイルを選択可能。
    • setFileMode(QFileDialog::AnyFile): 既存ファイルまたは新規ファイル名を入力可能(「名前を付けて保存」によく使われる)。
    • setFileMode(QFileDialog::Directory): ディレクトリのみ選択可能。
    • setFileMode(QFileDialog::DirectoryOnly): Directoryと同じだが、ファイルは表示されない。

    意図したファイルモードが設定されているか確認してください。例えば、ファイルを複数選択したいのにExistingFileに設定していると、1つしか選択できません。

URLの処理に関する問題

エラー/問題
selectedUrls()で取得したQUrlオブジェクトを、後続のファイル操作(QFileなど)で使用する際に問題が発生する。例えば、ファイルが見つからない、パスが不正だと解釈されるなど。

トラブルシューティング

  • 特殊文字やスペース
    ファイルパスにスペースや特殊文字が含まれている場合、手動でパスを構築しようとすると問題になることがあります。QUrl::toLocalFile()はこれらのケースを適切に処理しますので、直接パスを結合するのではなく、常にtoLocalFile()を使用することを推奨します。

  • ローカルファイルパスへの変換
    QUrlは汎用的なURL形式ですが、ファイルシステム上のファイル操作には通常ローカルファイルパス(QString)が必要です。QUrl::toLocalFile()を使用して変換します。

    QList<QUrl> selectedUrls = dialog.selectedUrls();
    for (const QUrl& url : selectedUrls) {
        QString localFilePath = url.toLocalFile();
        if (!localFilePath.isEmpty()) {
            QFile file(localFilePath);
            if (file.open(QIODevice::ReadOnly)) {
                qDebug() << "ファイルを開けました: " << localFilePath;
                // ファイルの内容を読み込むなど
                file.close();
            } else {
                qDebug() << "ファイルを開けませんでした: " << localFilePath << " エラー: " << file.errorString();
            }
        } else {
            qDebug() << "URLをローカルファイルパスに変換できませんでした: " << url.toString();
        }
    }
    

    toLocalFile()が空の文字列を返す場合、そのURLはローカルファイルシステム上のパスを表していない可能性があります(例: http://example.com/file.txtなど)。しかし、QFileDialogから返されるURLは通常ローカルファイルです。

ネイティブダイアログに関する問題

エラー/問題
QFileDialogはデフォルトでOSのネイティブなファイルダイアログを使用しようとします。しかし、場合によってはネイティブダイアログが正しく動作しない、または期待通りの見た目にならないことがあります。

トラブルシューティング

  • DLLの欠落 (Windows)
    リリースビルドでQtアプリケーションを実行する場合、必要なDLLが不足していると、ダイアログが表示されずにクラッシュしたり、正しく動作しなかったりすることがあります。Qtのデプロイメントツール(windeployqtなど)を使用して、必要なDLLをすべて含めるようにしてください。

  • ネイティブダイアログの無効化
    setOption(QFileDialog::DontUseNativeDialog)を設定することで、Qt独自のファイルダイアログを使用するように強制できます。これにより、OS固有の問題を回避できる場合があります。

    QFileDialog dialog(this);
    dialog.setOption(QFileDialog::DontUseNativeDialog); // ネイティブダイアログを使用しない
    // ...
    

    ただし、Qt独自のダイアログはOSのUI/UXとは異なるため、見た目や操作感が統一されないというデメリットがあります。

エラー/問題
QFileDialogの表示中にアプリケーションがクラッシュしたりフリーズしたりする。

トラブルシューティング

  • リソース不足やシステムの問題
    非常に稀ですが、システムのメモリ不足やOSのファイルダイアログ関連のコンポーネントに問題がある場合に、クラッシュやフリーズが発生することがあります。他のアプリケーションでファイルダイアログが問題なく開けるか確認したり、OSを再起動してみることも有効です。

  • thisポインタの有効性
    QFileDialog dialog(this);のように親ウィジェットを指定する場合、thisが有効なポインタであることを確認してください。例えば、既に削除されたオブジェクトのポインタを渡すと問題が発生します。通常、ウィジェットのコンストラクタやスロット内で呼び出す場合は問題ありません。

  • メインスレッドでの実行
    QtのGUI操作はすべてメインスレッドで行われる必要があります。QFileDialogの呼び出しが別のスレッドで行われていないか確認してください。別のスレッドから呼び出している場合は、QMetaObject::invokeMethodなどを使用してメインスレッドに処理を委譲する必要があります。



例1: 単一のファイルを選択し、そのパスを表示する

最も基本的な使用例です。ユーザーに既存のファイルを1つだけ選択させます。

#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QFileDialog>
#include <QList>
#include <QUrl>
#include <QDebug> // デバッグ出力用
#include <QLabel> // 選択されたパスを表示するラベル

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        QWidget *centralWidget = new QWidget(this);
        setCentralWidget(centralWidget);

        QVBoxLayout *layout = new QVBoxLayout(centralWidget);

        QPushButton *openFileButton = new QPushButton("ファイルを開く", this);
        layout->addWidget(openFileButton);

        selectedPathLabel = new QLabel("選択されたパス: なし", this);
        layout->addWidget(selectedPathLabel);

        connect(openFileButton, &QPushButton::clicked, this, &MainWindow::onOpenFileClicked);

        setWindowTitle("単一ファイル選択の例");
        resize(400, 200);
    }

private slots:
    void onOpenFileClicked()
    {
        QFileDialog dialog(this);
        dialog.setFileMode(QFileDialog::ExistingFile); // 既存の単一ファイルのみ選択可能
        dialog.setWindowTitle("ファイルを選択してください");
        dialog.setNameFilter("テキストファイル (*.txt);;すべてのファイル (*.*)"); // フィルター設定

        if (dialog.exec()) { // ダイアログが「開く」ボタンで閉じられた場合
            QList<QUrl> selectedUrls = dialog.selectedUrls();
            if (!selectedUrls.isEmpty()) {
                QUrl fileUrl = selectedUrls.first(); // 最初のURLを取得
                QString localFilePath = fileUrl.toLocalFile(); // ローカルファイルパスに変換

                qDebug() << "選択されたファイルURL: " << fileUrl.toString();
                qDebug() << "ローカルファイルパス: " << localFilePath;
                selectedPathLabel->setText("選択されたパス: " + localFilePath);

                // ここで選択されたファイルパスを使って何か処理を行う (例: ファイルの内容を読み込む)
                // QFile file(localFilePath);
                // if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                //     QTextStream in(&file);
                //     qDebug() << "ファイルの内容の最初の行: " << in.readLine();
                //     file.close();
                // }
            } else {
                qDebug() << "ファイルが選択されませんでした。";
                selectedPathLabel->setText("選択されたパス: ファイルが選択されませんでした。");
            }
        } else {
            qDebug() << "ファイル選択がキャンセルされました。";
            selectedPathLabel->setText("選択されたパス: ダイアログがキャンセルされました。");
        }
    }

private:
    QLabel *selectedPathLabel;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

#include "main.moc" // mocファイルを含める

説明

  • fileUrl.toLocalFile()QUrlをローカルファイルパス(QString)に変換し、後のファイル操作で使用できるようにしています。
  • dialog.selectedUrls()QList<QUrl>を返します。単一ファイルモードなので、リストの最初の要素 (selectedUrls.first()) を取得します。
  • dialog.exec() の戻り値で、ユーザーがダイアログを「開く」で閉じたか、「キャンセル」で閉じたかを判断します。
  • dialog.setFileMode(QFileDialog::ExistingFile); で、既存の単一ファイルを選択するように設定しています。

例2: 複数のファイルを選択し、それぞれのパスを表示する

複数のファイルを同時に選択できるように設定します。

#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QFileDialog>
#include <QList>
#include <QUrl>
#include <QDebug>
#include <QTextEdit> // 複数のパスを表示するTextEdit

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        QWidget *centralWidget = new QWidget(this);
        setCentralWidget(centralWidget);

        QVBoxLayout *layout = new QVBoxLayout(centralWidget);

        QPushButton *openFilesButton = new QPushButton("複数のファイルを開く", this);
        layout->addWidget(openFilesButton);

        selectedPathsTextEdit = new QTextEdit(this);
        selectedPathsTextEdit->setReadOnly(true);
        layout->addWidget(selectedPathsTextEdit);

        connect(openFilesButton, &QPushButton::clicked, this, &MainWindow::onOpenFilesClicked);

        setWindowTitle("複数ファイル選択の例");
        resize(500, 300);
    }

private slots:
    void onOpenFilesClicked()
    {
        QFileDialog dialog(this);
        dialog.setFileMode(QFileDialog::ExistingFiles); // 既存の複数ファイルを選択可能
        dialog.setWindowTitle("複数のファイルを選択してください");
        dialog.setNameFilter("すべてのファイル (*.*)");

        selectedPathsTextEdit->clear(); // 以前の選択をクリア

        if (dialog.exec()) {
            QList<QUrl> selectedUrls = dialog.selectedUrls();
            if (!selectedUrls.isEmpty()) {
                QStringList localFilePaths;
                for (const QUrl& url : selectedUrls) {
                    QString localPath = url.toLocalFile();
                    if (!localPath.isEmpty()) {
                        localFilePaths << localPath;
                        qDebug() << "選択されたファイルURL: " << url.toString();
                        qDebug() << "ローカルファイルパス: " << localPath;
                    }
                }
                selectedPathsTextEdit->setText("選択されたファイル:\n" + localFilePaths.join("\n"));
            } else {
                qDebug() << "ファイルが選択されませんでした。";
                selectedPathsTextEdit->setText("ファイルが選択されませんでした。");
            }
        } else {
            qDebug() << "ファイル選択がキャンセルされました。";
            selectedPathsTextEdit->setText("ファイル選択がキャンセルされました。");
        }
    }

private:
    QTextEdit *selectedPathsTextEdit;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

#include "main.moc"

説明

  • forループを使って、リスト内の各QUrlを処理し、toLocalFile()でローカルパスに変換しています。
  • selectedUrls() は、選択されたすべてのQUrlオブジェクトを含むリストを返します。
  • dialog.setFileMode(QFileDialog::ExistingFiles); で、複数の既存ファイルを選択できるようにします。

例3: ディレクトリを選択し、そのパスを表示する

ファイルではなく、ディレクトリ(フォルダ)を選択させたい場合です。

#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QFileDialog>
#include <QList>
#include <QUrl>
#include <QDebug>
#include <QLabel>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        QWidget *centralWidget = new QWidget(this);
        setCentralWidget(centralWidget);

        QVBoxLayout *layout = new QVBoxLayout(centralWidget);

        QPushButton *openDirButton = new QPushButton("ディレクトリを開く", this);
        layout->addWidget(openDirButton);

        selectedPathLabel = new QLabel("選択されたディレクトリ: なし", this);
        layout->addWidget(selectedPathLabel);

        connect(openDirButton, &QPushButton::clicked, this, &MainWindow::onOpenDirectoryClicked);

        setWindowTitle("ディレクトリ選択の例");
        resize(400, 200);
    }

private slots:
    void onOpenDirectoryClicked()
    {
        QFileDialog dialog(this);
        dialog.setFileMode(QFileDialog::Directory); // ディレクトリのみ選択可能
        // dialog.setOption(QFileDialog::ShowDirsOnly, true); // ディレクトリのみ表示 (推奨されるオプション)
        dialog.setWindowTitle("ディレクトリを選択してください");

        if (dialog.exec()) {
            QList<QUrl> selectedUrls = dialog.selectedUrls();
            if (!selectedUrls.isEmpty()) {
                QUrl dirUrl = selectedUrls.first();
                QString localDirPath = dirUrl.toLocalFile();

                qDebug() << "選択されたディレクトリURL: " << dirUrl.toString();
                qDebug() << "ローカルディレクトリパス: " << localDirPath;
                selectedPathLabel->setText("選択されたディレクトリ: " + localDirPath);

                // ここで選択されたディレクトリパスを使って何か処理を行う (例: ディレクトリ内のファイルをリストアップする)
                // QDir dir(localDirPath);
                // QStringList files = dir.entryList(QDir::Files);
                // qDebug() << "ディレクトリ内のファイル: " << files;
            } else {
                qDebug() << "ディレクトリが選択されませんでした。";
                selectedPathLabel->setText("選択されたディレクトリ: ディレクトリが選択されませんでした。");
            }
        } else {
            qDebug() << "ディレクトリ選択がキャンセルされました。";
            selectedPathLabel->setText("選択されたディレクトリ: ダイアログがキャンセルされました。");
        }
    }

private:
    QLabel *selectedPathLabel;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

#include "main.moc"

説明

  • QFileDialog::ShowDirsOnly オプションは、ファイル表示を隠してディレクトリのみを表示するために役立ちますが、Directoryモードと組み合わせて使うのが一般的です。
  • dialog.setFileMode(QFileDialog::Directory); で、ディレクトリのみを選択できるように設定します。

ダイアログが開く際の初期位置と、表示するファイルの種類を制限します。

#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QFileDialog>
#include <QList>
#include <QUrl>
#include <QDebug>
#include <QLabel>
#include <QDir> // QDirを使用して初期ディレクトリを管理

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        QWidget *centralWidget = new QWidget(this);
        setCentralWidget(centralWidget);

        QVBoxLayout *layout = new QVBoxLayout(centralWidget);

        QPushButton *openFilteredFileButton = new QPushButton("画像ファイルを開く", this);
        layout->addWidget(openFilteredFileButton);

        selectedPathLabel = new QLabel("選択された画像ファイル: なし", this);
        layout->addWidget(selectedPathLabel);

        connect(openFilteredFileButton, &QPushButton::clicked, this, &MainWindow::onOpenFilteredFileClicked);

        setWindowTitle("フィルターと初期ディレクトリの例");
        resize(400, 200);
    }

private slots:
    void onOpenFilteredFileClicked()
    {
        QFileDialog dialog(this);
        dialog.setFileMode(QFileDialog::ExistingFile);
        dialog.setWindowTitle("画像ファイルを選択してください");

        // 初期ディレクトリを設定 (例: ドキュメントフォルダ)
        // QDir::homePath() はユーザーのホームディレクトリを返します
        // QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) も利用できます
        QString initialDir = QDir::homePath();
        qDebug() << "初期ディレクトリ: " << initialDir;
        dialog.setDirectory(initialDir);

        // 複数のフィルターを設定
        dialog.setNameFilters({
            "画像ファイル (*.png *.jpg *.jpeg *.gif)",
            "PNG画像 (*.png)",
            "JPEG画像 (*.jpg *.jpeg)",
            "すべてのファイル (*.*)"
        });
        dialog.selectNameFilter("画像ファイル (*.png *.jpg *.jpeg *.gif)"); // デフォルトで選択されるフィルター

        if (dialog.exec()) {
            QList<QUrl> selectedUrls = dialog.selectedUrls();
            if (!selectedUrls.isEmpty()) {
                QUrl fileUrl = selectedUrls.first();
                QString localFilePath = fileUrl.toLocalFile();

                qDebug() << "選択された画像ファイルURL: " << fileUrl.toString();
                qDebug() << "ローカルパス: " << localFilePath;
                selectedPathLabel->setText("選択された画像ファイル: " + localFilePath);
            } else {
                qDebug() << "画像ファイルが選択されませんでした。";
                selectedPathLabel->setText("選択された画像ファイル: ファイルが選択されませんでした。");
            }
        } else {
            qDebug() << "画像ファイル選択がキャンセルされました。";
            selectedPathLabel->setText("選択された画像ファイル: ダイアログがキャンセルされました。");
        }
    }

private:
    QLabel *selectedPathLabel;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

#include "main.moc"
  • dialog.selectNameFilter(...); で、初期状態でどのフィルターが選択されているかを指定します。
  • dialog.setNameFilters({...}); で、複数のファイルフィルターを設定できます。
  • dialog.setDirectory(initialDir); で、ダイアログが開く際の初期ディレクトリを設定します。


ここでは、QFileDialog::selectedUrls()の代替手段と、関連して知っておくと役立つメソッドについて説明します。

QFileDialog::selectedFiles() の使用

これは最も直接的な代替手段であり、実際にQtの以前のバージョンではselectedUrls()よりも頻繁に使用されていました。

  • selectedUrls()との違い:
    • selectedUrls()QUrlオブジェクトのリストを返し、より汎用的なURI/URLの表現に対応しています。これに対し、selectedFiles()は純粋なローカルファイルシステムパスを返します。
    • 通常、selectedUrls()はネットワークパスなど、より広範な「場所」を表現できるため、新しいQtコードでは推奨されます。しかし、ほとんどのケース(特にローカルファイルを扱う場合)では、両者から得られる情報は実質的に同じです。
    • QUrlからローカルパスに変換するにはQUrl::toLocalFile()が必要ですが、selectedFiles()は直接QStringとして提供します。
  • 戻り値: QStringList (文字列のリスト)
  • 機能: ユーザーが選択したファイルやディレクトリのローカルファイルパス(QString型)のリストを返します。

使用例

// ... (QFileDialog の設定と exec() の呼び出しは selectedUrls() の例と同じ)

if (dialog.exec()) {
    QStringList selectedFilePaths = dialog.selectedFiles(); // ここが異なる
    if (!selectedFilePaths.isEmpty()) {
        for (const QString& path : selectedFilePaths) {
            qDebug() << "選択されたローカルファイルパス: " << path;
            // 直接このパスを使ってファイル操作ができる
            // QFile file(path);
            // ...
        }
    } else {
        qDebug() << "ファイルが選択されませんでした。";
    }
} else {
    qDebug() << "ダイアログがキャンセルされました。";
}

いつ使うか:

  • ネットワークリソースなどを考慮する必要が全くない単純なファイル選択の場合。
  • 古いQtプロジェクトとの互換性を保ちたい場合。
  • 明確にローカルファイルシステムパスが必要であり、QUrlから変換する手間を省きたい場合。

静的関数(QFileDialog::getOpenFileName, getSaveFileName, getExistingDirectory, getOpenFileNames)の使用

QFileDialogをインスタンス化して設定する代わりに、Qtはいくつかの便利な静的関数を提供しています。これらは、一般的なファイル選択や保存のシナリオを簡潔に記述するのに役立ちます。

  • QFileDialog::getOpenFileNames(): 複数の既存ファイルを開くためのダイアログを表示し、選択されたファイルのパスリスト(QStringList)を返します。
  • QFileDialog::getExistingDirectory(): 既存のディレクトリを選択するためのダイアログを表示し、選択されたディレクトリのパス(QString)を返します。
  • QFileDialog::getSaveFileName(): ファイルを保存するためのダイアログを表示し、入力されたファイル名(QString)を返します。
  • QFileDialog::getOpenFileName(): 単一の既存ファイルを開くためのダイアログを表示し、選択されたファイルのパス(QString)を返します。キャンセルされた場合は空の文字列を返します。

使用例 (getOpenFileNames の例)

// ... (QApplication の初期化など)

QStringList selectedFilePaths = QFileDialog::getOpenFileNames(
    this, // 親ウィジェット
    tr("複数のファイルを選択"), // ダイアログのタイトル
    QDir::homePath(), // 初期ディレクトリ
    tr("テキストファイル (*.txt);;すべてのファイル (*.*)") // フィルター
);

if (!selectedFilePaths.isEmpty()) {
    for (const QString& path : selectedFilePaths) {
        qDebug() << "選択されたファイル: " << path;
    }
} else {
    qDebug() << "ファイル選択がキャンセルされたか、ファイルが選択されませんでした。";
}

いつ使うか:

  • 単一のファイル、複数のファイル、またはディレクトリの選択という、ごく一般的なタスクの場合。
  • ダイアログの細かなオプション(例: setOption())を設定する必要がない場合。
  • QFileDialogのインスタンスを明示的に作成・設定する手間を省き、コードをより簡潔にしたい場合。

QFileDialogはモーダルダイアログとしてexec()を使用するのが一般的ですが、非同期的にファイル選択を行いたい場合は、シグナルとスロットを活用することもできます。

  • urlsSelected(const QList<QUrl> &urls) シグナル: 複数のURLが選択されたときに発火します。
  • urlSelected(const QUrl &url) シグナル: 単一URLが選択されたときに発火します。
  • filesSelected(const QStringList &files) シグナル: 複数のファイルが選択されたときに発火します。
  • fileSelected(const QString &file) シグナル: 単一ファイルが選択されたときに発火します。

これらのシグナルは、ユーザーがダイアログで「開く」ボタンをクリックしたときに発火します。

使用例

// MainWindow クラス内、または QFileDialog を扱うクラス内
void MyClass::openFileDialogAsync()
{
    QFileDialog *dialog = new QFileDialog(this);
    dialog->setFileMode(QFileDialog::ExistingFiles);
    dialog->setWindowTitle("非同期ファイル選択");

    // urlsSelected シグナルをカスタムスロットに接続
    connect(dialog, &QFileDialog::urlsSelected, this, &MyClass::onFilesSelectedAsync);

    // ダイアログが閉じられたときに自動的に削除されるように設定
    dialog->setAttribute(Qt::WA_DeleteOnClose);

    dialog->open(); // モーダルではなく、非同期でダイアログを開く
}

void MyClass::onFilesSelectedAsync(const QList<QUrl> &urls)
{
    if (!urls.isEmpty()) {
        for (const QUrl& url : urls) {
            qDebug() << "非同期で選択されたURL: " << url.toString();
        }
    } else {
        qDebug() << "非同期選択でファイルが選ばれませんでした。";
    }
}

いつ使うか:

  • Qt Concurrent やスレッドと組み合わせて、バックグラウンドでのファイル処理をトリガーしたい場合。
  • 非同期処理のパターンに合わせたい場合。
  • ダイアログの表示中にUIがブロックされるのを避けたい場合(ただし、QFileDialog自体は通常、モーダルダイアログとして設計されており、これが必要になるケースは限られます)。
  • シグナル/スロット: 非同期的な処理が必要な場合や、よりイベント駆動型のデザインを好む場合に検討。
  • 静的関数 (getOpenFileNameなど): 最も手軽にファイル選択ダイアログを表示したい場合に最適。
  • QFileDialog::selectedFiles(): ローカルファイルパスを直接取得したい場合に便利。
  • QFileDialog::selectedUrls(): 最新のQtで推奨される、URL形式で結果を取得する方法。汎用性が高い。