初心者必見!Qt QListWidgetのアイテム追加・削除・取得の基本

2025-05-31

まず、QListWidget は、リスト形式で項目(アイテム)を表示・管理するためのウィジェットです。ファイルリストや設定項目の一覧など、ユーザーに選択肢を提示する際によく利用されます。

QListWidget::items() というメソッドは、QListWidget クラスのメンバ関数として存在します。ただし、Qtの公式ドキュメントで QListWidget::items() という正確な名前の関数は通常見当たりません。

一般的に、QListWidget 内のすべてのアイテムを取得したい場合は、以下のいずれかの方法を使用します。

  1. QListWidget::item(int row) と QListWidget::count() を組み合わせる方法
    QListWidget::count() は、リスト内のアイテムの総数を返します。 QListWidget::item(int row) は、指定された行(インデックス)にある QListWidgetItem へのポインタを返します。 したがって、ループを使って0から count() - 1 までの各行に対して item() を呼び出すことで、すべてのアイテムを順番に取得できます。

    QListWidget* listWidget; // 既存のQListWidgetへのポインタ
    QList<QListWidgetItem*> allItems;
    for (int i = 0; i < listWidget->count(); ++i) {
        QListWidgetItem* item = listWidget->item(i);
        if (item) {
            allItems.append(item);
        }
    }
    // allItems にすべての QListWidgetItem が格納されます
    
  2. QListWidget::selectedItems()
    これは QListWidget に存在する関数で、現在選択されているすべてのアイテムのリスト(QList<QListWidgetItem*>)を返します。もし、選択されているアイテムのみが必要な場合はこの関数が非常に便利です。

  3. QListWidget::findItems(const QString &text, Qt::MatchFlags flags)
    この関数は、指定されたテキストに一致するアイテムを検索し、それらのアイテムのリストを返します。これは特定の条件に合うアイテムを探す場合に役立ちます。



前述の通り、QListWidget::items() という直接の関数は存在しないため、ここでは主に QListWidget 内のアイテム(QListWidgetItem)の操作に関連する一般的な問題に焦点を当てます。

メモリ管理に関するエラー (セグメンテーションフォールトなど)

よくあるエラー

  • QListWidgetItem を動的に確保したが、QListWidget から削除する際に適切にメモリを解放しない。
  • QListWidgetItem をスタック上に作成し、それを QListWidget に追加しようとする。

詳細
QListWidget は、追加された QListWidgetItem の所有権(ownership)を持ちます。これはつまり、QListWidget が破棄される際に、そこに含まれるすべての QListWidgetItem も自動的に削除されるということです。

しかし、QListWidgetItem をスタック上に作成し、そのポインタを QListWidget に渡すと、QListWidgetItem がスコープを外れると同時に破棄されてしまいます。その結果、QListWidget は無効なポインタを保持することになり、後でそのアイテムにアクセスしようとするとセグメンテーションフォールトなどのクラッシュが発生します。

トラブルシューティング

  • takeItem() で取得したアイテムのメモリ解放を忘れずに
    QListWidget::takeItem(int row) メソッドは、指定された行のアイテムをリストから削除し、そのアイテムのポインタを返します。この場合、QListWidget はそのアイテムの所有権を放棄します。したがって、takeItem() で取得したアイテムは、開発者が責任を持って delete する必要があります。

    QListWidgetItem* itemToDelete = ui->listWidget->takeItem(0); // 最初のアイテムを取得して削除
    if (itemToDelete) {
        delete itemToDelete; // 取得したアイテムのメモリを解放
    }
    

    もし takeItem() を呼び出した後、そのアイテムを別の QListWidget に移動するなど、引き続き使用する場合は delete は不要です。

  • QListWidgetItem は必ずヒープ上に作成する (new を使う)
    QListWidget に追加する QListWidgetItem は、常に new QListWidgetItem() のようにヒープ上に動的に確保してください。

    // 悪い例: スタック上に作成すると、スコープを抜けると削除されてしまう
    // QListWidgetItem item("My Item");
    // ui->listWidget->addItem(&item);
    
    // 良い例: ヒープ上に作成し、QListWidgetが所有権を持つ
    QListWidgetItem* item = new QListWidgetItem("My Item");
    ui->listWidget->addItem(item);
    

アイテムが正しく表示されない、または予期しない動作をする

よくあるエラー

  • スクロールやサイズ変更時に表示がおかしくなる。
  • アイテムのテキストやアイコンが更新されない。
  • QListWidgetItem を追加したのにリストに表示されない。

