Qt QFileDialog::urlSelected()徹底解説: ファイル選択ダイアログでURLを扱う方法

2025-05-26

Qtプログラミングにおけるvoid QFileDialog::urlSelected()は、QFileDialogクラスが持つシグナルの一つです。

urlSelected()とは何か?

これは、ユーザーがファイルダイアログ内で単一のURLを選択し、「開く」または「保存」のようなアクションを実行したときに発行されるシグナルです。

通常、QFileDialogはファイルシステム上のローカルファイルを選択するために使われますが、Qt 5以降では、URL(例えば、http://ftp://のようなプロトコルを含むアドレス)を選択することも可能になりました。

このシグナルが発行されると、選択されたURLがQUrlオブジェクトとして引数として渡されます。

なぜこれが重要なのか?

QFileDialogは、ユーザーインターフェースからファイルやディレクトリを選択するための標準的なダイアログを提供します。アプリケーションがネットワーク上のリソースを操作する場合など、単にローカルファイルだけでなく、URLも選択できると非常に便利です。

urlSelected()シグナルを使用することで、アプリケーションはユーザーが選択したURLを受け取り、それに基づいて適切な処理(例えば、URLからデータをダウンロードする、URLを保存する、など)を行うことができます。

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

class MyWindow : public QWidget
{
    Q_OBJECT // シグナルとスロットを使用するために必要

public:
    MyWindow(QWidget *parent = nullptr) : QWidget(parent)
    {
        QPushButton *openButton = new QPushButton("URLを開く", this);
        connect(openButton, &QPushButton::clicked, this, &MyWindow::openUrlDialog);
    }

private slots:
    void openUrlDialog()
    {
        QFileDialog *dialog = new QFileDialog(this);
        dialog->setFileMode(QFileDialog::AnyFile); // 任意のファイルを選択可能にする

        // URLスキームをサポートすることを宣言("file"はデフォルトで含まれる)
        QStringList supportedSchemes;
        supportedSchemes << "http" << "https" << "ftp"; // サポートしたいスキームを追加
        dialog->setSupportedSchemes(supportedSchemes);

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

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

    void handleUrlSelected(const QUrl &url)
    {
        qDebug() << "選択されたURL:" << url.toString();
        // ここで選択されたURLに対する処理を記述します。
        // 例: URLからデータを読み込む、ブラウザで開くなど
    }
};

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

    MyWindow window;
    window.show();

    return app.exec();
}

#include "main.moc" // mocツールによって生成されるファイル

上記の例では、

  1. QFileDialogのインスタンスを作成します。
  2. setSupportedSchemes()を使用して、ダイアログでユーザーが入力または選択できるURLスキーム(プロトコル)を定義します。これにより、ユーザーはファイルシステム上のパスだけでなく、例えば https://example.com/somefile.txt のようなURLを入力できるようになります。
  3. QFileDialog::urlSelected シグナルを、カスタムスロットである MyWindow::handleUrlSelected に接続しています。
  4. ユーザーがファイルダイアログでURLを選択し、OKボタンをクリックすると、handleUrlSelected スロットが呼び出され、選択されたURL(QUrlオブジェクト)が引数として渡されます。


シグナルが発火しない/接続が機能しない

考えられる原因

  • ユーザーがキャンセルした
    ユーザーが「キャンセル」ボタンを押した場合、urlSelected()は発火しません。この場合、QFileDialog::rejected()シグナルやQFileDialog::result()メソッド(QDialog::Rejectedが返される)で処理する必要があります。
  • サポートされていないスキーム
    QFileDialog::setSupportedSchemes()で、ユーザーが入力または選択しようとしているURLのスキーム(例: http, ftpなど)が指定されていない場合、そのURLは有効と見なされず、urlSelected()が発火しないことがあります。
  • ダイアログがモーダルで開かれている
    QFileDialog::exec()を使ってダイアログをモーダルで開いている場合、ダイアログが閉じられるまでイベントループがブロックされ、シグナルが処理されないことがあります。urlSelected()は、ダイアログが閉じられる前にユーザーがURLを選択したときに発生するため、非モーダルなopen()を使用する必要があります。
  • Q_OBJECTマクロの欠如
    シグナルとスロットを使用するクラス(通常はQWidgetを継承したクラス)にQ_OBJECTマクロがない場合、MOC(Meta-Object Compiler)がメタオブジェクトコードを生成せず、シグナル/スロットシステムが機能しません。
  • シグナルとスロットの接続ミス
    最も基本的なエラーです。connect()関数の引数が間違っている、またはシグネチャが一致しないなどの可能性があります。

トラブルシューティング

  • デバッグ出力(qDebug())を使用して、シグナルが発火しているかどうか、スロットが呼び出されているかどうかを確認してください。
  • QFileDialog::setSupportedSchemes()を使って、アプリケーションがサポートするURLスキームを明示的にリストアップしてください。"file"スキームはデフォルトでサポートされており、明示的に追加する必要はありません。
  • ダイアログを開く際には、dialog->open();を使用し、dialog->exec();を使用しないようにしてください。
  • Q_OBJECTマクロがクラス定義の先頭に存在し、mocが正しく実行されていることを確認してください。ビルドシステムが適切に設定されていれば通常は自動的に処理されます。
  • connect()の引数を再確認し、シグナルとスロットの引数型、const修飾子などが完全に一致していることを確認してください。Qt 5以降の新しい接続構文(ラムダ式やメンバ関数ポインタ)を使用することをお勧めします。コンパイル時にエラーを検出できます。
    • 良い例: connect(dialog, &QFileDialog::urlSelected, this, &MyWindow::handleUrlSelected);
    • 避けるべき(古い)例: connect(dialog, SIGNAL(urlSelected(QUrl)), this, SLOT(handleUrlSelected(QUrl)));

選択されたURLが期待通りでない

考えられる原因

  • プラットフォーム固有の挙動
    ネイティブダイアログを使用している場合、プラットフォームによってはURLの処理方法が異なることがあります。例えば、WindowsではパスとURLの区別が曖昧になる場合があります。
  • 相対パス/無効なURL
    ユーザーが入力したURLが相対パスであったり、完全に無効な形式であったりする可能性があります。

トラブルシューティング

  • 特定のプラットフォームで問題が発生する場合は、QFileDialog::DontUseNativeDialogオプションを使用してQtの標準ダイアログを強制的に使用してみることで、問題が解決するかどうか確認できます。
  • ユーザーに有効なURLを入力するよう促すか、アプリケーション側でURLのバリデーションロジックを追加することを検討してください。
  • url.isValid()url.isLocalFile()url.scheme()などのQUrlのメソッドを使って、受け取ったURLオブジェクトが期待通りのものであるかを確認してください。

ダイアログの表示に関する問題 (クラッシュ、表示崩れなど)

urlSelected()シグナル自体が直接クラッシュの原因となることは稀ですが、QFileDialogのインスタンス化や使用方法に問題があると、ダイアログの表示時にクラッシュや表示崩れが発生することがあります。

考えられる原因

  • スレッドの問題
    UI操作はメインスレッドで行う必要があります。別のスレッドからQFileDialogを呼び出そうとすると、クラッシュや予期せぬ動作につながります。
  • ネイティブダイアログとの互換性
    特定のOSバージョンやデスクトップ環境で、Qtのネイティブダイアログとの互換性の問題が発生することがあります。
  • 親ウィジェットの解放
    QFileDialogの親ウィジェットが、ダイアログが閉じられる前に解放されてしまうと、クラッシュにつながることがあります。
  • QFileDialogの呼び出しが常にメインスレッドで行われていることを確認してください。
  • QFileDialog::DontUseNativeDialogオプションを試して、Qtの描画によるダイアログを使用してみてください。これで問題が解決する場合、OSのネイティブダイアログとの互換性の問題である可能性が高いです。
  • QFileDialogのインスタンスをヒープに割り当て(new QFileDialog(...))、適切な親オブジェクトを設定することで、親オブジェクトのライフサイクル管理に任せるようにしてください。
  • QFileDialogの初期ディレクトリやURLの設定ミス
    setDirectory()setDirectoryUrl()で指定するパスやURLが間違っていると、ダイアログが開いても目的の場所が表示されないことがあります。
    • トラブルシューティング
      指定するパス/URLが有効であることを確認してください。特にWindowsでは、パスの区切り文字に/を使用することを推奨します。


例1: 基本的なURL選択ダイアログ

この例では、ボタンをクリックするとファイルダイアログが開き、ユーザーがURLを選択したら、そのURLをコンソールに出力します。

main.cpp

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

class MyMainWindow : public QMainWindow
{
    Q_OBJECT // シグナルとスロットを使用するために必要

public:
    MyMainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        QPushButton *openUrlButton = new QPushButton("URLを開く", this);
        setCentralWidget(openUrlButton);

        // ボタンがクリックされたら openUrlDialog スロットを呼び出す
        connect(openUrlButton, &QPushButton::clicked, this, &MyMainWindow::openUrlDialog);
    }

private slots:
    void openUrlDialog()
    {
        QFileDialog *dialog = new QFileDialog(this);
        dialog->setWindowTitle("URLを選択");
        dialog->setFileMode(QFileDialog::AnyFile); // 任意のファイル(URLを含む)を選択可能にする

        // サポートするURLスキームを設定
        // これがないと、file:// 以外のURLは入力されても有効とみなされない場合があります
        QStringList supportedSchemes;
        supportedSchemes << "file" << "http" << "https" << "ftp";
        dialog->setSupportedSchemes(supportedScheemes);

        // urlSelected シグナルを handleUrlSelected スロットに接続
        // ユーザーがURLを選択し、OKをクリックするとこのシグナルが発火する
        connect(dialog, &QFileDialog::urlSelected, this, &MyMainWindow::handleUrlSelected);

        // ダイアログを非モーダルで開く(これ重要!)
        // モーダルな exec() を使うと、シグナル処理がブロックされる可能性があります。
        dialog->open();

        // ダイアログが閉じられたときのクリーンアップ
        // ダイアログが閉じられたときに自動的に削除されるように設定
        connect(dialog, &QFileDialog::finished, dialog, &QFileDialog::deleteLater);
    }

    void handleUrlSelected(const QUrl &url)
    {
        qDebug() << "選択されたURL:" << url.toString();

        // ここで選択されたURLに対する実際の処理を記述します。
        // 例:
        if (url.isValid()) {
            if (url.isLocalFile()) {
                qDebug() << "ローカルファイルパス:" << url.toLocalFile();
                // QUrl::toLocalFile() でローカルファイルパスに変換できます
            } else {
                qDebug() << "ネットワークURL:" << url.toString();
                // ネットワークURLを処理します
                // 例: QNetworkAccessManager を使ってダウンロードを開始するなど
            }
        } else {
            qDebug() << "無効なURLが選択されました。";
        }
    }
};

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

    MyMainWindow window;
    window.resize(300, 200);
    window.show();

    return app.exec();
}

