【Qt】QFileDialog::getOpenFileUrl()徹底解説!ファイル選択の基本と応用

2025-05-27

QUrl QFileDialog::getOpenFileUrl()とは?

QFileDialog::getOpenFileUrl()は、QtのQFileDialogクラスが提供する静的関数の一つで、ユーザーがファイル選択ダイアログを通じて単一のファイルを選択するための機能を提供します。この関数は、選択されたファイルのパスをQUrlオブジェクトとして返します。

QUrlについて

ここで重要なのが、戻り値の型がQStringではなくQUrlである点です。

  • QString: 通常、ローカルファイルシステムのパスを表すのに使われます。

getOpenFileUrl()QUrlを返すのは、ローカルファイルだけでなく、場合によってはネットワーク上のファイルなど、より広範なリソースを選択できる可能性を考慮しているためです。ただし、現在のQtの多くの実装では、ネイティブダイアログを使用する場合、ローカルファイルに限定されることがほとんどです。

機能と用途

この関数を使用すると、以下のようなファイル選択ダイアログを表示できます。

  • タイトル: ダイアログのタイトルバーに表示されるテキストを指定できます。
  • 初期ディレクトリ: ダイアログが最初に表示されるディレクトリを指定できます。
  • フィルタリング: 特定のファイルの種類(例: 画像ファイル *.png *.jpg、テキストファイル *.txt)のみを表示するようにフィルタを設定できます。
  • ファイルの選択: ユーザーがコンピュータ上のディレクトリを移動し、目的のファイルを選択することができます。

関数のシグネチャ(引数)

最も一般的なオーバーロードは以下のようになります。

QList<QUrl> QFileDialog::getOpenFileUrls(
    QWidget *parent = Q_NULLPTR,
    const QString &caption = QString(),
    const QUrl &dir = QUrl(),
    const QString &filter = QString(),
    QString *selectedFilter = Q_NULLPTR,
    Options options = Options(),
    const QStringList &supportedSchemes = QStringList()
)

それぞれの引数の意味は以下の通りです。

  • const QStringList &supportedSchemes (サポートされるスキーム):
    • このダイアログで選択できるURLスキーム(例: "file", "http", "ftp")のリストを指定します。デフォルトは空のリストで、この場合、特に制限は適用されません("file"スキームは常に暗黙的にサポートされます)。
  • Options options (オプション):
    • ダイアログの挙動を制御するためのオプションフラグです。QFileDialog::Option列挙体の値をORで結合して指定します。
    • よく使われるオプション:
      • QFileDialog::DontUseNativeDialog: プラットフォームネイティブのダイアログではなく、Qtが提供するウィジェットベースのダイアログを使用するように強制します。
      • QFileDialog::ReadOnly: 読み取り専用でファイルを開くことを示します(多くの場合、ダイアログの挙動には影響しませんが、ファイルを開くロジックで利用されます)。
  • QString *selectedFilter (選択されたフィルタ):
    • ユーザーがダイアログでどのフィルタを選択したかを保存するためのポインタです。必要なければNULLを指定できます。
  • const QString &filter (ファイルフィルタ):
    • 表示するファイルの種類を絞り込むためのフィルタ文字列です。
    • 例: "Images (*.png *.xpm *.jpg);;Text files (*.txt);;All files (*)"
    • セミコロン2つ(;;)で複数のフィルタを区切ります。
  • const QUrl &dir (初期ディレクトリ):
    • ダイアログが最初に開かれるディレクトリをQUrlで指定します。QUrl()(空のURL)を指定すると、システムが適切なデフォルトディレクトリ(通常はユーザーのホームディレクトリなど)を使用します。
  • const QString &caption (キャプション):
    • ファイル選択ダイアログのタイトルバーに表示される文字列です。
  • QWidget *parent (親ウィジェット):
    • ダイアログの親となるウィジェットを指定します。NULLを指定することも可能ですが、指定することでダイアログが親ウィンドウの中心に表示されたり、親ウィンドウが最小化されたときに一緒に最小化されたりといった挙動になります。

戻り値

  • QList<QUrl>: ユーザーが選択したファイルのQUrlのリストを返します。通常、getOpenFileUrl()は単一ファイルの選択を意図しているため、リストには1つのQUrlが含まれるか、ユーザーがキャンセルした場合は空のリストが返されます。
