Qt QFileDialog::setFilter() の使い方とプログラミング例【初心者向け】

2025-05-27

具体的には、この関数にフィルタ文字列を渡すことで、ダイアログのファイルリストに表示されるファイルを制限できます。フィルタ文字列は、一つまたは複数のフィルタをセミコロン(;)で区切って指定します。

それぞれのフィルタは、通常、表示される説明と、それに一致するファイル名のパターンで構成されます。説明とパターンは、丸括弧 () で囲んで記述します。パターンには、ワイルドカード文字 *(任意の数の任意の文字に一致)や ?(任意の 1 文字に一致)を使用できます。

例えば、次のようなフィルタ文字列が考えられます。

  • 複数のフィルタ

    "画像ファイル (*.png *.jpg *.jpeg);;テキストファイル (*.txt);;すべてのファイル (*)"
    

    この例では、セミコロンで区切られた 3 つのフィルタが定義されています。

    • 最初のフィルタは画像ファイル(.png, .jpg, .jpeg)を表示します。
    • 2 番目のフィルタはテキストファイル(.txt)を表示します。
    • 3 番目のフィルタは「すべてのファイル」という説明で、すべての種類のファイル(*)を表示します。
  • 単一のフィルタ

    "画像ファイル (*.png *.jpg *.jpeg)"
    

    このフィルタは、「画像ファイル」という説明を表示し、拡張子が .png.jpg、または .jpeg のファイルのみをダイアログに表示します。

QFileDialog のインスタンスを作成した後、setFilter() 関数を呼び出して目的のフィルタを設定します。ユーザーがダイアログを開くと、設定されたフィルタがドロップダウンリストなどに表示され、ユーザーは表示するファイルの種類を切り替えることができます。



フィルタ文字列の構文エラー

  • 正しい例
    dialog.setFilter("画像ファイル (*.png *.jpg);;テキストファイル (*.txt)");
    
  • 解決策
    フィルタ文字列の構文を正しく記述します。各フィルタは "説明 (パターン1 パターン2 ...)" の形式で、複数のフィルタは ";;" で区切ります。ファイル拡張子は空白で区切ります。

  • // 間違った例
    dialog.setFilter("画像ファイル *.png *.jpg");
    dialog.setFilter("画像ファイル (*.png *.jpg)テキストファイル (*.txt)");
    dialog.setFilter("画像ファイル (*.png;*.jpg)"); // セミコロンはファイル拡張子の区切りではない
    
  • エラー
    フィルタ文字列の形式が正しくない場合、フィルタが正しく認識されず、期待通りのファイルが表示されないことがあります。例えば、説明とパターンを囲む括弧が抜けていたり、セミコロンによる区切りが間違っていたりする場合です。

パターンの記述ミス

  • 解決策
    パターンの記述を正確に行います。
    • 大文字・小文字を区別したい場合は、ファイルシステムの特性に注意する必要があります(通常は区別されません)。すべてに一致させたい場合は * を使用します。
    • 特定の 1 文字に一致させたい場合は ? を使用します。
    • 複数の拡張子を指定する場合は、空白で区切ります。

  • dialog.setFilter("JPEG ファイル (*.jpeg)"); // 小文字で記述した場合、大文字の .JPEG ファイルは除外される可能性
    dialog.setFilter("すべての TXT ファイル (?.txt)"); // 1 文字のファイル名 + .txt のファイルのみに一致
    
  • エラー
    ファイル名のパターンでワイルドカード *? の使い方が間違っていると、意図しないファイルがフィルタリングされたり、必要なファイルが除外されたりします。

複数のフィルタの扱い

  • 解決策
    特定のフィルタを初期選択したい場合は、setFilter() の後に dialog.selectFilter("目的のフィルタの説明"); を呼び出します。説明文字列は setFilter() で設定したものと完全に一致している必要があります。
  • エラー
    複数のフィルタを設定した場合、ユーザーがどのフィルタを選択しているかによって表示されるファイルが変わります。プログラム側で特定のフィルタを初期状態で選択したい場合、QFileDialog::selectFilter() を使用する必要がありますが、これを忘れるとデフォルトのフィルタ(通常は最初に設定したフィルタ)が表示されます。

カスタムフィルタの利用

  • 解決策
    より高度なフィルタリングが必要な場合は、QFileDialog のシグナル(例えば filesSelected())を受け取り、選択されたファイルリストをプログラム内で独自にフィルタリングする必要があります。または、QFileSystemModelQSortFilterProxyModel を組み合わせて、より柔軟なフィルタリングと表示を行うことも検討できます。
  • エラー
    より複雑なフィルタリングを行いたい場合、正規表現などを使用したいと考えるかもしれませんが、QFileDialog::setFilter() で直接的な正規表現のサポートはありません。

