Qtでディレクトリ選択: QUrl QFileDialog::getExistingDirectoryUrl()の全て

2025-05-27

QUrl QFileDialog::getExistingDirectoryUrl() とは

QUrl QFileDialog::getExistingDirectoryUrl() は、QtのQFileDialogクラスが提供する静的関数の一つです。この関数は、ユーザーにディレクトリ(フォルダ)を選択させるためのダイアログを表示し、選択されたディレクトリのURLをQUrlオブジェクトとして返します。

主な特徴と用途

  1. ディレクトリ選択ダイアログの表示
    この関数を呼び出すと、OSのネイティブなディレクトリ選択ダイアログ(Windowsであればエクスプローラ、macOSであればFinderのようなダイアログ)が表示されます。ユーザーはこのダイアログを通じて、既存のディレクトリをGUIで簡単に参照・選択できます。

  2. QUrlの返却
    選択されたディレクトリのパスをQStringではなく、QUrlオブジェクトとして返します。QUrlは、ファイルパスだけでなく、FTPやHTTPなどのさまざまなプロトコルを含むURI(Uniform Resource Identifier)を扱うことができるため、ローカルファイルシステム以外のリモートの場所も扱う可能性を秘めています。

  3. 静的関数
    QFileDialogクラスのインスタンスを作成することなく、QFileDialog::getExistingDirectoryUrl(...) のように直接呼び出して使用できます。これは、Qtが提供する便利なユーティリティ関数の一つです。

  4. 引数
    この関数は、いくつかのオーバーロード(引数の異なるバージョン)がありますが、一般的なものは以下のようになります。

    QUrl QFileDialog::getExistingDirectoryUrl(
        QWidget *parent = nullptr,         // 親ウィジェット
        const QString &caption = QString(), // ダイアログのタイトル
        const QUrl &dir = QUrl(),           // 初期表示ディレクトリのURL
        QFileDialog::Options options = ShowDirsOnly, // ダイアログのオプション
        const QStringList &supportedSchemes = QStringList() // サポートするURLスキーム
    );
    
    • parent: ダイアログの親となるウィジェットを指定します。指定すると、ダイアログが親ウィジェットの上に表示され、親ウィジェットが非アクティブになります。
    • caption: ダイアログのウィンドウタイトルを設定します。
    • dir: ダイアログが開いたときに最初に表示されるディレクトリをQUrlで指定します。例えば、QUrl("file:///home/user/documents") のように指定できます。
    • options: ダイアログの動作を制御するオプションを指定します。
      • QFileDialog::ShowDirsOnly: これがデフォルトのオプションで、ディレクトリのみを表示します。
      • 他のオプション(例: QFileDialog::DontResolveSymlinks など)も指定できます。複数のオプションは|で結合します。
    • supportedSchemes: ダイアログで許可するURLスキームのリストを指定します。例えば、QStringList({"file", "ftp"}) のように設定すると、ファイルシステムとFTPプロトコルでのディレクトリ選択が可能になります。空のリストは、特に制限がないことを意味します("file"スキームは常に暗黙的にサポートされます)。
  5. 戻り値
    ユーザーがディレクトリを選択して「開く」または「選択」ボタンをクリックした場合、選択されたディレクトリのQUrlを返します。ユーザーが「キャンセル」ボタンをクリックした場合、無効な(nullの)QUrlが返されます。これを確認するには、url.isValid()url.isEmpty() などのメソッドを使用します。

getExistingDirectoryUrl() を使うメリット

  • プラットフォームネイティブな見た目
    多くのOSで、そのOSの標準的なファイルダイアログが使用されるため、ユーザーにとって馴染みのあるインターフェースを提供できます。
  • 利便性
    静的関数なので、手軽にディレクトリ選択ダイアログを表示できます。
  • URLベースの操作
    ディレクトリの場所をQUrlとして扱うことで、ローカルファイルシステムだけでなく、将来的にリモートの場所(ネットワークドライブ、FTPサーバーなど)も統一的に扱える可能性が広がります。