#include <QApplication>
#include <QFileDialog>
#include <QMessageBox>
#include <QUrl>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // ファイルダイアログを表示し、ユーザーにファイルを選択させる
    // 親ウィジェットはなし (NULL)、タイトルは "ファイルを開く"
    // 初期ディレクトリはデフォルト
    // フィルタは "テキストファイル (*.txt);;すべてのファイル (*)"
    QList<QUrl> urls = QFileDialog::getOpenFileUrls(
        NULL,
        QObject::tr("ファイルを開く"),
        QUrl(),
        QObject::tr("テキストファイル (*.txt);;すべてのファイル (*)"),
        NULL,
        QFileDialog::DontUseNativeDialog // ネイティブダイアログを使用しない例
    );

    if (!urls.isEmpty()) {
        // ユーザーがファイルを選択した場合
        for (const QUrl &url : urls) {
            QMessageBox::information(NULL, QObject::tr("選択されたファイル"), url.toLocalFile());
            // 通常はここで選択されたファイルパスを使って処理を続行します
        }
    } else {
        // ユーザーがダイアログをキャンセルした場合
        QMessageBox::information(NULL, QObject::tr("選択なし"), QObject::tr("ファイルは選択されませんでした。"));
    }

    return a.exec();
}
  • QUrl::toLocalFile()を使って、QUrlをローカルファイルパスを示すQStringに変換することができます。
  • ユーザーが「キャンセル」をクリックすると、空のQList<QUrl>が返されます。
  • ユーザーが「開く」(またはプラットフォームごとの対応するボタン)をクリックすると、選択されたファイルのQUrlが返されます。
  • QFileDialog::getOpenFileUrl()モーダルダイアログを表示します。これは、ダイアログが閉じられるまで、アプリケーションの他の部分を操作できないことを意味します。


QFileDialogはOSのネイティブダイアログを利用することが多いため、環境依存の問題が発生しやすい傾向があります。また、QUrlの扱い方に関する誤解もエラーの原因となることがあります。

ダイアログが表示されない、またはクラッシュする

一般的な原因

  • Qtのバグ
    まれに、特定のQtのバージョンやOSの組み合わせで、QFileDialog自体にバグがある場合があります。
  • 初期ディレクトリまたはURLの不正
    dir引数に無効なパスやアクセス権のないパスを指定した場合、ダイアログの表示に失敗したり、予期せぬ動作をしたりすることがあります。
  • 環境設定の問題 (Linux/macOS)
    • Linux (特にGTK/KDE環境)
      ネイティブダイアログのバックエンド(GTK+やKDEのファイルダイアログ)が正しくインストールされていない、または設定されていない場合に問題が発生することがあります。QtのアプリケーションがGTK+やKDEのテーマと競合する場合もあります。
    • macOS
      特定のバージョンのmacOSやQtの組み合わせで、ネイティブダイアログの表示に問題が生じることがあります。
  • 必要なDLL/ライブラリの不足 (Windows)
    リリースビルドでアプリケーションを実行する場合、必要なQtのDLLや、OSネイティブダイアログが依存するDLL(例えば、WindowsのCOM関連DLLなど)が不足していると、ダイアログが表示されずにクラッシュすることがあります。
  • GUIスレッド以外からの呼び出し
    QFileDialogはGUI要素であり、GUIスレッド(メインスレッド)から呼び出す必要があります。別のスレッドから呼び出すと、アプリケーションがフリーズしたりクラッシュしたりする可能性があります。