ファイルシステムの挙動

  • 解決策
    異なるプラットフォームでの挙動を考慮し、必要に応じてプラットフォーム固有の処理を追加することを検討します。例えば、隠しファイルを表示・非表示にするオプションは QFileDialog にも用意されています。
  • エラー
    ファイルシステムによっては、大文字・小文字の区別や隠しファイルの扱いなどが異なる場合があります。QFileDialog は通常、プラットフォームの標準的なファイルダイアログの挙動に準拠しますが、予期せぬフィルタリング結果になることもあります。
  • Qt のドキュメント
    QFileDialog および関連するクラスの公式ドキュメントをよく読み、関数の使い方や注意点を確認します。
  • シンプルなテスト
    まずは簡単なフィルタで動作を確認し、徐々に複雑なフィルタを追加していくことで、問題箇所を特定しやすくなります。
  • デバッグ出力
    qDebug() を使用して、設定したフィルタ文字列や、ダイアログが表示するファイルリストなどを出力し、意図した通りに動作しているか確認します。


例 1: 単一のフィルタを設定して画像ファイルのみを表示する

この例では、ファイルを開くダイアログを表示し、フィルタとして PNG と JPG 形式の画像ファイルのみを表示するように設定します。

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

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

    QFileDialog dialog;
    dialog.setFileMode(QFileDialog::AnyFile); // 任意のファイルを選択可能
    dialog.setViewMode(QFileDialog::Detail); // 詳細表示モード

    // 画像ファイル (.png と .jpg) のみをフィルタリング
    dialog.setNameFilter("画像ファイル (*.png *.jpg)");

    if (dialog.exec()) {
        QStringList selectedFiles = dialog.selectedFiles();
        foreach (const QString &file, selectedFiles) {
            qDebug() << "選択されたファイル:" << file;
        }
    } else {
        qDebug() << "キャンセルされました";
    }

    return a.exec();
}

このコードでは、setNameFilter() 関数を使ってフィルタを設定しています。"画像ファイル (*.png *.jpg)" という文字列は、「画像ファイル」という説明と、.png または .jpg の拡張子を持つファイルに一致するパターンを指定しています。

例 2: 複数のフィルタを設定してファイルの種類を切り替えられるようにする

この例では、画像ファイル(PNG, JPG)とテキストファイル(TXT)、そしてすべてのファイルを表示する 3 つのフィルタを設定します。ユーザーはダイアログ内で表示するファイルの種類をドロップダウンリストから選択できます。

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

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

    QFileDialog dialog;
    dialog.setFileMode(QFileDialog::AnyFile);
    dialog.setViewMode(QFileDialog::Detail);

    // 複数のフィルタをセミコロン (;;) で区切って設定
    dialog.setNameFilter("画像ファイル (*.png *.jpg);;テキストファイル (*.txt);;すべてのファイル (*)");

    if (dialog.exec()) {
        QStringList selectedFiles = dialog.selectedFiles();
        foreach (const QString &file, selectedFiles) {
            qDebug() << "選択されたファイル:" << file;
        }
    } else {
        qDebug() << "キャンセルされました";
    }

    return a.exec();
}

ここでは、setNameFilter() に渡す文字列が ; で区切られた 3 つのフィルタになっています。ユーザーがダイアログを開くと、ファイルの種類を選択できるドロップダウンリストが表示されます。

例 3: 特定のフィルタを初期状態で選択する

複数のフィルタを設定した場合、特定のフィルタをダイアログが開いたときにデフォルトで選択させたいことがあります。これには selectNameFilter() 関数を使用します。

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

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

    QFileDialog dialog;
    dialog.setFileMode(QFileDialog::AnyFile);
    dialog.setViewMode(QFileDialog::Detail);

    dialog.setNameFilter("画像ファイル (*.png *.jpg);;テキストファイル (*.txt);;すべてのファイル (*)");

    // 初期状態で「テキストファイル (*.txt)」フィルタを選択
    dialog.selectNameFilter("テキストファイル (*.txt)");

    if (dialog.exec()) {
        QStringList selectedFiles = dialog.selectedFiles();
        foreach (const QString &file, selectedFiles) {
            qDebug() << "選択されたファイル:" << file;
        }
    } else {
        qDebug() << "キャンセルされました";
    }

    return a.exec();
}


QFileSystemModel と QSortFilterProxyModel の組み合わせ