詳細

  • カスタムウィジェットをアイテムに設定する場合の注意
    QListWidget::setItemWidget() を使用してカスタムウィジェットをアイテムに埋め込む場合、そのウィジェットのライフサイクル管理に注意が必要です。
  • 大量のアイテム追加によるパフォーマンス問題
    非常に多くのアイテムを一度に追加すると、パフォーマンスが低下したり、UIが一時的にフリーズしたりすることがあります。
  • モデル/ビューの更新不足
    QListWidget は内部的にモデル/ビューアーキテクチャを使用しています。稀に、アイテムのプロパティを変更した後にウィジェットが自動的に再描画されない場合があります。
  • 同じアイテムを複数回追加
    同じ QListWidgetItem オブジェクトを複数回 QListWidget に追加しようとすると、未定義の動作を引き起こす可能性があります。各表示には新しい QListWidgetItem インスタンスが必要です。
  • addItem() や insertItem() の呼び忘れ
    アイテムを作成しただけでは表示されません。必ず QListWidget::addItem() または QListWidget::insertItem() を呼び出してリストに追加する必要があります。

トラブルシューティング

  • カスタムウィジェットのレイアウトとサイズヒント
    setItemWidget() を使う場合、埋め込んだカスタムウィジェットが適切な sizeHint() を提供しているか、または適切なレイアウトが設定されているか確認してください。これにより、アイテムが正しく表示されます。

  • パフォーマンス改善のための設定

    • listWidget->setUniformItemSizes(true);: すべてのアイテムのサイズが同じであると仮定することで、描画パフォーマンスを向上させることができます。特に、大量のアイテムを扱う場合に効果的です。
    • listWidget->setUpdatesEnabled(false); / listWidget->setUpdatesEnabled(true);: 大量のアイテムを一括で追加する前に setUpdatesEnabled(false) を呼び出し、追加完了後に setUpdatesEnabled(true) を呼び出すことで、中間的な再描画を防ぎ、処理を高速化できます。
    ui->listWidget->setUpdatesEnabled(false); // 更新を一時停止
    for (int i = 0; i < 10000; ++i) {
        ui->listWidget->addItem(QString("Item %1").arg(i));
    }
    ui->listWidget->setUpdatesEnabled(true); // 更新を再開
    ui->listWidget->update(); // 必要に応じて手動で更新を促す
    
  • update() または repaint() の呼び出し (通常は不要)
    ほとんどの場合、Qtは自動的にウィジェットを再描画しますが、もし表示の問題が続く場合は、対象のウィジェットに対して update()repaint() を呼び出してみるのも一つの手です。ただし、これは通常最後の手段です。

  • 一意な QListWidgetItem インスタンスの使用
    各リストアイテムに対して、新しい QListWidgetItem を作成してください。

  • addItem() や insertItem() の確認
    アイテムを作成したら、必ず適切な方法でリストに追加しているか確認してください。

よくあるエラー

  • 誤ったインデックスでアイテムにアクセスしようとする。
  • QListWidget::item(row)nullptr を返す。

詳細

  • 範囲外のインデックス
    QListWidget::item(int row)QListWidget::takeItem(int row) を呼び出す際に、有効な行番号(0から count() - 1 の範囲)を指定しないと、nullptr が返されたり、クラッシュしたりする可能性があります。

トラブルシューティング

  • QListWidget::currentItem() の活用
    現在選択されているアイテムを取得したい場合は、currentItem() を使用すると便利です。ただし、何も選択されていない場合は nullptr を返すので、これも確認が必要です。

    QListWidgetItem* selectedItem = ui->listWidget->currentItem();
    if (selectedItem) {
        QString text = selectedItem->text();
        // ... 処理
    } else {
        // アイテムが選択されていません
    }
    
  • インデックスのバリデーション
    アイテムにアクセスする前に、必ず row >= 0 && row < ui->listWidget->count() のようにインデックスが有効な範囲内にあるか確認してください。



繰り返しになりますが、QListWidget::items() という直接のメソッドは存在しません。ここでは、QListWidget 内のアイテム全般を扱う方法に焦点を当てます。

QListWidget の初期化とアイテムの追加

最も基本的な操作です。QListWidgetItem はヒープ (new) で作成する必要があります。