トラブルシューティング

  • 初期ディレクトリの省略または簡単なパスの指定
    dir引数を空のQUrl()にするか、QDir::homePath()など、確実に存在するシンプルなパスを初期ディレクトリとして指定してみてください。
  • Qtバージョンの更新/ダウングレード
    特定のQtバージョンで問題が発生している場合、新しいバージョンに更新するか、安定していると分かっている以前のバージョンを試してみるのも有効です。
  • ログ出力の確認
    アプリケーションをデバッグモードで実行し、コンソールやデバッグログにエラーメッセージや警告が出力されていないか確認します。
  • DLL/ライブラリの確認 (Windows)
    windeployqtツールを使って必要なDLLをすべて含めるか、手動でQtbinディレクトリから必要なDLL(Qt5Core.dll, Qt5Gui.dll, Qt5Widgets.dllなど)と、プラットフォームプラグイン(platformsディレクトリ以下のqwindows.dllなど)、イメージフォーマットプラグイン(imageformatsディレクトリ以下のqjpeg.dllなど)をアプリケーションの実行ファイルと同じディレクトリに配置してください。
  • QFileDialog::DontUseNativeDialogオプションの試用
    • もしダイアログが全く表示されない、またはクラッシュする場合は、QFileDialog::DontUseNativeDialogオプションを試してみてください。これにより、Qtが独自に実装したファイルダイアログが使用され、OSネイティブダイアログの問題を回避できる可能性があります。
    • 例:
      QList<QUrl> urls = QFileDialog::getOpenFileUrls(
          this,
          tr("ファイルを開く"),
          QUrl(),
          tr("すべてのファイル (*)"),
          NULL,
          QFileDialog::DontUseNativeDialog // ネイティブダイアログを使用しない
      );
      

QUrlが期待通りのパスを返さない

一般的な原因

  • ファイルが存在しない場合
    ユーザーがダイアログをキャンセルした場合、getOpenFileUrls()は空のQList<QUrl>を返します。これをチェックせずにurls.at(0)などにアクセスすると、クラッシュの原因になります。
  • ネットワークパス (UNCパス) の問題
    QFileDialog::getOpenFileUrl()は、ネイティブダイアログを使用している場合、共有ネットワークドライブ(UNCパス、例: \\Server\Share\file.txt)を選択できることがありますが、これをQUrlとして受け取った際に、正しくfile:///スキームに変換されない、またはtoLocalFile()が期待通りに動作しないことがあります。
  • ローカルファイルパスへの変換ミス
    QUrlは様々な種類のURIを扱うため、ローカルファイルパスとして利用するにはtoLocalFile()メソッドで変換する必要があります。

トラブルシューティング

  • ネットワークパスの扱い
    ネットワーク上のファイル(FTP, HTTPなど)を選択する要件がある場合、QFileDialogの標準機能では不十分な場合があります。その場合、QNetworkAccessManagerなどQtのネットワーク機能を使って、別途ファイルのダウンロードやアクセスロジックを実装する必要があります。ネイティブダイアログがFTPなどのURLを返した場合でも、QtのファイルI/O関数は直接それを扱えないことが多いです。
  • urls.isEmpty()の確認
    常にgetOpenFileUrls()の戻り値が空でないかを確認してから、リスト内の要素にアクセスするようにしてください。
  • QUrl::isLocalFile()のチェック
    処理を進める前に、url.isLocalFile()で、取得したQUrlがローカルファイルシステム上のファイルを示しているか確認することができます。
  • toLocalFile()の使用
    選択されたURLがローカルファイルを示す場合、必ずurl.toLocalFile()QStringに変換して使用します。
    if (!urls.isEmpty()) {
        QString filePath = urls.first().toLocalFile();
        if (!filePath.isEmpty()) {
            // filePath を使用してファイル操作を行う
        } else {
            // ローカルファイルパスに変換できなかった場合 (例: ネットワークリソースなど)
            QMessageBox::warning(this, tr("警告"), tr("選択されたファイルはローカルファイルではありません。"));
        }
    }
    

フィルタが正しく適用されない、または表示されない

一般的な原因

  • ネイティブダイアログの挙動
    ネイティブダイアログは、Qtが指定したフィルタ文字列をOSのAPIに渡しますが、OSによってはQtが想定する全てのフィルタフォーマットを完全にサポートしていない場合があります。
  • フィルタ文字列のフォーマットミス
    フィルタ文字列の記述が間違っていると、期待通りにファイルが絞り込まれません。

トラブルシューティング

  • QFileDialog::DontUseNativeDialogオプションの試用
    ネイティブダイアログのフィルタ処理に問題がある場合、DontUseNativeDialogを試すことで、Qt自身のダイアログでフィルタが正しく機能するか確認できます。
  • フィルタ文字列の確認
    • 正しいフォーマットは "説明 (*.拡張子1 *.拡張子2);;別の説明 (*.別の拡張子)" です。
    • 例: "画像ファイル (*.png *.jpg *.jpeg);;テキストファイル (*.txt);;すべてのファイル (*)"
    • 拡張子の前には*.が必要で、複数の拡張子を指定する場合はスペースで区切ります。