#include <QApplication>
#include <QFileDialog>
#include <QUrl>
#include <QDebug>

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

    // ディレクトリ選択ダイアログを表示
    // 親ウィジェットはnullptr(指定なし)、タイトルは"Select Directory"
    // 初期ディレクトリは指定なし(通常はカレントディレクトリや最後に開いたディレクトリ)
    // オプションはデフォルトのShowDirsOnly
    QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(
        nullptr,
        QObject::tr("Select Directory"),
        QUrl(), // 初期ディレクトリは指定しない
        QFileDialog::ShowDirsOnly
    );

    // ユーザーがディレクトリを選択したかを確認
    if (selectedDirUrl.isValid() && !selectedDirUrl.isEmpty()) {
        qDebug() << "Selected Directory URL:" << selectedDirUrl.toString();
        // 例えば、ファイルパスが必要な場合は、toLocalFile() を使用
        qDebug() << "Selected Directory Path:" << selectedDirUrl.toLocalFile();
    } else {
        qDebug() << "Directory selection cancelled.";
    }

    return 0;
}

このコードを実行すると、「Select Directory」というタイトルのディレクトリ選択ダイアログが表示され、ユーザーがディレクトリを選択すると、そのディレクトリのURLとローカルファイルパスがデバッグ出力されます。キャンセルした場合は、キャンセルされた旨が表示されます。



ユーザーがキャンセルした場合の処理不足

エラー/問題
ユーザーがディレクトリ選択ダイアログで「キャンセル」ボタンをクリックしたのに、その戻り値を適切に処理せず、無効な QUrl を使用しようとしてしまう。これにより、後続のファイル操作が失敗したり、予期せぬ動作を引き起こしたりします。


QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(this, tr("Select Directory"));
// ここで selectedDirUrl が有効かどうかのチェックをしない
QFile file(selectedDirUrl.toLocalFile() + "/test.txt"); // 無効なパスでファイルを開こうとする

トラブルシューティング
getExistingDirectoryUrl() が返す QUrl が有効かどうかを常にチェックしてください。QUrl::isValid()QUrl::isEmpty() メソッドを使用します。

QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(this, tr("Select Directory"));
if (selectedDirUrl.isValid() && !selectedDirUrl.isEmpty()) {
    // ユーザーがディレクトリを選択した
    QString localPath = selectedDirUrl.toLocalFile();
    // ここで localPath を使ってディレクトリ操作を行う
    qDebug() << "選択されたディレクトリ:" << localPath;
} else {
    // ユーザーがキャンセルした
    qDebug() << "ディレクトリ選択がキャンセルされました。";
}

isValid() はURLの形式が有効であるか、isEmpty() はURLが空であるかをチェックします。ユーザーがキャンセルした場合、通常は isValid()false を返し、isEmpty()true を返します。

QUrl::toLocalFile() の失敗(非ローカルファイルパスの場合)

エラー/問題
QUrl はURI (Uniform Resource Identifier) を表現するため、file:/// スキーム以外のプロトコル (例: ftp://, http://) を持つURLも格納できます。しかし、toLocalFile() メソッドは、ローカルファイルシステムのパスに変換できないURLに対しては空の文字列を返します。この場合、その空の文字列を使ってファイル操作を行うと失敗します。


もし、getExistingDirectoryUrl()supportedSchemes オプションで ftp など他のスキームを許可していて、ユーザーがFTPサーバー上のディレクトリを選択した場合:

// 例えば、もしFTPサーバーのディレクトリが選択された場合
QUrl ftpUrl("ftp://user:[email protected]/some/directory");
QString localPath = ftpUrl.toLocalFile(); // これは空の文字列になるか、予期せぬパスになる
QFile file(localPath + "/file.txt"); // 失敗する

トラブルシューティング
toLocalFile() を呼び出す前に、QUrl::isLocalFile() を使用して、その QUrl がローカルファイルを表しているかを確認します。

QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(this, tr("Select Directory"));
if (selectedDirUrl.isValid() && !selectedDirUrl.isEmpty()) {
    if (selectedDirUrl.isLocalFile()) {
        QString localPath = selectedDirUrl.toLocalFile();
        qDebug() << "選択されたローカルディレクトリ:" << localPath;
        // ここでローカルファイル操作を行う
    } else {
        qDebug() << "選択されたのはローカルファイルではありません。URL:" << selectedDirUrl.toString();
        // ローカルファイルではない場合の処理 (例: ネットワーク通信でアクセスするなど)
    }
} else {
    qDebug() << "ディレクトリ選択がキャンセルされました。";
}

通常、QFileDialog::getExistingDirectoryUrl() を特に設定せずに使用した場合、返されるのは file:// スキームを持つローカルファイルのURLです。しかし、supportedSchemes を変更したり、後でURLを操作したりする場合には注意が必要です。

親ウィジェット (parent) の指定不足または無効な親ウィジェット

エラー/問題
QFileDialog::getExistingDirectoryUrl() は静的関数ですが、第一引数に親ウィジェット (QWidget *parent) を取ります。これを nullptr に指定しない場合、ダイアログはその親ウィジェットにモーダル(親がブロックされる)で表示されます。もし親ウィジェットが有効でない(例えば、すでに破棄されている)場合、クラッシュや予期せぬ動作が発生する可能性があります。

トラブルシューティング

  • nullptr の使用
    親を指定する必要がない、または指定しない方が良い場合は、明示的に nullptr を渡します。この場合、ダイアログはデスクトップの中央などに表示されることが多いです。
  • 適切な親ウィジェットの指定
    this ポインタ(現在のウィジェットを親にする場合)や、メインウィンドウのポインタなどを適切に渡します。
  • 親ウィジェットの生存期間
    親ウィジェットがダイアログの表示中に有効であることを確認してください。

ネイティブダイアログに関する問題 (QFileDialog::DontUseNativeDialog)

エラー/問題
稀に、特定のOS環境やシステムにインストールされているサードパーティ製ソフトウェア(例: ファイル管理ツール、セキュリティソフト)が原因で、Qtのネイティブファイルダイアログが正しく動作しないことがあります。ダイアログが表示されない、選択後に閉じない、クラッシュするといった現象が発生することがあります。

トラブルシューティング
このような問題が発生した場合、Qtが提供する非ネイティブ(Qt標準)のダイアログを使用するように強制することで解決できることがあります。

QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(
    this,
    tr("Select Directory"),
    QUrl(),
    QFileDialog::ShowDirsOnly | QFileDialog::DontUseNativeDialog // ここを追加
);

QFileDialog::DontUseNativeDialog オプションを追加することで、Qt独自のダイアログが表示されるようになります。ただし、ネイティブダイアログの方がOSに馴染んだ見た目や操作感を提供するため、このオプションは最終手段として検討するのが一般的です。

エラー/問題
QUrl::toLocalFile() は、UNIXスタイルのスラッシュ (/) を使用してパスを返します。Windows環境では、ファイルシステム操作にバックラッシュ (\) を使用することが一般的です。QtのQFileQDirクラスはどちらの形式でも扱えるため通常は問題ありませんが、C++標準ライブラリのファイルストリーム (std::ifstream, std::ofstream) や、外部ライブラリにパスを渡す場合など、ネイティブなパス区切り文字が求められる場面で問題が発生することがあります。

トラブルシューティング
もし、toLocalFile() から得たパスをQt以外のファイル操作関数に渡す必要があり、かつパス区切り文字が原因で問題が発生する場合は、QDir::toNativeSeparators() を使用してプラットフォーム固有の区切り文字に変換します。

QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(this, tr("Select Directory"));
if (selectedDirUrl.isValid() && !selectedDirUrl.isEmpty() && selectedDirUrl.isLocalFile()) {
    QString localPath = selectedDirUrl.toLocalFile();
    QString nativePath = QDir::toNativeSeparators(localPath); // プラットフォーム固有の区切り文字に変換
    qDebug() << "ネイティブパス:" << nativePath;

    // 例: C++標準ライブラリでファイルを開く場合
    // std::ifstream ifs(nativePath.toStdString()); // 注意: toStdString() はUTF-8エンコーディングになるため、Windowsでは問題になる場合がある
    // QtではQFileを使うのが推奨
}

