【初心者向け】Qt Widgets: ツリーウィジェットでアイテム展開を自在に操る!QTreeWidget::itemExpanded()のしくみとサンプルコード


QTreeWidget::itemExpanded()は、Qt WidgetsライブラリにおけるQTreeWidgetクラスのシグナルであり、ツリーウィジェット内のアイテムが展開されたときに発生します。このシグナルは、アイテムの展開状態を監視したり、展開されたアイテムに応じて処理を実行したりするために使用されます。

シグナルの引数

QTreeWidget::itemExpanded()シグナルは、1つの引数を受け取ります。

  • QTreeWidgetItem* item: 展開されたアイテムを表すポインタ

シグナルの接続

QTreeWidget::itemExpanded()シグナルをスロットに接続するには、QObject::connect()関数を使用します。以下の例は、itemExpanded()シグナルをmySlot()スロットに接続する方法を示しています。

QObject::connect(treeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)),
                 this, SLOT(mySlot(QTreeWidgetItem*)));

スロットの実装

mySlot()スロットは、QTreeWidgetItem*型の引数を受け取ります。この引数は、展開されたアイテムを表します。スロット内では、展開されたアイテムに関する処理を実行できます。

void mySlot(QTreeWidgetItem* item)
{
    // 展開されたアイテムに関する処理
    qDebug() << "Item expanded:" << item->text(0);
}

以下の例は、QTreeWidget内のアイテムが展開されたときに、アイテムのテキストをコンソールに出力するコードを示しています。

#include <QApplication>
#include <QTreeWidget>

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

    QTreeWidget treeWidget;
    treeWidget.setWindowTitle("Tree Widget");

    QTreeWidgetItem* rootItem = treeWidget.addItem("Root");
    QTreeWidgetItem* childItem1 = rootItem->addChild("Child 1");
    QTreeWidgetItem* childItem2 = rootItem->addChild("Child 2");

    QObject::connect(&treeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)),
                     &treeWidget, SLOT(mySlot(QTreeWidgetItem*)));

    treeWidget.show();

    return app.exec();
}

void mySlot(QTreeWidgetItem* item)
{
    qDebug() << "Item expanded:" << item->text(0);
}

このコードを実行すると、Rootアイテムをクリックすると、Child 1Child 2アイテムが展開され、コンソールに"Item expanded: Root"と"Item expanded: Child 1"と"Item expanded: Child 2"というメッセージが出力されます。

  • QTreeWidget::setItemExpanded()関数を使用して、アイテムを強制的に展開または折りたたむことができます。
  • QTreeWidget::isItemExpanded()関数を使用して、アイテムが展開されているかどうかを確認できます。


アイテムのテキストを取得する

void mySlot(QTreeWidgetItem* item)
{
    qDebug() << "Item expanded:" << item->text(0);
}

展開されたアイテムの子アイテムをすべて展開する

以下のコードは、itemExpanded()シグナル内で展開されたアイテムの子アイテムをすべて展開する例です。

void mySlot(QTreeWidgetItem* item)
{
    item->expandAll();
}

展開されたアイテムの背景色を変更する

以下のコードは、itemExpanded()シグナル内で展開されたアイテムの背景色を変更する例です。

void mySlot(QTreeWidgetItem* item)
{
    item->setBackgroundColor(QColor(Qt::lightBlue));
}

展開されたアイテムにアイコンを設定する

以下のコードは、itemExpanded()シグナル内で展開されたアイテムにアイコンを設定する例です。

void mySlot(QTreeWidgetItem* item)
{
    item->setIcon(0, QIcon(":/images/folder.png"));
}

以下のコードは、itemExpanded()シグナル内で展開されたアイテムに応じてカスタム処理を実行する例です。

void mySlot(QTreeWidgetItem* item)
{
    if (item->text(0) == "Child 1") {
        // Child 1 アイテムが展開された場合の処理
        qDebug() << "Child 1 item expanded";
    } else if (item->text(0) == "Child 2") {
        // Child 2 アイテムが展開された場合の処理
        qDebug() << "Child 2 item expanded";
    }
}


QModelIndex::dataChanged()シグナルを使用する

QModelIndex::dataChanged()シグナルは、モデル内のデータが変更されたときに発生します。このシグナルを監視することで、アイテムの展開状態の変化を検知できます。

QObject::connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
                 this, SLOT(mySlot(QModelIndex, QModelIndex)));

mySlot()スロットでは、dataChanged()シグナルの引数として渡されるQModelIndexオブジェクトを使用して、変更されたアイテムと列を特定できます。

void mySlot(const QModelIndex&topLeft, const QModelIndex& bottomRight)
{
    if (topLeft.column() == QTreeWidget::isExpandedColumn()) {
        // 展開状態が変更された
        QTreeWidgetItem* item = model->itemFromIndex(topLeft);
        if (item) {
            qDebug() << "Item expanded:" << item->text(0);
        }
    }
}

タイマーを使用して定期的にアイテムの状態をチェックする

タイマーを使用して定期的にアイテムの状態をチェックすることで、QTreeWidget::itemExpanded()シグナルを明示的に接続しなくても、アイテムの展開状態を監視できます。

QTimer timer(this);
timer.setInterval(100); // 100ミリ秒ごとにチェック
connect(&timer, SIGNAL(timeout()), this, SLOT(checkItemStates()));

void checkItemStates()
{
    for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) {
        QTreeWidgetItem* item = treeWidget->topLevelItem(i);
        if (item->isExpanded()) {
            qDebug() << "Item expanded:" << item->text(0);
        }
    }
}

カスタムフラグを使用して展開状態を管理する

各アイテムにカスタムフラグを設定し、そのフラグを使用して展開状態を管理する方法もあります。

struct ItemData {
    QString text;
    bool expanded;
};

QVector<ItemData> items;

// ...

void mySlot(QTreeWidgetItem* item)
{
    ItemData& data = items[item->row()];
    data.expanded = !data.expanded;
    item->setExpanded(data.expanded);
}

この方法は、シグナルやタイマーを使用せずに、アイテムの展開状態を柔軟に制御できます。

最適な代替方法の選択

どの代替方法が最適かは、状況によって異なります。

  • 柔軟性を重視する場合は: カスタムフラグを使用して展開状態を管理する方法がおすすめです。
  • パフォーマンスが重要: タイマーを使用して定期的にアイテムの状態をチェックする方法がおすすめです。
  • シンプルさを重視する場合は: QModelIndex::dataChanged()シグナルを使用するのがおすすめです。
  • カスタムフラグを使用した方法は、コードが複雑になる可能性があります。
  • パフォーマンス上の理由から、タイマーを使用した方法は、大量のアイテムを扱う場合に適していない場合があります。
  • 上記の代替方法は、あくまでも例であり、状況に合わせて調整する必要があります。