ダイアログの表示位置やサイズが意図しない

一般的な原因

  • parent引数の不足
    getOpenFileUrl()を呼び出す際にparent引数をNULLにしている場合、ダイアログは画面の中央やOSが決定する位置に表示されます。親ウィジェットを指定しないと、ダイアログがアプリケーションの背後に隠れてしまうこともあります。
  • 親ウィジェットの指定
    getOpenFileUrl()の第一引数に、ダイアログの親となるQWidgetのポインタ(通常は現在のウィンドウのthis)を指定してください。これにより、ダイアログが親ウィンドウに紐付けられ、適切な位置に表示される可能性が高まります。
    // MyMainWindowクラスのメンバー関数から呼び出す場合
    QList<QUrl> urls = QFileDialog::getOpenFileUrls(this, tr("ファイルを開く"));
    


QFileDialog::getOpenFileUrl() は、ユーザーにファイルを選択させるための非常に便利な静的関数です。ここでは、基本的な使用方法から、より詳細なオプションを使った例まで、いくつかご紹介します。

例 1: 基本的なファイル選択ダイアログ

最もシンプルにファイル選択ダイアログを表示する例です。

#include <QApplication>
#include <QFileDialog>
#include <QMessageBox>
#include <QUrl>
#include <QString> // QUrl::toLocalFile() の結果を受け取るため

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // QFileDialog::getOpenFileUrls() を呼び出す。
    // 静的関数なので、インスタンスを作成する必要はありません。
    //
    // 引数:
    // 1. parent: 親ウィジェット。NULL を指定すると、ダイアログは独立して表示されます。
    // 2. caption: ダイアログのタイトルバーに表示されるテキスト。
    // 3. dir: ダイアログが最初に開かれるディレクトリ(QUrl形式)。QUrl() でデフォルト。
    // 4. filter: ファイルの種類を絞り込むフィルタ。
    // 5. selectedFilter: ユーザーが選択したフィルタを格納するポインタ(不要なら NULL)。
    // 6. options: ダイアログの挙動を制御するオプション。
    QList<QUrl> selectedUrls = QFileDialog::getOpenFileUrls(
        nullptr, // 親ウィジェットなし
        QObject::tr("ファイルを選択してください"), // ダイアログのタイトル
        QUrl(), // デフォルトのディレクトリ(通常はユーザーのホームディレクトリなど)
        QObject::tr("テキストファイル (*.txt);;すべてのファイル (*)") // フィルタ
    );

    // ユーザーがファイルを一つでも選択したか確認
    if (!selectedUrls.isEmpty()) {
        // 最初の選択されたファイル (QList<QUrl>なので、複数選択も考慮されるが、
        // getOpenFileUrl()の性質上、通常は1つ)
        QUrl firstUrl = selectedUrls.first();

        // QUrlをローカルファイルパス (QString) に変換
        QString filePath = firstUrl.toLocalFile();

        // 選択されたファイルパスを表示
        QMessageBox::information(
            nullptr, // 親ウィジェットなし
            QObject::tr("ファイルが選択されました"),
            QObject::tr("選択されたファイル: ") + filePath
        );

        // ここで選択されたファイルパス (filePath) を使って、
        // ファイルの読み込みなどの処理を行います。
    } else {
        // ユーザーが「キャンセル」ボタンを押した、または何も選択しなかった場合
        QMessageBox::information(
            nullptr, // 親ウィジェットなし
            QObject::tr("選択なし"),
            QObject::tr("ファイルは選択されませんでした。")
        );
    }

    return a.exec();
}

例 2: オプションと初期ディレクトリの指定

ダイアログの表示方法を細かく制御するためのオプションや、特定の初期ディレクトリを指定する例です。