注意
QStringstd::string に変換してC++標準ライブラリのファイル操作関数に渡す場合、特にWindowsでは文字エンコーディングの問題(通常はUTF-8とシステムロケールの違い)が発生することがあります。Qtアプリケーションでは、可能な限り QFileQDir といったQtのファイル操作クラスを使用することが強く推奨されます。これらはUnicodeパスを適切に処理します。



QUrl QFileDialog::getExistingDirectoryUrl() の基本的な使い方と応用例

この関数は、引数を省略せずに指定することで、より細かくダイアログの挙動を制御できます。

#include <QApplication> // QApplication を使うために必要
#include <QWidget>      // QWidget を使うために必要(MainWindow の親など)
#include <QPushButton>  // ボタンを追加するために必要
#include <QVBoxLayout>  // レイアウトのために必要
#include <QFileDialog>  // QFileDialog を使うために必要
#include <QUrl>         // QUrl を使うために必要
#include <QDebug>       // デバッグ出力のために必要
#include <QDir>         // QDir::homePath() のために必要

// メインウィンドウクラス
class MainWindow : public QWidget
{
    Q_OBJECT // Qt のシグナル/スロット機構を使うために必要

public:
    explicit MainWindow(QWidget *parent = nullptr)
        : QWidget(parent)
    {
        setWindowTitle(tr("Directory Selector Example"));
        resize(400, 200);

        QVBoxLayout *layout = new QVBoxLayout(this);

        // 例1: 最小限の引数での使用
        QPushButton *button1 = new QPushButton(tr("Select Directory (Basic)"), this);
        connect(button1, &QPushButton::clicked, this, &MainWindow::selectDirectoryBasic);
        layout->addWidget(button1);

        // 例2: タイトルと初期ディレクトリを指定
        QPushButton *button2 = new QPushButton(tr("Select Directory (Custom Title & Start Dir)"), this);
        connect(button2, &QPushButton::clicked, this, &MainWindow::selectDirectoryCustom);
        layout->addWidget(button2);

        // 例3: ネイティブダイアログを強制しない
        QPushButton *button3 = new QPushButton(tr("Select Directory (Qt Dialog)"), this);
        connect(button3, &QPushButton::clicked, this, &MainWindow::selectDirectoryQtDialog);
        layout->addWidget(button3);

        // 例4: 複数のURLスキームをサポート
        QPushButton *button4 = new QPushButton(tr("Select Directory (Supported Schemes)"), this);
        connect(button4, &QPushButton::clicked, this, &MainWindow::selectDirectoryWithSchemes);
        layout->addWidget(button4);
    }

private slots:
    // 例1: 最小限の引数での使用
    void selectDirectoryBasic()
    {
        qDebug() << "--- Basic Directory Selection ---";
        // 親ウィジェット: this (この MainWindow を親にする)
        // 他の引数はすべてデフォルト値(タイトルなし、初期ディレクトリなし、オプションはShowDirsOnly)
        QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(this);

        handleSelectedUrl(selectedDirUrl);
    }

    // 例2: タイトルと初期ディレクトリを指定
    void selectDirectoryCustom()
    {
        qDebug() << "--- Custom Directory Selection ---";
        QString caption = tr("Please Choose a Project Directory"); // ダイアログのタイトル
        // 初期ディレクトリをユーザーのホームディレクトリに設定
        // QUrl::fromLocalFile() でローカルファイルパスを QUrl に変換
        QUrl initialDirUrl = QUrl::fromLocalFile(QDir::homePath());

        QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(
            this,          // 親ウィジェット
            caption,       // ダイアログのタイトル
            initialDirUrl  // 初期表示ディレクトリ
        );

        handleSelectedUrl(selectedDirUrl);
    }

    // 例3: ネイティブダイアログを強制しない (Qt標準のダイアログを使用)
    void selectDirectoryQtDialog()
    {
        qDebug() << "--- Qt-style Directory Selection ---";
        QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(
            this,
            tr("Select Directory (Qt Style)"),
            QUrl(),
            QFileDialog::ShowDirsOnly | QFileDialog::DontUseNativeDialog // DontUseNativeDialog を追加
        );

        handleSelectedUrl(selectedDirUrl);
    }