#include "main.moc" // MOC (Meta-Object Compiler) が生成するファイル

解説

  1. Q_OBJECT マクロ
    MyMainWindow クラスがシグナルとスロットを使用するために、クラス定義の先頭にQ_OBJECTマクロが必要です。これにより、Qtのメタオブジェクトシステムが有効になります。
  2. openUrlDialog() スロット
    • QFileDialog のインスタンスを動的に作成します。this を親オブジェクトとして設定することで、MyMainWindow が破棄されるときにダイアログも自動的に破棄されるようになります(ただし、deleteLater も併用するとより確実です)。
    • setFileMode(QFileDialog::AnyFile): これにより、ユーザーはファイルシステム上のパスだけでなく、URLを入力できるようになります。
    • setSupportedSchemes(): これが非常に重要です。 このメソッドを使って、QFileDialog がURLとして認識し、urlSelected() シグナルを発火させるスキーム(プロトコル、例: http, https, ftp)を指定します。"file" は通常デフォルトでサポートされていますが、明示的に追加しておくと良いでしょう。
    • connect(dialog, &QFileDialog::urlSelected, this, &MyMainWindow::handleUrlSelected);: QFileDialogurlSelected() シグナルを MyMainWindowhandleUrlSelected() スロットに接続しています。ユーザーがダイアログでURLを選択し、「開く」または「保存」ボタンをクリックすると、このシグナルが発火し、handleUrlSelected が呼び出されます。
    • dialog->open();: ダイアログを非モーダルで開きます。QFileDialog::exec() を使うとダイアログが閉じられるまでプログラムの実行がブロックされるため、シグナルを処理するには open() を使用します。
    • connect(dialog, &QFileDialog::finished, dialog, &QFileDialog::deleteLater);: ダイアログが閉じられたときに、そのオブジェクトが自動的にメモリから削除されるように設定しています。これは、ヒープに割り当てたオブジェクトのメモリ管理を行う良いプラクティスです。
  3. handleUrlSelected(const QUrl &url) スロット
    • urlSelected() シグナルから渡された QUrl オブジェクトを受け取ります。
    • url.toString() でURLの文字列表現を取得できます。
    • url.isValid() でURLが有効な形式であるかを確認できます。
    • url.isLocalFile() でそのURLがローカルファイルシステムを指しているかを確認できます。ローカルファイルであれば、url.toLocalFile() で通常のファイルパス文字列に変換できます。