#include <QApplication>
#include <QFileDialog>
#include <QMessageBox>
#include <QUrl>
#include <QDir> // QDir::homePath() を使うため

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 初期ディレクトリをユーザーのホームディレクトリに設定
    // QUrl::fromLocalFile() でローカルパスをQUrlに変換
    QUrl initialDir = QUrl::fromLocalFile(QDir::homePath());

    // フィルタ文字列を定義
    QString filter = QObject::tr("画像ファイル (*.png *.jpg *.jpeg *.gif);;動画ファイル (*.mp4 *.avi);;すべてのファイル (*)");

    // ユーザーが選択したフィルタを格納する変数
    QString selectedFilter;

    // オプションを設定:
    // QFileDialog::DontUseNativeDialog: OSネイティブのダイアログではなく、Qtのダイアログを使用する
    // QFileDialog::ReadOnly: ファイルを読み取り専用で開くことを示す(このダイアログでは挙動に影響しないことが多い)
    QFileDialog::Options options;
    options |= QFileDialog::DontUseNativeDialog; // Qtのダイアログを使う
    options |= QFileDialog::ReadOnly; // 読み取り専用

    QList<QUrl> selectedUrls = QFileDialog::getOpenFileUrls(
        nullptr, // 親ウィジェットなし
        QObject::tr("開くファイルを選択"), // タイトル
        initialDir, // 初期ディレクトリをホームディレクトリに設定
        filter, // 定義したフィルタを使用
        &selectedFilter, // 選択されたフィルタをこの変数に格納
        options // 定義したオプションを使用
    );

    if (!selectedUrls.isEmpty()) {
        QUrl fileUrl = selectedUrls.first();
        QString filePath = fileUrl.toLocalFile();

        QString message = QObject::tr("選択されたファイル: %1\n選択されたフィルタ: %2")
                              .arg(filePath)
                              .arg(selectedFilter);
        QMessageBox::information(nullptr, QObject::tr("ファイル選択完了"), message);
    } else {
        QMessageBox::information(nullptr, QObject::tr("選択なし"), QObject::tr("ファイルは選択されませんでした。"));
    }

    return a.exec();
}

例 2 のポイント

  • QFileDialog::Options
    | (ビットOR) 演算子を使って複数のオプションフラグを結合できます。QFileDialog::DontUseNativeDialog は、OSネイティブダイアログに関する問題が発生した場合のトラブルシューティングによく使われます。
  • selectedFilter
    ユーザーが実際にどのフィルタを選択したかを、ポインタを渡すことで取得できます。
  • フィルタの複数指定
    セミコロン2つ(;;)で区切ることで、複数のフィルタをQFileDialogに提供できます。ユーザーはダイアログのドロップダウンからフィルタを選択できます。
  • QDir::homePath() と QUrl::fromLocalFile()
    ローカルファイルシステムのパスをQUrlに変換して初期ディレクトリとして指定しています。

例 3: ウィジェット内部での使用 (親ウィジェットの指定)

実際のアプリケーションでは、メインウィンドウや他のウィジェットのメンバー関数としてQFileDialogを呼び出すことが多いです。この場合、parent引数にthisを指定することで、ダイアログがその親ウィジェットに紐付けられます。

#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QFileDialog>
#include <QMessageBox>
#include <QUrl>
#include <QDebug> // デバッグ出力用

// メインウィンドウクラス
class MyMainWindow : public QMainWindow
{
    Q_OBJECT // シグナル・スロットを使用するために必要

public:
    MyMainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        setWindowTitle(tr("ファイル選択の例"));
        setFixedSize(300, 150);

        QPushButton *openFileButton = new QPushButton(tr("ファイルを開く"), this);

        // ボタンがクリックされたときに openFile() スロットを呼び出す
        connect(openFileButton, &QPushButton::clicked, this, &MyMainWindow::openFile);

        QWidget *centralWidget = new QWidget(this);
        QVBoxLayout *layout = new QVBoxLayout(centralWidget);
        layout->addWidget(openFileButton);
        setCentralWidget(centralWidget);
    }