    // 例4: 複数のURLスキームをサポート (ここではファイルスキームのみ)
    // 実際にはFTPやHTTPをサポートするには別途ネットワーク処理が必要です
    void selectDirectoryWithSchemes()
    {
        qDebug() << "--- Directory Selection with Supported Schemes ---";
        QStringList supportedSchemes;
        supportedSchemes << "file"; // ローカルファイルのみをサポート

        QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(
            this,
            tr("Select Directory (File Schemes Only)"),
            QUrl(),
            QFileDialog::ShowDirsOnly,
            supportedSchemes // サポートするスキームのリスト
        );

        handleSelectedUrl(selectedDirUrl);
    }

    // 選択されたURLを処理する共通関数
    void handleSelectedUrl(const QUrl &url)
    {
        if (url.isValid() && !url.isEmpty()) {
            qDebug() << "選択されたURL:" << url.toString();
            // ローカルファイルパスとして必要であれば toLocalFile() を使う
            if (url.isLocalFile()) {
                qDebug() << "ローカルパス:" << url.toLocalFile();
                // ここで選択されたディレクトリパスを使ってファイル操作などを行う
            } else {
                qDebug() << "ローカルファイルではないURLが選択されました。";
            }
        } else {
            qDebug() << "ディレクトリ選択がキャンセルされました。";
        }
    }
};