#include <QApplication>
#include <QListWidget>
#include <QListWidgetItem>
#include <QVBoxLayout>
#include <QWidget>

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

    // メインウィンドウを作成
    QWidget *window = new QWidget;
    window->setWindowTitle("QListWidget サンプル");

    // QListWidget を作成
    QListWidget *listWidget = new QListWidget;

    // アイテムをいくつか追加
    // 文字列だけで追加することも可能 (内部でQListWidgetItemが作成される)
    listWidget->addItem("りんご");
    listWidget->addItem("バナナ");
    listWidget->addItem("オレンジ");

    // QListWidgetItem を自分で作成して追加することも可能
    QListWidgetItem *item4 = new QListWidgetItem("ぶどう");
    listWidget->addItem(item4);

    // アイコン付きのアイテムを追加
    QListWidgetItem *item5 = new QListWidgetItem(QIcon(":/icons/star.png"), "星"); // 適切なアイコンパスに置き換えてください
    listWidget->addItem(item5);

    // レイアウトにリストウィジェットを追加
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(listWidget);
    window->setLayout(layout);

    window->show();

    return app.exec();
}

ポイント

  • new QListWidgetItem(...) で作成したアイテムは、listWidget->addItem(item); で追加すると、listWidget がそのアイテムの所有権を持つため、手動で delete item; を呼び出す必要はありません。
  • listWidget->addItem("文字列"); のように文字列を直接渡すと、Qtが内部的に new QListWidgetItem(文字列) を呼び出してアイテムを作成し、所有権を持ちます。

すべてのアイテムを走査(取得)する

QListWidget::count()QListWidget::item(int row) を組み合わせて、すべてのアイテムにアクセスします。

#include <QApplication>
#include <QListWidget>
#include <QListWidgetItem>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug> // デバッグ出力用

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

    QWidget *window = new QWidget;
    window->setWindowTitle("QListWidget アイテム走査");

    QListWidget *listWidget = new QListWidget;
    listWidget->addItem("北海道");
    listWidget->addItem("青森県");
    listWidget->addItem("東京都");
    listWidget->addItem("大阪府");

    // すべてのアイテムを走査して、テキストを出力する
    qDebug() << "--- すべてのアイテム ---";
    for (int i = 0; i < listWidget->count(); ++i) {
        QListWidgetItem *item = listWidget->item(i);
        if (item) { // item が nullptr でないことを確認
            qDebug() << "行" << i << ":" << item->text();
        }
    }

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(listWidget);
    window->setLayout(layout);
    window->show();

    return app.exec();
}

選択されているアイテムを取得する

QListWidget::selectedItems() を使用します。この関数は、選択されている QListWidgetItem のポインタのリスト (QList<QListWidgetItem*>) を返します。

#include <QApplication>
#include <QListWidget>
#include <QListWidgetItem>
#include <QVBoxLayout>
#include <QPushButton>
#include <QWidget>
#include <QDebug>
#include <QMessageBox>

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

    QWidget *window = new QWidget;
    window->setWindowTitle("QListWidget 選択アイテム");

    QListWidget *listWidget = new QListWidget;
    listWidget->setSelectionMode(QAbstractItemView::MultiSelection); // 複数選択を許可
    listWidget->addItem("Apple");
    listWidget->addItem("Banana");
    listWidget->addItem("Cherry");
    listWidget->addItem("Date");
    listWidget->addItem("Elderberry");

    QPushButton *showSelectedButton = new QPushButton("選択アイテムを表示");

    QObject::connect(showSelectedButton, &QPushButton::clicked, [&]() {
        QList<QListWidgetItem*> selectedItems = listWidget->selectedItems();
        if (selectedItems.isEmpty()) {
            QMessageBox::information(window, "情報", "何も選択されていません。");
            return;
        }

        QString selectedText;
        for (QListWidgetItem *item : selectedItems) {
            selectedText += item->text() + "\n";
        }
        QMessageBox::information(window, "選択されたアイテム", selectedText);
    });

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(listWidget);
    layout->addWidget(showSelectedButton);
    window->setLayout(layout);
    window->show();

    return app.exec();
}

特定のアイテムを検索する

QListWidget::findItems(const QString &text, Qt::MatchFlags flags) を使用して、指定されたテキストに一致するアイテムを見つけます。