private slots:
    void openFile()
    {
        qDebug() << "openFile() スロットが呼ばれました";

        QList<QUrl> selectedUrls = QFileDialog::getOpenFileUrls(
            this, // 親ウィジェットを現在のウィンドウ (MyMainWindow) に設定
            QObject::tr("画像ファイルを選択"),
            QUrl(), // デフォルトの初期ディレクトリ
            QObject::tr("画像ファイル (*.png *.jpg *.jpeg);;すべてのファイル (*)")
        );

        if (!selectedUrls.isEmpty()) {
            QUrl fileUrl = selectedUrls.first();
            QString filePath = fileUrl.toLocalFile();

            QMessageBox::information(
                this, // 親ウィジェットを設定
                QObject::tr("ファイルが選択されました"),
                QObject::tr("選択されたファイル: ") + filePath
            );
            qDebug() << "選択されたファイルパス:" << filePath;
        } else {
            QMessageBox::information(
                this, // 親ウィジェットを設定
                QObject::tr("選択なし"),
                QObject::tr("ファイルは選択されませんでした。")
            );
            qDebug() << "ファイル選択がキャンセルされました。";
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MyMainWindow mainWindow;
    mainWindow.show();

    return a.exec();
}

#include "main.moc" // mocファイルを含める(Qt Creator/qmakeが自動生成)

  • QDebug
    開発中に変数の値やプログラムの流れを確認するために、qDebug() を使うと便利です。
  • this を親ウィジェットとして渡す
    openFile() スロット内で QFileDialog::getOpenFileUrls(this, ...) とすることで、生成されるファイルダイアログが MyMainWindow の子として扱われます。これにより、ダイアログの位置やZオーダー(手前に表示されるか)が適切に管理され、親ウィンドウが最小化されたときにダイアログも一緒に最小化されるなどの挙動が期待できます。
  • Q_OBJECT マクロ
    シグナルとスロットを使用するクラスには必須です。


主な代替手段は以下の3つに分けられます。

  1. QFileDialog の他の静的関数を使用する
  2. QFileDialog オブジェクトをインスタンス化して使用する
  3. 完全にカスタムなファイル選択ダイアログを実装する

QFileDialog の他の静的関数を使用する

QFileDialog には、getOpenFileUrl() (実際には getOpenFileUrls() ですが、単一ファイル選択用途ではこの関数で十分です) 以外にも便利な静的関数がいくつかあります。これらは、特定のユースケースに特化しており、よりシンプルなコードで目的を達成できる場合があります。

  • QString QFileDialog::getExistingDirectory(...)

    • 特徴
      ディレクトリ(フォルダ)のみをユーザーに選択させ、そのパスをQStringとして返します。
    • 用途
      ファイルではなく、特定のフォルダを選択させたい場合。

    • #include <QApplication>
      #include <QFileDialog>
      #include <QMessageBox>
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
      
          QString directoryPath = QFileDialog::getExistingDirectory(
              nullptr,
              QObject::tr("フォルダを選択してください"),
              QDir::homePath(),
              QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks // オプション
          );
      
          if (!directoryPath.isEmpty()) {
              QMessageBox::information(
                  nullptr,
                  QObject::tr("フォルダが選択されました"),
                  QObject::tr("選択されたフォルダ: ") + directoryPath
              );
          } else {
              QMessageBox::information(
                  nullptr,
                  QObject::tr("選択なし"),
                  QObject::tr("フォルダは選択されませんでした。")
              );
          }
      
          return a.exec();
      }
      
  • QString QFileDialog::getSaveFileName(...)

    • 特徴
      ファイルの保存先とファイル名をユーザーに選択させ、そのパスをQStringとして返します。
    • 用途
      ユーザーにファイルを保存させる場合。「名前を付けて保存」機能。

    • #include <QApplication>
      #include <QFileDialog>
      #include <QMessageBox>
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
      
          QString saveFilePath = QFileDialog::getSaveFileName(
              nullptr,
              QObject::tr("ファイルを保存"),
              QDir::homePath() + "/新しいファイル.txt", // 初期ファイル名
              QObject::tr("テキストファイル (*.txt);;すべてのファイル (*)")
          );
      
          if (!saveFilePath.isEmpty()) {
              QMessageBox::information(
                  nullptr,
                  QObject::tr("保存パスが選択されました"),
                  QObject::tr("保存先: ") + saveFilePath
              );
              // ここでファイルにデータを書き込む処理を行う
          } else {
              QMessageBox::information(
                  nullptr,
                  QObject::tr("キャンセル"),
                  QObject::tr("ファイル保存がキャンセルされました。")
              );
          }
      
          return a.exec();
      }
      
  • QStringList QFileDialog::getOpenFileNames(...)

    • 特徴
      ユーザーが複数のファイルを選択できるようにし、そのパスをQStringListとして返します。
    • 用途
      複数のファイルを一度に開きたい場合。

    • #include <QApplication>
      #include <QFileDialog>
      #include <QMessageBox>
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
      
          QStringList filePaths = QFileDialog::getOpenFileNames(
              nullptr,
              QObject::tr("複数のファイルを選択してください"),
              QDir::homePath(),
              QObject::tr("テキストファイル (*.txt);;すべてのファイル (*)")
          );
      
          if (!filePaths.isEmpty()) {
              QString message = QObject::tr("選択されたファイル:\n") + filePaths.join("\n");
              QMessageBox::information(
                  nullptr,
                  QObject::tr("ファイルが選択されました"),
                  message
              );
          } else {
              QMessageBox::information(
                  nullptr,
                  QObject::tr("選択なし"),
                  QObject::tr("ファイルは選択されませんでした。")
              );
          }
      
          return a.exec();
      }
      
    • 特徴
      選択されたファイルのパスをQStringとして返します。QUrlに変換する必要がないため、ローカルファイルパスのみを扱う場合はよりシンプルです。
    • 用途
      最も一般的な「ファイルを開く」ダイアログで、ファイルパスを文字列として取得したい場合。

    • #include <QApplication>
      #include <QFileDialog>
      #include <QMessageBox>
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
      
          QString filePath = QFileDialog::getOpenFileName(
              nullptr,
              QObject::tr("ファイルを選択してください"),
              QDir::homePath(), // 初期ディレクトリ
              QObject::tr("画像ファイル (*.png *.jpg);;すべてのファイル (*)")
          );
      
          if (!filePath.isEmpty()) {
              QMessageBox::information(
                  nullptr,
                  QObject::tr("ファイルが選択されました"),
                  QObject::tr("選択されたファイル: ") + filePath
              );
          } else {
              QMessageBox::information(
                  nullptr,
                  QObject::tr("選択なし"),
                  QObject::tr("ファイルは選択されませんでした。")
              );
          }
      
          return a.exec();
      }
      