この例は、ユーザーがURLを「保存先」として指定できるようにするものです。

#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QFileDialog>
#include <QUrl>
#include <QDebug>

class MySaveApp : public QMainWindow
{
    Q_OBJECT

public:
    MySaveApp(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        QPushButton *saveUrlButton = new QPushButton("URLとして保存", this);
        setCentralWidget(saveUrlButton);
        connect(saveUrlButton, &QPushButton::clicked, this, &MySaveApp::saveUrlDialog);
    }

private slots:
    void saveUrlDialog()
    {
        QFileDialog *dialog = new QFileDialog(this);
        dialog->setWindowTitle("URLとして保存");
        dialog->setFileMode(QFileDialog::AnyFile); // ファイル名(URL)を入力可能にする
        dialog->setAcceptMode(QFileDialog::AcceptSave); // 保存モードに設定

        QStringList supportedSchemes;
        supportedSchemes << "file" << "http" << "ftp"; // 保存先としてサポートしたいスキーム
        dialog->setSupportedSchemes(supportedSchemes);

        // urlSelected シグナルを接続
        connect(dialog, &QFileDialog::urlSelected, this, &MySaveApp::handleUrlToSave);

        dialog->open();
        connect(dialog, &QFileDialog::finished, dialog, &QFileDialog::deleteLater);
    }

