4

私のqtコードで何か間違ったことをしたかどうかはわかりません。itemChangedアイテムデータが変更されるたびにシグナルが発行される必要があります。次のコードを使用してモデルを作成します。

QStandardItemModel* model = new QStandardItemModel;
QStandardItem *parentItem = model->invisibleRootItem();
QList<QStandardItem*> itemList1;
QList<QStandardItem*> itemList2;
QList<QStandardItem*> itemList3;
QStandardItem* item1;
QStandardItem* item2;
QStandardItem* item3;

for (int i = 0; i < 3; ++i)
{
    item1 = new QStandardItem;
    item1->setText("item1-" + QString::number(i));

    for (int i = 0; i < 3; ++i)
    {
        item2 = new QStandardItem;
        item2->setText("item2-" + QString::number(i));

        for (int i = 0; i < 3; ++i)
        {
            item3 = new QStandardItem;
            item3->setText("item3-" + QString::number(i));
            itemList3 << item3;
        }
        item2->appendRows(itemList3);
        itemList3.clear();
        itemList2 << item2;
    }
    item1->appendRows(itemList2);
    itemList2.clear();
    itemList1 << item1;
}
parentItem->appendRows(itemList1);
itemList1.clear();

ui.treeView->setModel(model);

QObject::connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(onChanged(QStandardItem*)));

onChangedそして、アイテムが変更されるたびに呼び出されるようにしたいです-たとえば、アイテムのテキストが編集されたり、チェックボックスがクリックされたりします。しかし、いずれの場合もitemChanged、item2/3 レベルのアイテムではなく、"item1-..." レベルのアイテム (第 1 レベルのアイテム) でのみシグナルをトリガーしました。なんで?そして、どうすればそれを正しくすることができますか?

PS: QTreeWidget を使用した同じコードは完全に機能しますが、アプリでマルチスレッドを使用しているため、モデルとビューを分割する必要があります。QTreeWidget アイテムは非 GUI スレッドで作成できず、qtreewidget は自己作成モデルを使用できません。これが、QStandardItem で QTreeView を使用しなければならない理由です。

4

2 に答える 2

5

状況をデバッグしたところ、シグナルを取得できない理由は次のとおりです。アイテムのデータが変更されると、Qt ソースに次のように表示されます。

void QStandardItem::setData(...)
{
   /* ... */
   if (d->model)
       d->model->d_func()->itemChanged(this);
}

一方、子アイテムを親に追加するときは、

bool QStandardItemPrivate::insertRows(int row, const QList<QStandardItem*> &items)
{
   /* ... */
   for (int i = 0; i < items.count(); ++i) {
     /* ... */
       item->d_func()->model = model;
   }
}

つまり、アイテムには変更についてモデルに通知するためのモデルへのポインターが必要であり、子アイテムのモデルは挿入時に親のアイテムに設定されます。ここで、最初に子を親に追加し、次に親を親に追加します。非表示のルートがレベル 1 アイテムの親になります。目に見えないルートにはモデルがあるため、レベル 1 のアイテムは信号を送信しますが、他のアイテムは送信しません。

簡単な変更でこれが修正されます: 次のように、最初に項目をその親に追加してから、子を追加します。

for (int i = 0; i < 3; ++i)
{
    item1 = new QStandardItem;
    item1->setText("item1-" + QString::number(i));
    parentItem->appendRow(item1);

    for (int i = 0; i < 3; ++i)
    {
        item2 = new QStandardItem;
        item2->setText("item2-" + QString::number(i));
        item1->appendRow(item2);

        for (int i = 0; i < 3; ++i)
        {
            item3 = new QStandardItem;
            item3->setText("item3-" + QString::number(i));
            item2->appendRow(item3);
        }
    }
}
于 2016-06-13T11:50:54.770 に答える
1

親アイテムが「変更」されない子アイテム mod のデフォルトがなぜなのか、私にはわかりません。回避策として、各子DataChanged()信号をその親DataChanged()信号に接続して、信号が階層を上って伝播するようにすることができると思います。

for (int i = 0; i < 3; ++i)
{
    item1 = new QStandardItem;
    item1->setText("item1-" + QString::number(i));

    for (int i = 0; i < 3; ++i)
    {
        item2 = new QStandardItem;
        item2->setText("item2-" + QString::number(i));

        for (int i = 0; i < 3; ++i)
        {
            item3 = new QStandardItem;
            item3->setText("item3-" + QString::number(i));
            itemList3 << item3;
            connect(item3, SIGNAL(DataChanged()), item2, SIGNAL(DataChanged()));
        }
        item2->appendRows(itemList3);
        itemList3.clear();
        itemList2 << item2;
        connect(item2, SIGNAL(DataChanged()), item1, SIGNAL(DataChanged()));
    }
    item1->appendRows(itemList2);
    itemList2.clear();
    itemList1 << item1;
}

何が起こるかというと、item3 レベルのレコードを変更すると、シグナルは item1 までずっと転送され (これは機能していると思われます)、その後は通常どおり続行されます。

item3 ---DataChanged()---> item2
item2 ---DataChanged()---> item1
item1 ---DataChanged()---> model
model ---itemChanged()---> onChanged()

私はこれをテストしていませんが、 item1 dataChanged() シグナルが機能していると仮定すると(コメントが示唆しています)、これは機能するはずです。

編集

ああ、これは実際には思い通りにいかないかもしれないと思います。onChanged() スロットに送信される item1 ポインターを常に取得すると思います。item3 ポインターを送信したい場合は、QStandardItem をサブクラス化し (QStandardItem を継承するクラスを作成)、次の操作を行う必要があります。

  • 以下を発するシグナルを追加します。itemChanged(QStandardItem*)
  • スロットを追加します:void itemHasChanged() {emit itemChanged(this);}
  • コンストラクターで dataChanged() を itemHasChanged() に接続します。

次に、ループで次のことができます。次に、item1 = new myQStandardItem; 追加する新しいアイテムごとに、それらを onChanged() スロットに直接接続します。

QObject::connect(itemX, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(onChanged(QStandardItem*)));

モデルにそれを実行させることができない場合 (つまり、プラン B)...

于 2016-06-13T08:38:59.153 に答える