QFileDialog オブジェクトをインスタンス化して使用する

静的関数は手軽ですが、より詳細な制御が必要な場合は、QFileDialog オブジェクトを直接作成し、プロパティを設定してから exec() メソッドを呼び出すことができます。これにより、ダイアログの挙動をより細かくカスタマイズできます。

  • 用途
    • QFileDialog::DontUseNativeDialog を使って Qt 独自のダイアログを強制し、カスタムウィジェットを追加したい場合。
    • ダイアログのライフサイクルをより厳密に制御したい場合。
  • 特徴
    • ダイアログの表示モード(単一ファイル、複数ファイル、ディレクトリなど)をsetFileMode()で設定できます。
    • カスタムウィジェットをダイアログに追加したり、より複雑な初期設定を行うことができます(ただし、ネイティブダイアログでは制限があります)。
    • 非モーダルダイアログとして表示することも可能ですが、ファイル選択ダイアログの性質上、モーダル(exec())が一般的です。


#include <QApplication>
#include <QFileDialog>
#include <QMessageBox>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>

// QFileDialog を継承してカスタマイズする例 (ただし、DontUseNativeDialog が必要)
class MyCustomFileDialog : public QFileDialog
{
    Q_OBJECT
public:
    MyCustomFileDialog(QWidget *parent = nullptr) : QFileDialog(parent)
    {
        // Qt独自のダイアログを使用するように強制
        setOption(QFileDialog::DontUseNativeDialog, true);

        setWindowTitle(tr("カスタムファイル選択"));
        setNameFilter(tr("設定ファイル (*.ini);;すべてのファイル (*)"));
        setFileMode(QFileDialog::ExistingFile); // 単一の既存ファイルを選択

        // ダイアログにカスタムウィジェットを追加する例 (Qtダイアログの場合のみ可能)
        // 注意: ネイティブダイアログではこの方法は使えません
        if (!testOption(QFileDialog::DontUseNativeDialog)) {
            qWarning("Custom widgets are not supported with native file dialogs.");
            return;
        }

        // QFileDialogのレイアウトを取得(内部実装に依存するため非推奨ですが、例として)
        // Qt 5.x 以降では、QFileDialogの内部レイアウトに直接アクセスするのは難しい場合があります。
        // 一般的には、QFileDialog::setOption(QFileDialog::DontUseNativeDialog) を使用し、
        // setLayout() や setWidget() を利用して独自のUIを構成します。
        // ここでは簡易的に、カスタムウィジェットを追加する可能性を示すに留めます。
        // QGridLayout *layout = qobject_cast<QGridLayout*>(this->layout());
        // if (layout) {
        //     QLabel *customLabel = new QLabel(tr("カスタム情報:"), this);
        //     QLineEdit *customLineEdit = new QLineEdit(this);
        //     layout->addWidget(customLabel, layout->rowCount(), 0);
        //     layout->addWidget(customLineEdit, layout->rowCount()-1, 1);
        // }
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // QFileDialog オブジェクトをインスタンス化
    QFileDialog dialog(nullptr);
    dialog.setWindowTitle(QObject::tr("ファイルを選択"));
    dialog.setFileMode(QFileDialog::ExistingFile); // 既存の単一ファイルを選択
    dialog.setNameFilter(QObject::tr("ドキュメント (*.doc *.pdf);;すべてのファイル (*)"));
    dialog.setDirectory(QDir::homePath()); // 初期ディレクトリを設定
    dialog.setOption(QFileDialog::DontUseNativeDialog, true); // Qt独自のダイアログを使用

    // ダイアログを表示し、ユーザーの操作を待つ
    if (dialog.exec() == QDialog::Accepted) {
        // ユーザーが「開く」ボタンをクリックした場合
        QList<QUrl> selectedUrls = dialog.selectedUrls(); // QUrl のリストを取得
        if (!selectedUrls.isEmpty()) {
            QString filePath = selectedUrls.first().toLocalFile();
            QMessageBox::information(
                nullptr,
                QObject::tr("ファイル選択完了"),
                QObject::tr("選択されたファイル: ") + filePath
            );
        }
    } else {
        // ユーザーが「キャンセル」ボタンをクリックした場合
        QMessageBox::information(
            nullptr,
            QObject::tr("キャンセル"),
            QObject::tr("ファイル選択がキャンセルされました。")
        );
    }

    return a.exec();
}

#include "main.moc" // Q_OBJECT を使用する場合に必要

インスタンス化のポイント