#include "main.moc" // moc ファイルをインクルード (CMakeList.txt or .pro で自動生成)

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

    MainWindow window;
    window.show();

    return app.exec();
}
  1. インクルード (#include):

    • QApplication, QWidget, QPushButton, QVBoxLayout: GUIアプリケーションの基本要素です。
    • QFileDialog: ディレクトリ選択ダイアログを提供します。
    • QUrl: URL(Uniform Resource Locator)を扱うためのクラスです。getExistingDirectoryUrl() の戻り値として使用します。
    • QDebug: デバッグ出力をコンソールに行うために使用します。
    • QDir: QDir::homePath() のように、特定のシステムディレクトリパスを取得するために使用します。
  2. MainWindow クラス:

    • Q_OBJECT: Qtのメタオブジェクトシステム(シグナルとスロット)を有効にするために必要です。
    • コンストラクタ (MainWindow::MainWindow):
      • ウィンドウのタイトルとサイズを設定します。
      • QVBoxLayout を使用して、ボタンを縦に並べます。
      • 各ボタンを作成し、clicked() シグナルを対応するスロット (selectDirectoryBasic, selectDirectoryCustom など) に接続しています。
  3. スロット関数:

    • selectDirectoryBasic(): 最もシンプルな使い方です。

      QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(this);
      

      this は現在の MainWindow インスタンスを親ウィジェットとして渡しています。これにより、ダイアログがこのウィンドウに紐付けられ、このウィンドウが非アクティブになります。他の引数は省略されているため、デフォルト値が使われます。ダイアログのタイトルはOSのデフォルト(例: "フォルダの参照")、初期ディレクトリは通常、最後に開いた場所か、アプリケーションの起動ディレクトリになります。

    • selectDirectoryCustom(): ダイアログのタイトルと初期ディレクトリを指定する例です。

      QString caption = tr("Please Choose a Project Directory");
      QUrl initialDirUrl = QUrl::fromLocalFile(QDir::homePath()); // ホームディレクトリを初期値に
      
      QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(
          this,
          caption,
          initialDirUrl
      );
      
      • caption: ダイアログのタイトルバーに表示される文字列を設定します。tr() は国際化対応のための関数です。
      • initialDirUrl: ダイアログが開いたときに最初に表示されるディレクトリを指定します。QDir::homePath() でユーザーのホームディレクトリのパス(例: /home/userC:\Users\user)を取得し、それを QUrl::fromLocalFile()QUrl オブジェクトに変換しています。
    • selectDirectoryQtDialog(): ネイティブなダイアログではなく、Qtが提供するウィジェットベースのダイアログを強制する例です。

      QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(
          this,
          tr("Select Directory (Qt Style)"),
          QUrl(),
          QFileDialog::ShowDirsOnly | QFileDialog::DontUseNativeDialog
      );
      
      • QFileDialog::DontUseNativeDialog: このオプションを指定すると、QtはOS標準のファイルダイアログではなく、Qt自身で実装されたファイルダイアログを使用します。これは、特定の環境でネイティブダイアログに問題がある場合や、アプリケーション全体で統一されたUIを提供したい場合に役立ちます。QFileDialog::ShowDirsOnly と論理OR (|) で結合して複数のオプションを有効にしています。
    • selectDirectoryWithSchemes(): サポートするURLスキームを制限する例です。

      QStringList supportedSchemes;
      supportedSchemes << "file"; // ローカルファイルのみを許可
      
      QUrl selectedDirUrl = QFileDialog::getExistingDirectoryUrl(
          this,
          tr("Select Directory (File Schemes Only)"),
          QUrl(),
          QFileDialog::ShowDirsOnly,
          supportedSchemes
      );
      
      • supportedSchemes: QStringList で、ダイアログで許可されるURLスキームのリストを指定します。デフォルトでは、file スキームが常にサポートされます。ここで他のスキーム(例: ftp)を追加すると、FTPサーバー上のディレクトリも選択できるようになる可能性がありますが、それにはQtのネットワークモジュール (QtNetwork) を使用した追加の処理が必要です。この例では file スキームのみに明示的に制限しています。
    • handleSelectedUrl(const QUrl &url): すべての選択スロットで共通して呼び出されるヘルパー関数です。

      • url.isValid()!url.isEmpty() で、ユーザーが実際にディレクトリを選択したか(キャンセルしなかったか)をチェックします。これは、以前に説明した一般的なエラーを避けるために非常に重要です。
      • url.toString() で、選択されたディレクトリのURL文字列(例: file:///path/to/directory)を出力します。
      • url.isLocalFile() で、選択されたURLがローカルファイルシステム上のパスであるかを確認します。
      • url.toLocalFile() で、file:// スキームのURLをローカルファイルシステムパス(例: /path/to/directoryC:/path/to/directory)に変換して出力します。ローカルファイルでない場合は空文字列が返されます。
  4. main 関数:

    • QApplication インスタンスを作成し、Qtアプリケーションを初期化します。
    • MainWindow のインスタンスを作成し、表示します。
    • app.exec() でイベントループを開始し、アプリケーションを実行します。


QString QFileDialog::getExistingDirectory() の使用

getExistingDirectoryUrl() と同様に、QFileDialog クラスには QString を返す静的関数 getExistingDirectory() も存在します。これは、URL形式ではなく、純粋なローカルファイルパス(QString)が必要な場合に便利です。

特徴

  • リモートの場所(FTPなど)を扱う能力はありません。ローカルファイルシステムのディレクトリ選択に特化しています。
  • 戻り値が QString なので、QUrl::toLocalFile() を呼び出す手間が省けます。


#include <QApplication>
#include <QFileDialog>
#include <QString>
#include <QDebug>

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

    // QString を返すディレクトリ選択ダイアログ
    QString selectedDirPath = QFileDialog::getExistingDirectory(
        nullptr, // 親ウィジェット
        QObject::tr("Select Local Directory"), // ダイアログのタイトル
        QDir::homePath(), // 初期ディレクトリ(例: ユーザーのホームディレクトリ)
        QFileDialog::ShowDirsOnly // オプション: ディレクトリのみ表示
    );

    if (!selectedDirPath.isEmpty()) {
        qDebug() << "Selected Local Directory Path:" << selectedDirPath;
        // ここで QString のパスを使ってファイル操作を行う
    } else {
        qDebug() << "Directory selection cancelled.";
    }

    return 0;
}

使い分け

  • getExistingDirectory(): 純粋にローカルファイルシステムのパスのみを扱い、シンプルな QString パスで十分な場合に適しています。
  • getExistingDirectoryUrl(): リモートアクセス(FTP、HTTPなど)の可能性を考慮に入れたり、URI形式でパスを統一的に扱いたい場合に適しています。

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

静的関数ではなく、QFileDialog オブジェクトを自分で作成し、プロパティを設定して exec() メソッドで表示する方法です。これにより、より詳細なカスタマイズが可能になります。

特徴

  • directoryUrl() メソッドで選択されたディレクトリのURLを取得できます。
  • setViewMode() で表示モード(リスト表示か詳細表示か)を設定できます。
  • setNameFilter()setFilter() でファイル名フィルタを設定できますが、ディレクトリ選択では通常あまり使いません。
  • setFileMode(QFileDialog::Directory) を使用して、ディレクトリのみを選択可能に設定します。
  • ダイアログのライフサイクルをより細かく制御できます。


#include <QApplication>
#include <QFileDialog>
#include <QUrl>
#include <QDebug>
#include <QDir>

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

    QFileDialog dialog; // QFileDialog オブジェクトをインスタンス化

    dialog.setFileMode(QFileDialog::Directory); // ディレクトリのみを選択可能にする
    dialog.setOption(QFileDialog::ShowDirsOnly, true); // ディレクトリのみ表示(念のため)
    dialog.setWindowTitle(QObject::tr("Choose Folder (Custom Dialog)"));
    dialog.setDirectoryUrl(QUrl::fromLocalFile(QDir::homePath())); // 初期ディレクトリ

    // オプションで Qt 標準のダイアログを強制することも可能
    // dialog.setOption(QFileDialog::DontUseNativeDialog, true);

    if (dialog.exec()) { // ダイアログを表示し、ユーザーがOKをクリックしたら true
        // 選択されたディレクトリのURLを取得
        // selectFiles() はファイル用、selectedUrls() はURL用
        QList<QUrl> selectedUrls = dialog.selectedUrls();
        if (!selectedUrls.isEmpty()) {
            QUrl selectedDirUrl = selectedUrls.first(); // ディレクトリ選択なので通常は1つ
            qDebug() << "Selected Directory URL (Custom Dialog):" << selectedDirUrl.toString();
            if (selectedDirUrl.isLocalFile()) {
                qDebug() << "Selected Directory Path (Custom Dialog):" << selectedDirUrl.toLocalFile();
            }
        }
    } else {
        qDebug() << "Directory selection cancelled (Custom Dialog).";
    }

    return app.exec();
}