この方法は、ファイルシステムの情報をモデルとして扱い、プロキシモデルを使ってフィルタリングやソートなどの処理を行うものです。QFileDialog が内部的に使用している仕組みをより直接的に操作できます。

  • 基本的な流れ

    1. QFileSystemModel のインスタンスを作成し、表示するルートディレクトリを設定します。
    2. QSortFilterProxyModel のインスタンスを作成し、ソースモデルとして QFileSystemModel を設定します。
    3. QSortFilterProxyModelsetFilterRegExp()setFilterFixedString() などの関数を使ってフィルタリングのルールを設定します。
    4. QFileDialog の代わりに、QListViewQTreeView などのビューウィジェットを作成し、そのモデルに QSortFilterProxyModel を設定します。
    5. ファイルの選択処理は、ビューウィジェットのシグナル(例えば doubleClicked())を処理することで実現します。
  • 欠点

    • QFileDialog を直接使うよりもコード量が増えます。
    • モデルとビューの概念を理解する必要があります。
    • 正規表現を使ったより複雑なフィルタリングが可能になります。
    • ファイル属性(サイズ、更新日時など)に基づいたフィルタリングも容易です。
    • フィルタリングのロジックを再利用しやすいです。
    • ファイルの表示方法(アイコン、詳細など)をより細かく制御できます。

例 (概念的なコード)

#include <QApplication>
#include <QFileSystemModel>
#include <QSortFilterProxyModel>
#include <QListView>
#include <QDir>
#include <QDebug>
#include <QItemSelectionModel>

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

    QFileSystemModel *fileSystemModel = new QFileSystemModel;
    fileSystemModel->setRootPath(QDir::homePath());

    QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel;
    proxyModel->setSourceModel(fileSystemModel);

    // 正規表現で .txt または .log ファイルをフィルタリング
    QRegExp filter(".*\\.(txt|log)$", Qt::CaseInsensitive, QRegExp::RegExp);
    proxyModel->setFilterRegExp(filter);

    QListView *listView = new QListView;
    listView->setModel(proxyModel);
    listView->setRootIndex(proxyModel->mapFromSource(fileSystemModel->index(QDir::homePath())));

    QItemSelectionModel *selectionModel = listView->selectionModel();
    QObject::connect(selectionModel, &QItemSelectionModel::selectionChanged,
                     [&](const QItemSelection &selected, const QItemSelection &deselected){
        if (!selected.isEmpty()) {
            QModelIndex proxyIndex = selected.indexes().first();
            QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
            QString filePath = fileSystemModel->filePath(sourceIndex);
            qDebug() << "選択されたファイル:" << filePath;
        }
    });

    listView->show();

    return a.exec();
}

独自のダイアログとフィルタリングロジックの実装

より自由な UI やフィルタリングが必要な場合は、QFileDialog を使わずに、独自のダイアログを作成し、ファイルリストの表示とフィルタリングのロジックを自分で実装する方法があります。

  • 基本的な流れ

    1. QDialog を継承したカスタムダイアログクラスを作成します。
    2. ダイアログ内にファイルリストを表示するためのウィジェット (QListWidget, QTableView など)を配置します。
    3. フィルタリング条件を入力するためのウィジェット (QLineEdit, QComboBox など)を配置します。
    4. ファイルシステムを走査し、条件に合致するファイルリストを生成するロジックを実装します (QDir, QFileInfo などを使用)。
    5. フィルタリング条件が変更されたときにファイルリストを更新する処理を実装します。
    6. ファイル選択の結果を親ウィンドウに通知する仕組みを実装します(シグナルとスロットなど)。
  • 欠点

    • 開発に必要な工数が大幅に増えます。
    • ファイルシステムの操作や表示に関する多くの処理を自分で実装する必要があります。
    • プラットフォームごとのファイルダイアログの標準的な挙動を再現する必要がある場合があります。
  • 利点

    • UI を完全にカスタマイズできます。
    • 独自のフィルタリングアルゴリズムを実装できます。
    • 特定のアプリケーションの要件に完全に合致したファイル選択ダイアログを作成できます。

QFileDialog のシグナルと組み合わせた追加のフィルタリング

QFileDialog を使いつつ、setFilter() だけでは実現できないより細かいフィルタリングを行いたい場合は、QFileDialog のシグナル(例えば filesSelected())を受け取り、選択されたファイルリストをプログラム内でさらにフィルタリングする方法があります。

  • 基本的な流れ

    1. QFileDialog のインスタンスを作成し、必要に応じて setFilter() で基本的なフィルタを設定します。
    2. filesSelected() シグナルをカスタムのスロットに接続します。
    3. スロット内で、filesSelected() シグナルから渡される選択されたファイルリストに対して、追加のフィルタリングロジックを適用します。
    4. 最終的に必要なファイルのみを処理します。
  • 欠点

    • ユーザーが一度ファイルを選択した後で、プログラム側でさらにフィルタリングを行うため、ユーザーに余計な操作を強いる可能性があります。
  • 利点

    • QFileDialog の基本的な機能(標準的な UI、プラットフォームごとの挙動など)を再利用できます。
    • setFilter() による基本的なフィルタリングに加えて、より複雑な条件で選択結果を絞り込むことができます。