  • selectedUrls() / selectedFiles(): ダイアログが閉じられた後に、選択されたファイル(またはURL)のリストを取得します。
  • exec(): モーダルダイアログとして表示し、ユーザーが操作を完了するまでブロックします。戻り値は QDialog::Accepted または QDialog::Rejected です。
  • setFileMode(): QFileDialog::ExistingFile, QFileDialog::ExistingFiles, QFileDialog::Directory, QFileDialog::AnyFile など、選択できるファイルの種類を設定します。

完全にカスタムなファイル選択ダイアログを実装する

QFileDialog が提供する機能が不十分な場合(例: 特定のデータベースからファイルを選択する、クラウドストレージと連携するなど、標準的なファイルシステムとは異なるアクセス方法を提供したい場合)、QDialog を継承して独自のファイル選択ダイアログを最初から実装することができます。

  • 考慮事項
    • 開発コストが大幅に増加します。標準の QFileDialog が提供する多くの機能(フィルタリング、ディレクトリ履歴、ネットワークドライブへのアクセスなど)を自分で実装する必要があります。
    • プラットフォームネイティブのルック&フィールやキーボードショートカットなどが利用できなくなります。
  • 用途
    • 非常に特殊なファイル選択ロジックが必要な場合。
    • アプリケーションのUIと完全に一致するファイル選択ダイアログを構築したい場合。
    • ファイルの内容のプレビュー、カスタムメタデータの表示、タグ付けなどの高度な機能を組み込みたい場合。
  • 特徴
    • デザイン、機能、ロジックを完全に自由にカスタマイズできます。
    • QFileSystemModelQTreeViewQListView などの Qt クラスを利用して、ファイルシステムを視覚的に表現できます。
    • ネットワークリソース、クラウドストレージ、アプリケーション独自のファイルシステムなど、あらゆる種類の「ファイル」アクセスをサポートできます。

実装の一般的なアプローチ

  1. QDialog を継承した新しいクラスを作成します。
  2. QVBoxLayoutQHBoxLayout などのレイアウトを使って、ファイルリスト表示用の QTreeView (または QListView)、パス表示用の QLineEdit、フィルタ入力用の QComboBox、開く/保存/キャンセルボタン (QDialogButtonBox) などを配置します。
  3. QFileSystemModel を使用して、ファイルシステム上のディレクトリやファイルのデータを QTreeView に表示します。
  4. ユーザーがファイルを選択し、「開く」ボタンをクリックしたときに、選択されたファイルのパスを返すようにロジックを実装します。