使い分け

  • 静的関数では提供されていない、より高度な機能(例: 複数のディレクトリ選択 - ただし、ネイティブダイアログでは通常サポートされていません)を実装したい場合に利用します。
  • より詳細なカスタマイズ(例: 特定の列を表示/非表示にする、カスタムウィジェットを追加するなど)が必要な場合に検討します。

QFileDialog が提供する機能だけでは要件を満たせない場合、QTreeViewQFileSystemModel を組み合わせて、独自のディレクトリ選択ダイアログをゼロから構築する方法があります。

特徴

  • QTreeView: 階層的なデータをツリービューとして表示するためのウィジェットです。
  • QFileSystemModel: ファイルシステムのデータをモデルとして提供し、QTreeView などで表示するのに非常に適しています。
  • 複雑さの増加
    ゼロから構築するため、より多くのコードと設計が必要です。
  • 最大の柔軟性
    UIの見た目、動作、機能(例: 複数のディレクトリ選択、特定ファイルタイプの表示、ディレクトリの作成/削除など)を完全に制御できます。

例(概念的なコード、完全な動作には追加コードが必要)

#include <QApplication>
#include <QDialog>
#include <QVBoxLayout>
#include <QTreeView>
#include <QPushButton>
#include <QFileSystemModel>
#include <QDebug>
#include <QDir>
#include <QStandardPaths> // ドキュメントフォルダなどの標準パスを取得

class CustomDirectoryDialog : public QDialog
{
    Q_OBJECT

public:
    explicit CustomDirectoryDialog(QWidget *parent = nullptr)
        : QDialog(parent)
    {
        setWindowTitle(tr("Select Directory (Custom)"));
        QVBoxLayout *layout = new QVBoxLayout(this);

        model = new QFileSystemModel(this);
        model->setRootPath(QDir::rootPath()); // ルートパスを設定
        // ディレクトリのみを表示し、隠しファイルとドットファイルは非表示
        model->setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden);