#include <QApplication>
#include <QListWidget>
#include <QListWidgetItem>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QWidget>
#include <QDebug>
#include <QMessageBox>

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

    QWidget *window = new QWidget;
    window->setWindowTitle("QListWidget アイテム検索");

    QListWidget *listWidget = new QListWidget;
    listWidget->addItem("ファイル1.txt");
    listWidget->addItem("画像2.jpg");
    listWidget->addItem("ドキュメント.pdf");
    listWidget->addItem("ファイル3.txt");
    listWidget->addItem("Report.docx");

    QLineEdit *searchTextEdit = new QLineEdit;
    searchTextEdit->setPlaceholderText("検索キーワードを入力");
    QPushButton *searchButton = new QPushButton("検索");

    QObject::connect(searchButton, &QPushButton::clicked, [&]() {
        QString searchText = searchTextEdit->text();
        if (searchText.isEmpty()) {
            QMessageBox::warning(window, "警告", "検索キーワードを入力してください。");
            return;
        }

        // 大文字小文字を区別せず、部分一致で検索
        QList<QListWidgetItem*> foundItems = listWidget->findItems(searchText, Qt::MatchContains | Qt::CaseInsensitive);

        if (foundItems.isEmpty()) {
            QMessageBox::information(window, "結果", QString("'%1' に一致するアイテムは見つかりませんでした。").arg(searchText));
        } else {
            QString resultText = QString("'%1' に一致するアイテム:\n").arg(searchText);
            for (QListWidgetItem *item : foundItems) {
                resultText += "- " + item->text() + "\n";
                item->setSelected(true); // 検索されたアイテムを選択状態にする
            }
            QMessageBox::information(window, "結果", resultText);
        }
    });

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(listWidget);
    layout->addWidget(searchTextEdit);
    layout->addWidget(searchButton);
    window->setLayout(layout);
    window->show();

    return app.exec();
}

QListWidget::takeItem(int row) を使用すると、アイテムをリストから取り除き、そのポインタを返します。この場合、開発者がそのアイテムのメモリを解放する責任があります。

#include <QApplication>
#include <QListWidget>
#include <QListWidgetItem>
#include <QVBoxLayout>
#include <QPushButton>
#include <QWidget>
#include <QDebug>
#include <QMessageBox>

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

    QWidget *window = new QWidget;
    window->setWindowTitle("QListWidget アイテム削除");

    QListWidget *listWidget = new QListWidget;
    listWidget->addItem("Item A");
    listWidget->addItem("Item B");
    listWidget->addItem("Item C");
    listWidget->addItem("Item D");

    QPushButton *deleteSelectedButton = new QPushButton("選択アイテムを削除");
    QPushButton *clearAllButton = new QPushButton("すべてクリア");

    // 選択されたアイテムを削除
    QObject::connect(deleteSelectedButton, &QPushButton::clicked, [&]() {
        // 選択されているアイテムを逆順に処理することで、インデックスのずれを防ぐ
        QList<QListWidgetItem*> selectedItems = listWidget->selectedItems();
        for (int i = selectedItems.size() - 1; i >= 0; --i) {
            QListWidgetItem *item = selectedItems.at(i);
            int row = listWidget->row(item); // アイテムの現在の行を取得
            if (row != -1) {
                QListWidgetItem *takenItem = listWidget->takeItem(row);
                if (takenItem) {
                    qDebug() << "削除されたアイテム:" << takenItem->text();
                    delete takenItem; // takeItem() で取得したアイテムは手動で解放
                }
            }
        }
    });

    // すべてのアイテムをクリア
    QObject::connect(clearAllButton, &QPushButton::clicked, [&]() {
        listWidget->clear(); // すべてのアイテムを削除し、メモリも解放される
        qDebug() << "すべてのアイテムがクリアされました。";
    });

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(listWidget);
    layout->addWidget(deleteSelectedButton);
    layout->addWidget(clearAllButton);
    window->setLayout(layout);
    window->show();

    return app.exec();
}
  • selectedItems() を削除する際は、インデックスのずれを防ぐために逆順に処理するのが一般的です。
  • QListWidget::takeItem(int row) は、指定された行のアイテムをリストから取り除き、そのポインタを返します。この場合、QListWidget はそのアイテムの所有権を放棄するため、開発者はそのアイテムが不要になったときに delete を呼び出してメモリを解放する必要があります。takeItem() で取得したアイテムを別の QListWidget に追加するなど、引き続き使用する場合は delete は不要です。
  • QListWidget::clear() を呼び出すと、リスト内のすべての QListWidgetItem が削除され、対応するメモリも自動的に解放されます。


QListWidget を使い続けるが、より高度な機能を利用する