    void handleUrlToSave(const QUrl &url)
    {
        qDebug() << "保存対象のURL:" << url.toString();

        if (url.isValid()) {
            if (url.isLocalFile()) {
                qDebug() << "ローカルファイルパスとして保存:" << url.toLocalFile();
                // ここで実際にファイルにデータを書き込む処理などを記述
            } else {
                qDebug() << "ネットワークURLとして処理(例えばFTPアップロード先など):" << url.toString();
                // 例えばFTPクライアントでアップロードするなどの処理
            }
        } else {
            qDebug() << "無効なURLが指定されました。";
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MySaveApp window;
    window.resize(300, 200);
    window.show();
    return app.exec();
}

#include "main.moc"

この例では、setAcceptMode(QFileDialog::AcceptSave) を設定することで、ダイアログの挙動を「保存」に適したものにしています。ユーザーがファイル名としてURLを入力し、保存ボタンを押すと urlSelected シグナルが発火します。



QInputDialog::getText() を使用する

最もシンプルで手軽な方法の一つは、QInputDialogを使ってユーザーに直接URLを入力させるテキスト入力ダイアログを表示することです。

メリット

  • ファイルシステムの閲覧機能が必要ない場合に、UIがシンプルになる。
  • ダイアログのカスタマイズが比較的容易(タイトル、ラベル、初期値など)。
  • 実装が非常に簡単。

デメリット

  • QUrlオブジェクトを直接返すわけではないので、入力された文字列を自分でQUrlに変換し、バリデーションする必要がある。
  • ファイルシステム上のパスを選択するような視覚的な補助がない。
  • ユーザーがURLを正確に入力する必要があるため、手動入力ミスが発生しやすい。

コード例

#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QInputDialog>
#include <QUrl>
#include <QDebug>

class MyMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MyMainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        QPushButton *enterUrlButton = new QPushButton("URLを入力", this);
        setCentralWidget(enterUrlButton);
        connect(enterUrlButton, &QPushButton::clicked, this, &MyMainWindow::enterUrlManually);
    }

private slots:
    void enterUrlManually()
    {
        bool ok;
        // QInputDialog::getText() を使ってテキスト入力を促す
        QString urlString = QInputDialog::getText(this, tr("URLを入力"),
                                                  tr("WebサイトのURLを入力してください:"),
                                                  QLineEdit::Normal,
                                                  "https://example.com", // 初期値
                                                  &ok);

        if (ok && !urlString.isEmpty()) {
            QUrl url(urlString); // QString を QUrl に変換
            qDebug() << "入力されたURL:" << url.toString();

            if (url.isValid()) {
                qDebug() << "有効なURLです。";
                // ここでURLに対する処理を記述
            } else {
                qDebug() << "無効なURLです。";
                // ユーザーに再入力を促す、エラーメッセージを表示するなどの処理
            }
        } else {
            qDebug() << "URL入力がキャンセルされました。";
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MyMainWindow window;
    window.resize(300, 200);
    window.show();
    return app.exec();
}

#include "main.moc"

カスタムダイアログを作成する

より複雑な要件や、特定のUI/UXを提供したい場合は、QDialogを継承して独自のURL入力ダイアログを作成する方法が最も柔軟です。

メリット

  • リアルタイムの入力バリデーションや、URLスキームに基づく動的なUI変更が可能。
  • 完全にカスタマイズ可能なUI(QLineEdit、バリデーション、ボタン、ヒントなど)。

デメリット

  • シグナルとスロットの設計を自分で考える必要がある。
  • 実装の手間が最も大きい。
// MyUrlInputDialog.h
#ifndef MYURLINPUTDIALOG_H
#define MYURLINPUTDIALOG_H

#include <QDialog>
#include <QLineEdit>
#include <QPushButton>
#include <QUrl>
#include <QVBoxLayout>
#include <QLabel>

class MyUrlInputDialog : public QDialog
{
    Q_OBJECT

public:
    explicit MyUrlInputDialog(QWidget *parent = nullptr);
    QUrl getUrl() const; // 選択されたURLを取得するメソッド

signals:
    void urlConfirmed(const QUrl &url); // カスタムシグナル

private slots:
    void onOkButtonClicked();
    void validateUrlInput(const QString &text); // 入力バリデーション

private:
    QLineEdit *urlLineEdit;
    QPushButton *okButton;
    QPushButton *cancelButton;
    QLabel *statusLabel; // バリデーション結果を表示
    QUrl m_url;
};

#endif // MYURLINPUTDIALOG_H

// MyUrlInputDialog.cpp
#include "MyUrlInputDialog.h"
#include <QRegExpValidator>
#include <QMessageBox>

MyUrlInputDialog::MyUrlInputDialog(QWidget *parent) : QDialog(parent)
{
    setWindowTitle("カスタムURL入力");

    urlLineEdit = new QLineEdit(this);
    urlLineEdit->setPlaceholderText("例: https://www.example.com");
    connect(urlLineEdit, &QLineEdit::textChanged, this, &MyUrlInputDialog::validateUrlInput);

    okButton = new QPushButton("OK", this);
    okButton->setEnabled(false); // 初期状態では無効
    connect(okButton, &QPushButton::clicked, this, &MyUrlInputDialog::onOkButtonClicked);

    cancelButton = new QPushButton("キャンセル", this);
    connect(cancelButton, &QPushButton::clicked, this, &MyUrlInputDialog::reject); // QDialog::reject() を呼び出す

    statusLabel = new QLabel("有効なURLを入力してください", this);
    statusLabel->setStyleSheet("color: red;");

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(new QLabel("URL:", this));
    layout->addWidget(urlLineEdit);
    layout->addWidget(statusLabel);
    QHBoxLayout *buttonLayout = new QHBoxLayout();
    buttonLayout->addStretch();
    buttonLayout->addWidget(okButton);
    buttonLayout->addWidget(cancelButton);
    layout->addLayout(buttonLayout);

    setLayout(layout);
}

QUrl MyUrlInputDialog::getUrl() const
{
    return m_url;
}

void MyUrlInputDialog::onOkButtonClicked()
{
    QUrl inputUrl(urlLineEdit->text());
    if (inputUrl.isValid()) {
        m_url = inputUrl;
        emit urlConfirmed(m_url); // カスタムシグナルを発火
        accept(); // QDialog::accept() を呼び出し、ダイアログを閉じる
    } else {
        QMessageBox::warning(this, "無効なURL", "入力されたURLは有効ではありません。");
    }
}

void MyUrlInputDialog::validateUrlInput(const QString &text)
{
    QUrl tempUrl(text);
    if (tempUrl.isValid()) {
        statusLabel->setText("有効なURLです");
        statusLabel->setStyleSheet("color: green;");
        okButton->setEnabled(true);
    } else {
        statusLabel->setText("無効なURLです");
        statusLabel->setStyleSheet("color: red;");
        okButton->setEnabled(false);
    }
}

// main.cpp での使用例
// (MyMainWindow クラスの一部として)
/*
void MyMainWindow::openCustomUrlInputDialog()
{
    MyUrlInputDialog dialog(this);
    // カスタムシグナルに接続
    connect(&dialog, &MyUrlInputDialog::urlConfirmed, this, [](const QUrl &url){
        qDebug() << "カスタムダイアログからURLを受信:" << url.toString();
        // ここでURLの処理
    });

    if (dialog.exec() == QDialog::Accepted) {
        // ダイアログがAcceptedで閉じられた場合、getUrl()でURLを取得することも可能
        // QUrl selectedUrl = dialog.getUrl();
        // qDebug() << "QDialog::Accepted で取得:" << selectedUrl.toString();
    } else {
        qDebug() << "カスタムダイアログがキャンセルされました。";
    }
}
*/

設定ファイルや履歴からのロード

過去に保存したURLのリストから選択させる、または設定ファイルからデフォルトのURLをロードする機能を提供することも、手動入力を減らす代替手段となります。

メリット

  • よく使うURLの再入力を防ぐことができる。
  • ユーザーの利便性が向上する。

デメリット

  • リスト管理のロジックが必要。
  • 初回利用時には手動入力または他の方法が必要。
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QComboBox> // ドロップダウンリスト
#include <QSettings> // 設定保存用
#include <QVBoxLayout>
#include <QDebug>

class MySettingsApp : public QMainWindow
{
    Q_OBJECT

public:
    MySettingsApp(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        QWidget *centralWidget = new QWidget(this);
        QVBoxLayout *layout = new QVBoxLayout(centralWidget);

        urlComboBox = new QComboBox(this);
        urlComboBox->setEditable(true); // ユーザーが直接入力できるようにする
        layout->addWidget(urlComboBox);

        QPushButton *loadUrlButton = new QPushButton("選択/入力したURLをロード", this);
        layout->addWidget(loadUrlButton);
        connect(loadUrlButton, &QPushButton::clicked, this, &MySettingsApp::loadSelectedUrl);

        loadUrlHistory(); // 履歴をロード

        setCentralWidget(centralWidget);
    }

private slots:
    void loadSelectedUrl()
    {
        QString currentText = urlComboBox->currentText();
        QUrl url(currentText);

        if (url.isValid()) {
            qDebug() << "ロードされたURL:" << url.toString();
            // 履歴にない場合は追加
            if (urlComboBox->findText(currentText) == -1) {
                urlComboBox->addItem(currentText);
                saveUrlHistory(currentText); // 履歴を保存
            }
            // ここでURLに対する処理を記述
        } else {
            qDebug() << "無効なURLが選択/入力されました。";
        }
    }

private:
    QComboBox *urlComboBox;
    QSettings settings; // 設定ファイル

    void loadUrlHistory()
    {
        QStringList history = settings.value("url_history").toStringList();
        urlComboBox->addItems(history);
    }

    void saveUrlHistory(const QString &newUrl)
    {
        QStringList history = settings.value("url_history").toStringList();
        // 重複を避ける
        if (!history.contains(newUrl)) {
            history.prepend(newUrl); // 新しいものを先頭に追加
            // 必要に応じて履歴の最大数を制限する
            while (history.size() > 10) {
                history.removeLast();
            }
            settings.setValue("url_history", history);
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    // QSettings が正しく動作するためにアプリケーション情報を設定
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyUrlApp");

    MySettingsApp window;
    window.resize(300, 200);
    window.show();
    return app.exec();
}

#include "main.moc"