Я не знаю, делаю ли я что-то не так в своем коде 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
Сигнал только для предметов уровня «item1 -…» (предметы первого уровня), но не для предметов уровня item2 / 3.
Зачем? И как я могу сделать это правильно?
PS: тот же код с QTreeWidget работает отлично, но я использую многопоточность в своем приложении, и мне нужно разделить модель и представление. Элементы QTreeWidget не могут быть созданы в потоке, отличном от графического интерфейса, и qtreewidget не может использовать самостоятельно созданную модель. Вот почему я должен использовать QTreeView с QStandardItem.
Я только что отладил ситуацию, причина, по которой вы не получаете сигнал, заключается в следующем: когда данные элемента изменяются, вы получаете это в источнике 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);
}
}
}
Я не уверен, почему по умолчанию моды дочерних элементов не вызывают «изменение» родительского элемента. Я полагаю, что в качестве обходного пути вы могли бы соединить каждого ребенка 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()
Я не проверял это, но предполагая, что сигнал itemChanged () item1 работает для вас (что предлагают ваши комментарии), тогда это должно сработать.
редактировать
Ах, я думаю, что это может на самом деле не работать, как вы хотите. Я думаю, что вы всегда будете получать указатель item1 на ваш слот onChanged (). Если вы хотите, чтобы указатель item3 был отправлен, вам, возможно, придется подкласс QStandardItem (создать класс, который наследует QStandardItem), а затем выполнить следующее:
itemChanged(QStandardItem*)
void itemHasChanged() {emit itemChanged(this);}
Тогда в вашем цикле вы можете item1 = new myQStandardItem;
А затем для каждого добавляемого вами нового элемента напрямую подключите его к вашему слоту onChanged ():
QObject::connect(itemX, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(onChanged(QStandardItem*)));
Это немного дополнительные усилия (но не слишком много), если вы не можете заставить модель сделать это за вас (то есть план-B) …