QListWidget 自体にも、単純なテキスト表示だけでなく、アイテムのカスタマイズやイベントハンドリングのための機能が備わっています。

  • setItemWidget() を用いたカスタムウィジェットの埋め込み
    QListWidgetItem の代わりに、任意の QWidget をリストの各行に表示させることができます。これにより、リストアイテム内にボタン、プログレスバー、複数のラベルなどを自由に配置できます。

    #include <QApplication>
    #include <QListWidget>
    #include <QListWidgetItem>
    #include <QVBoxLayout>
    #include <QHBoxLayout>
    #include <QLabel>
    #include <QPushButton>
    #include <QWidget>
    #include <QDebug>
    
    int main(int argc, char *argv[]) {
        QApplication app(argc, argv);
    
        QWidget *window = new QWidget;
        window->setWindowTitle("カスタムアイテムウィジェット");
    
        QListWidget *listWidget = new QListWidget;
    
        for (int i = 0; i < 3; ++i) {
            // アイテム自体を作成 (表示はされませんが、行を管理するために必要)
            QListWidgetItem *listItem = new QListWidgetItem(listWidget);
    
            // 各行に表示するカスタムウィジェットを作成
            QWidget *itemWidget = new QWidget;
            QHBoxLayout *itemLayout = new QHBoxLayout(itemWidget);
            QLabel *label = new QLabel(QString("アイテム %1").arg(i + 1));
            QPushButton *button = new QPushButton("詳細");
    
            itemLayout->addWidget(label);
            itemLayout->addStretch(); // スペーサー
            itemLayout->addWidget(button);
            itemLayout->setContentsMargins(5, 5, 5, 5); // レイアウトのマージン設定
    
            // ボタンクリックのシグナル/スロット接続
            QObject::connect(button, &QPushButton::clicked, [=]() {
                QMessageBox::information(nullptr, "詳細", QString("アイテム %1 の詳細表示").arg(i + 1));
            });
    
            // リストアイテムのサイズヒントを設定 (ウィジェットのサイズに合わせる)
            listItem->setSizeHint(itemWidget->sizeHint());
    
            // アイテムにカスタムウィジェットを設定
            listWidget->setItemWidget(listItem, itemWidget);
        }
    
        QVBoxLayout *layout = new QVBoxLayout(window);
        layout->addWidget(listWidget);
        window->setLayout(layout);
        window->show();
    
        return app.exec();
    }
    

    注意点
    setItemWidget() は静的な内容の表示に適しており、編集可能なカスタムエディタなどを実装する場合は、後述のモデル/ビューアーキテクチャとデリゲートを使う方が適切です。また、大量のアイテムで setItemWidget() を使うとパフォーマンスが低下する可能性があります。

    • setText(), setIcon(), setCheckState(), setFlags() などを利用して、表示されるテキスト、アイコン、チェックボックスの状態、選択・編集可能性などを細かく設定できます。
    • setData() を使用して、アイテムに任意のカスタムデータを関連付けることができます。これにより、表示されているテキストとは異なる、裏側のデータを扱うことができます。
    // 例: カスタムデータを持つアイテム
    QListWidgetItem* item = new QListWidgetItem("商品A");
    item->setData(Qt::UserRole, 100); // Qt::UserRole を使って価格データ (100) を格納
    listWidget->addItem(item);
    
    // 後でデータを取得
    int price = listWidget->item(0)->data(Qt::UserRole).toInt();
    qDebug() << "商品Aの価格:" << price;
    

Qtの最も強力で推奨されるデータ表示方法がモデル/ビューアーキテクチャです。QListWidget はこのアーキテクチャの「便利クラス」であり、内部的に QStandardItemModel を使用しています。より柔軟性やパフォーマンスが必要な場合は、QListView とカスタムモデルを組み合わせます。

利点

  • カスタムデリゲートによる描画/編集の完全な制御
    アイテムの描画や編集をピクセル単位でカスタマイズできます。
  • 柔軟なデータ表示
    同じデータを複数の異なるビュー(リスト、テーブル、ツリーなど)で表示したり、ソートやフィルタリングといったプロキシモデルを簡単に適用したりできます。
  • 大規模データセットの効率的な処理
    数百万行といった大量のデータを扱う場合でも、ビューは画面に表示される部分のみを描画するため、非常に高いパフォーマンスを発揮します。
  • データと表示の分離
    データ(モデル)と表示(ビュー)が完全に分離されるため、コードの保守性、再利用性が向上します。