        treeView = new QTreeView(this);
        treeView->setModel(model);
        // ディレクトリツリーの最初の展開(例:ユーザーのドキュメントフォルダ)
        QModelIndex rootIndex = model->index(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
        treeView->setRootIndex(rootIndex);

        // ファイル名、サイズ、タイプなどの列を非表示にしてディレクトリパスのみに集中させる
        for (int i = 1; i < model->columnCount(); ++i) {
            treeView->hideColumn(i);
        }
        treeView->setHeaderHidden(true); // ヘッダーも非表示に

        // 選択モードを単一選択に設定(複数選択も可能)
        treeView->setSelectionMode(QAbstractItemView::SingleSelection);
        treeView->setSelectionBehavior(QAbstractItemView::SelectRows);

        // 初期選択
        treeView->setCurrentIndex(rootIndex);

        layout->addWidget(treeView);

        QPushButton *okButton = new QPushButton(tr("OK"), this);
        QPushButton *cancelButton = new QPushButton(tr("Cancel"), this);

        QHBoxLayout *buttonLayout = new QHBoxLayout();
        buttonLayout->addStretch();
        buttonLayout->addWidget(okButton);
        buttonLayout->addWidget(cancelButton);
        layout->addLayout(buttonLayout);

        connect(okButton, &QPushButton::clicked, this, &CustomDirectoryDialog::accept);
        connect(cancelButton, &QPushButton::clicked, this, &CustomDirectoryDialog::reject);
        connect(treeView, &QTreeView::clicked, this, &CustomDirectoryDialog::onTreeViewClicked); // クリック時にパスを更新
    }

    QUrl getSelectedDirectoryUrl() const
    {
        return selectedDirectoryUrl;
    }

private slots:
    void onTreeViewClicked(const QModelIndex &index)
    {
        if (model->isDir(index)) { // 選択されたのがディレクトリであることを確認
            selectedDirectoryUrl = QUrl::fromLocalFile(model->filePath(index));
            qDebug() << "Currently selected (custom):" << selectedDirectoryUrl.toLocalFile();
        }
    }

private:
    QFileSystemModel *model;
    QTreeView *treeView;
    QUrl selectedDirectoryUrl;
};

#include "main.moc" // moc ファイルをインクルード

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

    CustomDirectoryDialog dialog;
    if (dialog.exec() == QDialog::Accepted) {
        QUrl selectedUrl = dialog.getSelectedDirectoryUrl();
        if (selectedUrl.isValid() && !selectedUrl.isEmpty()) {
            qDebug() << "Final Selected Directory (Custom):" << selectedUrl.toLocalFile();
        } else {
            qDebug() << "Custom directory selection cancelled or no valid directory selected.";
        }
    } else {
        qDebug() << "Custom directory selection cancelled.";
    }

    return app.exec();
}
  • ユーザー体験を完全にカスタマイズしたい場合に、最も強力な選択肢となりますが、その分開発コストも高くなります。
  • 例えば、特定のネットワークリソースとローカルファイルを統合して表示したい、ディレクトリのアクセス権限に基づいて表示を制御したい、などの高度な要件がある場合。
  • QFileDialog が提供する機能だけでは実現できない、非常に特殊なUIや動作が必要な場合。
  • カスタムダイアログの構築: 既存の QFileDialog では対応できないような、非常に高度なカスタマイズや特殊な要件がある場合にのみ検討します。
  • QFileDialog オブジェクトのインスタンス化: 静的関数では設定できない詳細なオプション(例: setFileMode()setOptions() でのきめ細かい制御)が必要な場合に使います。
  • QString QFileDialog::getExistingDirectory(): 純粋にローカルパスが必要で、シンプルなAPIを好む場合に適しています。
  • QUrl QFileDialog::getExistingDirectoryUrl(): 大抵のケースで十分で、最も手軽で標準的な方法です。リモートURLの可能性も考慮します。