QFileDialog::history()だけじゃない!Qtで「最近使ったファイル」を管理する代替手法
QFileDialogとは?
まず、QFileDialog
は、ユーザーがファイルシステムを操作してファイルやディレクトリを選択するための標準的なダイアログを提供するQtウィジェットです。ファイルを開く、保存する、ディレクトリを選択するといった一般的な操作で利用されます。
QFileDialog::history() の機能
QFileDialog::history()
は、このファイルダイアログが記憶しているディレクトリの閲覧履歴をQStringList
(文字列のリスト)として返します。これは、ユーザーが以前にアクセスしたフォルダのパスをリストアップしたものです。
例えば、ユーザーがファイルダイアログを使っていくつかの異なるフォルダを開いた場合、history()
メソッドを呼び出すことで、それらのフォルダのパスがリストとして取得できます。
使用目的
この履歴は、主に以下のような目的で利用されます。
- デバッグや分析
ユーザーがどのようなパスを辿っているかを把握するために、履歴情報を取得してデバッグや分析に利用することも考えられます。 - 状態の保存と復元
アプリケーションの終了時にQFileDialog
の履歴を保存し、次回起動時にその履歴を復元することで、ユーザーが中断した作業をスムーズに再開できるようにします。setHistory()
関数を使って、この履歴をファイルダイアログに設定することができます。 - ユーザーエクスペリエンスの向上
ユーザーが頻繁にアクセスするディレクトリをダイアログの「最近の場所」や「履歴」セクションに表示することで、再度同じ場所へアクセスする手間を省き、利便性を高めます。
- 履歴はフォルダのパスのみを格納し、個々のファイルのパスは格納しません。
QFileDialog
のインスタンスごとに履歴が管理されるため、複数のファイルダイアログを作成した場合、それぞれのインスタンスが独自の履歴を持つことになります。QFileDialog
は、OSネイティブのファイルダイアログを使用する場合と、Qtが提供するウィジェットベースのダイアログを使用する場合があります。history()
がネイティブダイアログの履歴と完全に一致するかは、OSの実装やQtのバージョンによって異なる可能性があります。
履歴が期待通りに更新されない・表示されない
考えられる原因
- 無効なパスの混入
履歴リストに存在しない、またはアクセスできないパスが含まれている場合、ダイアログによってはそれらのパスが適切に表示されないことがあります。 - アプリケーション終了時の履歴の保存忘れ
アプリケーションを終了する際に、現在のQFileDialog
の履歴を取得して保存(例えば設定ファイルに書き込む)処理を行っていない場合、次回起動時に履歴が失われます。 - setHistory() との混同
history()
は履歴を取得する関数であり、履歴を設定する関数ではありません。履歴を設定するにはsetHistory()
を使用します。 - 非モーダルダイアログの問題
QFileDialog
を非モーダルで表示した場合(exec()
ではなくshow()
を使用)、ダイアログが閉じられる前に履歴を取得しようとすると、期待する履歴が得られない場合があります。 - OSネイティブダイアログの使用
QFileDialog
は、デフォルトでOSネイティブのファイルダイアログを使用しようとします。ネイティブダイアログの場合、Qtのhistory()
メソッドは必ずしもOSの履歴と同期しない、あるいはQtが管理する履歴がネイティブダイアログに反映されないことがあります。OSネイティブダイアログは、OS自身が履歴を管理するため、QtのsetHistory()
で設定した内容が反映されにくいです。
トラブルシューティング
- 履歴リストの検証
setHistory()
に渡す前に、履歴リスト内のパスが有効であるか(例えばQDir::exists()
で確認する)をチェックすることを検討します。ただし、これは必須ではありません。 - 履歴の保存と復元ロジックの確認
アプリケーションの起動時と終了時に、history()
で取得した履歴をsetHistory()
で設定する処理が正しく実装されているか確認します。- 保存例
QStringList currentHistory = myFileDialog->history(); // currentHistory を設定ファイル (QSettings など) に保存 QSettings settings("MyCompany", "MyApp"); settings.setValue("fileDialogHistory", currentHistory);
- 復元例
QSettings settings("MyCompany", "MyApp"); QStringList savedHistory = settings.value("fileDialogHistory").toStringList(); if (!savedHistory.isEmpty()) { myFileDialog->setHistory(savedHistory); }
- 保存例
- ダイアログが閉じられた後に履歴を取得
QFileDialog
がAccepted
またはRejected
シグナルを発した後など、ダイアログがユーザー操作によって閉じられたタイミングでhistory()
を呼び出すようにします。 - Qtのウィジェットベースダイアログの使用を検討
ネイティブダイアログの挙動が問題となる場合、QFileDialog::DontUseNativeDialog
オプションを使用して、Qtが提供するウィジェットベースのダイアログを強制的に使用させることができます。
これにより、QtのQFileDialog dialog(this); dialog.setOption(QFileDialog::DontUseNativeDialog, true); // ... QStringList history = dialog.history();
setHistory()
で設定した内容が確実にダイアログに反映されるようになります。
history() が空のリストを返す
考えられる原因
- OSネイティブダイアログによる影響
上述のように、ネイティブダイアログが使用されている場合、Qtが管理する履歴が蓄積されていない可能性があります。 - 履歴がクリアされた後
何らかの理由でQFileDialog
の内部履歴がクリアされた後かもしれません(通常は明示的にクリアするAPIはありませんが、特定の条件でリセットされる可能性はゼロではありません)。 - ダイアログが一度も表示されていない、または操作されていない
QFileDialog
インスタンスを作成したばかりで、まだユーザーがダイアログを操作してディレクトリを移動していない場合、履歴は空です。
トラブルシューティング
- setHistory() による初期設定の検討
アプリケーション起動時に既知の履歴をsetHistory()
で設定しておけば、最初から空になることを防げます。 - ダイアログの表示と操作を確認
QFileDialog
がユーザーによって開かれ、ディレクトリが選択されたことを確認します。
考えられる原因
QFileDialog::history()
はQStringList
を返すため、この関数自体がメモリリークを引き起こすことはほとんどありません。問題が発生するとすれば、QStringList
を受け取った後の処理で、不要になった文字列が適切に解放されない場合や、大量の履歴を不必要に保持し続けるようなロジックがある場合です。
- 履歴のサイズ制限
無限に履歴が蓄積されないように、QStringList
のサイズを一定数(例:20件など)に制限することを検討します。これにより、メモリ使用量を抑え、UIのパフォーマンスも向上させることができます。 - メモリプロファイラの使用
Qt Creator に含まれるプロファイラなどを使用して、アプリケーションのメモリ使用量を監視します。
基本的な履歴の取得
この例では、ファイルダイアログを表示し、ユーザーがファイルをいくつか開いた後、そのダイアログの履歴を取得してデバッグ出力します。
#include <QApplication>
#include <QFileDialog>
#include <QStringList>
#include <QDebug> // デバッグ出力用
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "ファイルダイアログを開きます。いくつかのディレクトリを移動してみてください。";
// QFileDialogのインスタンスを作成
QFileDialog dialog;
dialog.setWindowTitle("ファイルを開く (履歴取得の例)");
dialog.setFileMode(QFileDialog::ExistingFiles); // 既存ファイルを選択
// ダイアログを表示し、ユーザーが「開く」をクリックするまで待機
if (dialog.exec()) {
qDebug() << "ユーザーがファイルを選択しました。";
// ユーザーがディレクトリを移動した場合、その履歴がここに蓄積されます。
}
// ダイアログが閉じられた後に履歴を取得
QStringList history = dialog.history();
qDebug() << "\nQFileDialogの履歴:";
if (history.isEmpty()) {
qDebug() << "履歴は空です。";
} else {
for (const QString &path : history) {
qDebug() << " - " << path;
}
}
return a.exec();
}
解説
QFileDialog dialog;
でファイルダイアログのインスタンスを作成します。dialog.exec()
を呼び出して、ダイアログをモーダルで表示します。ユーザーがダイアログを操作し、ディレクトリを移動すると、そのパスが内部的に履歴として記録されます。if (dialog.exec())
のブロックを抜けた後(つまりユーザーが「開く」または「キャンセル」をクリックした後)に、QStringList history = dialog.history();
を呼び出して、蓄積された履歴を取得します。- 取得した
QStringList
の内容をqDebug()
で出力しています。
この例では、アプリケーションの設定を保存するための QSettings
クラスを使用して、QFileDialog
の履歴をアプリケーションのセッション間で保存し、次回起動時に復元する方法を示します。
main.cpp
#include <QApplication>
#include <QFileDialog>
#include <QStringList>
#include <QDebug>
#include <QSettings> // 設定保存用
// 履歴を保存・復元するためのキー
const QString HISTORY_KEY = "fileDialogHistory";
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// アプリケーション情報の設定 (QSettingsが適切に動作するために必要)
a.setOrganizationName("MyCompany");
a.setApplicationName("MyFileDialogApp");
qDebug() << "アプリケーションを起動しました。";
// QFileDialogのインスタンスを作成
QFileDialog dialog;
dialog.setWindowTitle("ファイルを開く (履歴保存・復元)");
dialog.setFileMode(QFileDialog::ExistingFiles);
// QSettingsから前回の履歴を読み込む
QSettings settings;
QStringList savedHistory = settings.value(HISTORY_KEY).toStringList();
if (!savedHistory.isEmpty()) {
dialog.setHistory(savedHistory);
qDebug() << "保存された履歴を復元しました:";
for (const QString &path : savedHistory) {
qDebug() << " - " << path;
}
} else {
qDebug() << "保存された履歴はありません。";
}
// 必要に応じて、Qtネイティブダイアログの使用を無効化する
// これにより、Qtが管理する履歴が確実に反映されます。
dialog.setOption(QFileDialog::DontUseNativeDialog, true);
// ダイアログを表示
if (dialog.exec()) {
qDebug() << "ユーザーがファイルを選択しました。";
}
// ダイアログが閉じられた後に現在の履歴を取得
QStringList currentHistory = dialog.history();
// 現在の履歴をQSettingsに保存
settings.setValue(HISTORY_KEY, currentHistory);
qDebug() << "\n現在のQFileDialogの履歴を保存しました:";
if (currentHistory.isEmpty()) {
qDebug() << "履歴は空です。";
} else {
for (const QString &path : currentHistory) {
qDebug() << " - " << path;
}
}
return a.exec();
}
- QSettings の準備
QApplication::setOrganizationName()
とQApplication::setApplicationName()
を設定します。これにより、QSettings
が設定ファイルをどこに保存するかを決定します(Windowsではレジストリ、macOSではplist、LinuxではINIファイルなど)。QSettings settings;
でインスタンスを作成します。
- 履歴の復元
settings.value(HISTORY_KEY).toStringList();
を使用して、前回のセッションで保存された履歴をQStringList
として読み込みます。if (!savedHistory.isEmpty()) { dialog.setHistory(savedHistory); }
で、読み込んだ履歴をQFileDialog
のインスタンスに設定します。これにより、ダイアログを開いたときに、前回の履歴が「最近の場所」などに表示されるようになります。
- QFileDialog::DontUseNativeDialog の使用
dialog.setOption(QFileDialog::DontUseNativeDialog, true);
を追加しています。これは非常に重要です。このオプションを設定しない場合、QtはOSネイティブのファイルダイアログを使用しようとしますが、その場合、setHistory()
で設定した内容がネイティブダイアログに反映されない、あるいはネイティブダイアログ独自の履歴が優先されるといった問題が発生する可能性があります。このオプションを有効にすることで、Qtが提供するウィジェットベースのダイアログが使用され、setHistory()
やhistory()
の挙動がより予測可能になります。
- 履歴の保存
- ダイアログが閉じられた後(
dialog.exec()
が戻り値を返した後)に、QStringList currentHistory = dialog.history();
で現在の履歴を取得します。 settings.setValue(HISTORY_KEY, currentHistory);
を使用して、この履歴をQSettings
に保存します。次回アプリケーションを起動したときに、この履歴が読み込まれます。
- ダイアログが閉じられた後(
カスタムの「最近使用したファイル/ディレクトリ」リストを独自に管理する
これは最も一般的で柔軟なアプローチです。QFileDialog
の履歴機能に頼らず、アプリケーション自身が「最近使用したファイル」や「最近使用したディレクトリ」のリストを管理し、それをユーザーに提供します。
メリット
- メニューへの統合
アプリケーションの「ファイル」メニューに「最近使用したファイル」サブメニューを追加するなど、UI に密に統合できます。 - プラットフォーム非依存の挙動
OS ネイティブダイアログの挙動に左右されず、すべてのプラットフォームで一貫したユーザー体験を提供できます。 - ファイルとディレクトリの両方に対応
QFileDialog::history()
はディレクトリの履歴のみですが、この方法ならファイルとディレクトリの両方の履歴を管理できます。 - 完全な制御
履歴の保存形式、最大数、表示方法、更新ロジックなど、すべてをアプリケーション側で自由に制御できます。
実装方法
- 履歴リストのデータ構造
QStringList
やQList<QUrl>
などで、最近アクセスしたパス(ファイルまたはディレクトリ)を保持します。重複を避けるためにQSet<QString>
なども検討できます。 - 履歴の追加
ファイル/ディレクトリが選択されるたびに、そのパスをリストの先頭に追加します。最大数を超えた場合は、古い項目を削除します。- 例:
QFileDialog::selectedFiles()
またはQFileDialog::selectedUrls()
から取得したパスを使用します。
- 例:
- 履歴の保存と復元
- 保存
アプリケーション終了時に、QSettings
やカスタム設定ファイル (.ini
, JSON, XMLなど) を使用して履歴リストを保存します。 - 復元
アプリケーション起動時に、保存された履歴を読み込み、リストに設定します。
- 保存
- UI への表示
- メニュー
QMenu
とQAction
を使用して、「ファイル」メニューなどに「最近使用したファイル」サブメニューを作成し、各履歴項目をQAction
として追加します。 - QFileDialogへの設定
もしQFileDialog
を使用する場合でも、setDirectory()
やsetSidebarUrls()
(Qt 5.3以降) を使って、独自の履歴リストのパスを初期ディレクトリやサイドバーに表示させることで、利便性を高めることができます。ただし、これらの方法で設定したパスがQFileDialog
の内部履歴に自動的に追加されるわけではありません。
- メニュー
#include <QApplication>
#include <QMainWindow>
#include <QAction>
#include <QMenu>
#include <QFileDialog>
#include <QSettings>
#include <QDebug>
#include <QUrl>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
{
createActions();
createMenus();
loadRecentFiles(); // 起動時に履歴をロード
setWindowTitle("カスタム履歴の例");
resize(400, 300);
}
private slots:
void openFile()
{
QFileDialog dialog(this);
dialog.setWindowTitle("ファイルを開く");
// 前回のディレクトリを設定 (オプション)
if (!m_recentFiles.isEmpty()) {
dialog.setDirectory(QFileInfo(m_recentFiles.first()).dir().path());
}
if (dialog.exec()) {
QString selectedFile = dialog.selectedFiles().first();
qDebug() << "選択されたファイル:" << selectedFile;
updateRecentFiles(selectedFile); // 履歴を更新
}
}
void openRecentFile()
{
QAction *action = qobject_cast<QAction *>(sender());
if (action) {
QString filePath = action->data().toString();
qDebug() << "最近のファイルを開く:" << filePath;
// ここでファイルを開くロジックを実装
updateRecentFiles(filePath); // 開いたファイルを履歴の先頭に移動
}
}
private:
void createActions()
{
m_openAction = new QAction(tr("&開く..."), this);
connect(m_openAction, &QAction::triggered, this, &MainWindow::openFile);
}
void createMenus()
{
QMenu *fileMenu = menuBar()->addMenu(tr("&ファイル"));
fileMenu->addAction(m_openAction);
m_recentFilesMenu = fileMenu->addMenu(tr("最近開いたファイル"));
// 履歴メニューのアクションは動的に追加される
}
void loadRecentFiles()
{
QSettings settings;
m_recentFiles = settings.value("recentFiles").toStringList();
updateRecentFilesMenu();
}
void saveRecentFiles()
{
QSettings settings;
settings.setValue("recentFiles", m_recentFiles);
}
void updateRecentFiles(const QString &filePath)
{
// 既存のパスを削除 (重複を避けるため)
m_recentFiles.removeAll(filePath);
// パスをリストの先頭に追加
m_recentFiles.prepend(filePath);
// 最大履歴数を制限 (例: 10件)
while (m_recentFiles.size() > 10) {
m_recentFiles.removeLast();
}
updateRecentFilesMenu();
saveRecentFiles(); // 変更を保存
}
void updateRecentFilesMenu()
{
m_recentFilesMenu->clear(); // 既存のアクションをクリア
for (const QString &filePath : m_recentFiles) {
QAction *action = new QAction(QFileInfo(filePath).fileName(), this);
action->setData(filePath); // パスをアクションのデータとして保存
connect(action, &QAction::triggered, this, &MainWindow::openRecentFile);
m_recentFilesMenu->addAction(action);
}
// 履歴が空の場合、メニューを無効化するなど
m_recentFilesMenu->setEnabled(!m_recentFiles.isEmpty());
}
private:
QAction *m_openAction;
QMenu *m_recentFilesMenu;
QStringList m_recentFiles; // カスタム履歴リスト
};
#include "main.moc" // mocファイルをインクルード
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setOrganizationName("MyCompany");
a.setApplicationName("MyCustomHistoryApp");
MainWindow w;
w.show();
return a.exec();
}
QFileSystemModel を使用したカスタムダイアログ
QFileDialog
は内部的に QFileSystemModel
を使用してファイルシステムの内容を表示しています。より高度なカスタマイズが必要な場合は、QDialog
を継承した独自のダイアログを作成し、その中に QTreeView
や QListView
と QFileSystemModel
を組み合わせて独自のファイルブラウザを構築する方法があります。
メリット
- 独自の履歴/お気に入り機能
QFileDialog::history()
とは全く異なる、独自の履歴メカニズム(例えば、ユーザーが「お気に入り」として登録したフォルダを素早く表示する機能など)を実装できます。 - 究極のカスタマイズ性
レイアウト、表示される情報、フィルタリングロジック、コンテキストメニューなど、ダイアログのあらゆる側面を自由に制御できます。
- OSネイティブの見た目と挙動との乖離
OSの標準的なファイルダイアログとは見た目や操作感が異なるため、ユーザーが戸惑う可能性があります。 - 複雑性の増加
ゼロからファイルダイアログを構築するため、実装の手間とコード量が増加します。
QDialog
を継承したクラスを作成します。- 内部に
QTreeView
またはQListView
を配置します。 QFileSystemModel
のインスタンスを作成し、QTreeView
/QListView
のモデルとして設定します。QFileSystemModel::setRootPath()
で表示するルートディレクトリを設定します。- ユーザーがパスを選択できるように、シグナルとスロットを接続し、選択されたパスを取得するロジックを実装します。
- 独自の履歴(お気に入り)リストを管理し、それをダイアログ内の
QListWidget
やQComboBox
などに表示し、ユーザーがクリックすることで目的のディレクトリへ移動できるようにします。
#include <QApplication>
#include <QDialog>
#include <QTreeView>
#include <QListView>
#include <QFileSystemModel>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QSettings>
#include <QDebug>
#include <QCompleter> // 自動補完用
class CustomFileDialog : public QDialog
{
Q_OBJECT
public:
explicit CustomFileDialog(QWidget *parent = nullptr) : QDialog(parent)
{
setWindowTitle("カスタムファイルダイアログ");
setMinimumSize(600, 400);
m_fileSystemModel = new QFileSystemModel(this);
m_fileSystemModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
m_fileSystemModel->setRootPath(""); // システムのルートから開始
m_treeView = new QTreeView(this);
m_treeView->setModel(m_fileSystemModel);
m_treeView->setRootIndex(m_fileSystemModel->index(QDir::currentPath())); // 初期ディレクトリ
m_treeView->setColumnHidden(1, true); // サイズ列を非表示
m_treeView->setColumnHidden(2, true); // タイプ列を非表示
m_treeView->setColumnHidden(3, true); // 更新日時列を非表示
// ディレクトリ変更時の処理
connect(m_treeView, &QTreeView::doubleClicked, this, &CustomFileDialog::onTreeViewDoubleClicked);
connect(m_treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &CustomFileDialog::onSelectionChanged);
m_pathEdit = new QLineEdit(this);
// 履歴をオートコンプリートに利用
m_completer = new QCompleter(this);
m_completer->setCaseSensitivity(Qt::CaseInsensitive);
m_pathEdit->setCompleter(m_completer);
QPushButton *okButton = new QPushButton("開く", this);
QPushButton *cancelButton = new QPushButton("キャンセル", this);
connect(okButton, &QPushButton::clicked, this, &CustomFileDialog::accept);
connect(cancelButton, &QPushButton::clicked, this, &CustomFileDialog::reject);
connect(m_pathEdit, &QLineEdit::returnPressed, this, &CustomFileDialog::accept);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(m_pathEdit);
mainLayout->addWidget(m_treeView);
QHBoxLayout *buttonLayout = new QHBoxLayout();
buttonLayout->addStretch();
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
mainLayout->addLayout(buttonLayout);
loadRecentPaths(); // 履歴をロードしてコンプリータに設定
m_pathEdit->setText(QDir::currentPath()); // 初期パスを設定
}
QString selectedFilePath() const {
return m_pathEdit->text();
}
protected:
void accept() override {
// パスがディレクトリの場合、ファイル選択ダイアログとして機能しない可能性
// 適切な検証を追加する必要がある
QFileInfo fileInfo(m_pathEdit->text());
if (fileInfo.exists() && fileInfo.isFile()) {
addRecentPath(m_pathEdit->text());
QDialog::accept();
} else {
QMessageBox::warning(this, "エラー", "ファイルを選択してください。");
}
}
private slots:
void onTreeViewDoubleClicked(const QModelIndex &index)
{
if (m_fileSystemModel->isDir(index)) {
m_treeView->setRootIndex(index); // ディレクトリを掘り下げる
m_pathEdit->setText(m_fileSystemModel->filePath(index));
} else {
m_pathEdit->setText(m_fileSystemModel->filePath(index));
accept(); // ファイルの場合は選択してダイアログを閉じる
}
}
void onSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous)
{
Q_UNUSED(previous);
m_pathEdit->setText(m_fileSystemModel->filePath(current));
}
private:
void loadRecentPaths()
{
QSettings settings;
QStringList recentPaths = settings.value("customFileDialogRecentPaths").toStringList();
m_completer->setModel(new QStringListModel(recentPaths, m_completer)); // コンプリータに履歴を設定
}
void addRecentPath(const QString &path)
{
QSettings settings;
QStringList recentPaths = settings.value("customFileDialogRecentPaths").toStringList();
recentPaths.removeAll(path); // 重複を削除
recentPaths.prepend(path); // 先頭に追加
while (recentPaths.size() > 20) { // 最大20件
recentPaths.removeLast();
}
settings.setValue("customFileDialogRecentPaths", recentPaths);
m_completer->setModel(new QStringListModel(recentPaths, m_completer)); // コンプリータを更新
}
private:
QFileSystemModel *m_fileSystemModel;
QTreeView *m_treeView;
QLineEdit *m_pathEdit;
QCompleter *m_completer;
};
#include "main.moc" // mocファイルをインクルード
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setOrganizationName("MyCompany");
a.setApplicationName("MyCustomFileDialogApp");
CustomFileDialog dialog;
if (dialog.exec() == QDialog::Accepted) {
qDebug() << "選択されたファイル:" << dialog.selectedFilePath();
}
return a.exec();
}
- ファイルダイアログの見た目や挙動を大幅にカスタマイズしたい場合
「QFileSystemModel を使用したカスタムダイアログ」が適しています。例えば、特定の種類のファイルのみを表示する特別なフィルター、ネットワークドライブのリスト、クラウドストレージとの連携など、標準のQFileDialog
では不可能な機能を追加できます。ただし、OSネイティブダイアログの使い慣れた操作感を犠牲にする可能性があります。 - シンプルな「最近開いたファイル」リストが欲しいだけの場合
「カスタムの『最近使用したファイル/ディレクトリ』リストを独自に管理する」方法が最も簡単で、多くのアプリケーションで十分です。QFileDialog
はそのまま使い、履歴はアプリケーションのメニューなどに表示します。