主要コンポーネント

  • デリゲート (QStyledItemDelegate を継承)
    ビュー内の各アイテムの描画方法を決定し、必要に応じてアイテムの編集用ウィジェットを提供します。
  • ビュー (QListView)
    モデルからデータを取得し、それをユーザーに表示します。ユーザーからの入力(選択、クリックなど)も処理します。
  • モデル (QAbstractListModel を継承)
    データの格納、取得、変更、役割 (roles) の定義など、データに関するすべてのロジックを管理します。

簡単な例 (QListView + QStringListModel)
QStringListModel は、QStringList をモデルとして表示するためのQt標準のモデルです。

#include <QApplication>
#include <QListView>
#include <QStringListModel>
#include <QVBoxLayout>
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QInputDialog> // 入力ダイアログ用

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

    QWidget *window = new QWidget;
    window->setWindowTitle("QListView とモデル");

    // モデルを作成し、データを設定
    QStringListModel *model = new QStringListModel(listWidget); // 親オブジェクトを渡す
    QStringList data;
    data << "アイテム 1" << "アイテム 2" << "アイテム 3";
    model->setStringList(data);

    // ビューを作成し、モデルを設定
    QListView *listView = new QListView;
    listView->setModel(model);

    // アイテム追加ボタン
    QPushButton *addButton = new QPushButton("アイテム追加");
    QObject::connect(addButton, &QPushButton::clicked, [&]() {
        bool ok;
        QString text = QInputDialog::getText(window, "新しいアイテム", "アイテム名:", QLineEdit::Normal, "", &ok);
        if (ok && !text.isEmpty()) {
            int row = model->rowCount(); // 末尾に追加
            model->insertRows(row, 1);
            QModelIndex index = model->index(row);
            model->setData(index, text);
        }
    });

    // 選択アイテム削除ボタン
    QPushButton *deleteButton = new QPushButton("選択アイテム削除");
    QObject::connect(deleteButton, &QPushButton::clicked, [&]() {
        QModelIndexList selectedIndexes = listView->selectionModel()->selectedIndexes();
        // 選択されたインデックスを逆順に処理することで、削除によるインデックスのずれを防ぐ
        for (int i = selectedIndexes.size() - 1; i >= 0; --i) {
            model->removeRows(selectedIndexes.at(i).row(), 1);
        }
    });

    QVBoxLayout *layout = new QVBoxLayout(window);
    layout->addWidget(listView);
    layout->addWidget(addButton);
    layout->addWidget(deleteButton);
    window->setLayout(layout);
    window->show();

    return app.exec();
}

カスタムモデル (QAbstractListModel の継承)
より複雑なデータ構造(例: 複数のプロパティを持つオブジェクトのリスト)を表示したい場合は、QAbstractListModel を継承して独自のモデルを実装します。

主なオーバーライド関数:

  • setData(...): データを変更する。
  • headerData(...): ヘッダーのデータを返す。
  • flags(const QModelIndex &index) const: アイテムのフラグ(選択可能、編集可能など)を返す。
  • data(const QModelIndex &index, int role = Qt::DisplayRole) const: 指定されたインデックスと役割に対応するデータを返す。
  • rowCount(const QModelIndex &parent = QModelIndex()) const: 行数を返す。

このアプローチは、初期学習コストは高いですが、Qtで複雑なリスト表示を扱う上での最も強力で柔軟な方法です。

リスト形式の表示とは少し異なりますが、用途によってはこれらのウィジェットも代替となり得ます。

  • QTreeWidget / QTreeView

    • 階層的なデータを表示したい場合に利用します。
    • QTreeWidget は項目ベースで、QTreeView はモデル/ビューアーキテクチャの一部です。
  • QTableWidget / QTableView

    • QListWidget が単一列のリストであるのに対し、QTableWidgetQTableView は複数列の表形式でデータを表示できます。
    • QTableWidgetQListWidget と同様に項目ベースのクラスで、手軽に表を作成できます。
    • QTableView はモデル/ビューアーキテクチャの一部であり、カスタムモデルと組み合わせて非常に柔軟な表表示を実現します。
  • 大量のデータ、複雑なデータ構造、高度なカスタマイズ、パフォーマンスが要求される場合
    Qtのモデル/ビューアーキテクチャ(QListView + QAbstractListModel または QStandardItemModel + カスタムデリゲート)を使用することを強く推奨します。これはQtの真骨頂であり、より柔軟で拡張性の高いアプリケーションを構築できます。
  • 非常にシンプルで、アイテム数が少ない(数十〜数百程度)場合
    QListWidget が最も手軽で十分な機能を提供します。特に、項目ごとにカスタムウィジェットを表示したい場合は setItemWidget() が便利です。