Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: AD от Февраль 24, 2009, 17:24



Название: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 17:24
Есть дерево, представленное QTreeWidget. Пытаюсь сделать так, чтобы при нажатии на checkbox элемента дерева, отмечались/разотмечались соответствующие узлы дерева. Короче говоря, хотелось бы, чтобы это работало стандартно: если отмечают корень - отмечаются все узлы и листья, если отмечают узел - отмечаются все листья этого узла, если разотмечают (убирают отметку) у листа, то если это единственный лист, то снимается отметка с узла и т.д.

Код, который я написал, работает неправильно. Сможете помочь сделать верно или же подскажите, где взять готовый код? Это ведь стандартная вещь?
Код
C++ (Qt)
/// Где-то
connect(treePhaseView, SIGNAL(itemPressed(QTreeWidgetItem*, int)), this, SLOT(treeItemPress(QTreeWidgetItem*, int)));
 
/// Нажатие на элемент дерева
void TLV::treeItemPress(QTreeWidgetItem* item, int column)
{
if(item == 0) return;
for(register int i=0; i<item -> childCount(); ++i)
{
QTreeWidgetItem* childItem = item -> child(i);
if(childItem == 0) continue;
Qt::CheckState check = (childItem -> checkState(column) == 2 || childItem -> checkState(column) == 1) ?
Qt::Unchecked : Qt::Checked;
childItem -> setCheckState(column, check);
treeItemPress(childItem, column);
}
QTreeWidgetItem* parentItem = item -> parent();
if(parentItem == 0) return;
Qt::CheckState check = (parentItem -> checkState(column) == 2 || parentItem -> checkState(column) == 1) ?
Qt::Unchecked : Qt::Checked;
parentItem -> setCheckState(column, check);
}
 

если что-то непонятно, то  тут (http://www.forum.crossplatform.ru/index.php?showtopic=2261&pid=15228&st=0&#entry15228) можно посмотреть!



Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: spirit от Февраль 24, 2009, 17:37
нет, это не стандартное поведение. нужно реализовывать самому.


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 17:42
Почему не стандартное? В чем нестандартность заключается? Если все-же нестандартное, то поможете реализовать корректно?


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: spirit от Февраль 24, 2009, 17:44
ну в Qt такое поведение не предусмотрено.


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 17:47
За время существования данного элемента в Qt, разве подобная задача не решалась совсем ни разу? Я думаю, решали. Искал гуглом, но не нашел. Может у кого-то уже есть подобное, может поделитесь?


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: pastor от Февраль 24, 2009, 17:50
Первое что кинулось в глаза - это рекурсия. Откройте для себя QTreeWidgetItemIterator


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 17:52
Я клоню к тому, что, наверняка, кто-нибудь уже решал эту задачку. Поделитесь, пожалуйста, кодом. А называю способ стандартным, ну потому что он естественен по идее!!!

Заранее спасибо.


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 18:12
Первое что кинулось в глаза - это рекурсия. Откройте для себя QTreeWidgetItemIterator
А как правильно написать приведенной мною кусок кода? Каким способом этот итератор может помочь?


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: spirit от Февраль 24, 2009, 18:21
по идее так должно работать, не проверял правда :)
Код
C++ (Qt)
...
QTreeWidget *tree = new QTreeWidget;
tree->setColumnCount(1);
 
QTreeWidgetItem *root = new QTreeWidgetItem(QStringList(QString("root")));
root->setCheckState(0, Qt::Unchecked);
tree->insertTopLevelItem(0, root);
 
for (int i = 0; i < 10; ++i) {
QTreeWidgetItem *item = new QTreeWidgetItem(root, QStringList(QString("item: %1").arg(i)));
item->setCheckState(0, Qt::Unchecked);
for (int j = 0; j < 10; ++j) {
QTreeWidgetItem *itm = new QTreeWidgetItem(item, QStringList(QString("item: %1").arg(i)));
itm->setCheckState(0, Qt::Unchecked);
}
}
 
connect(tree, SIGNAL(itemChanged(QTreeWidgetItem *, int)), SLOT(itemChanged(QTreeWidgetItem *, int)));
....
void MyWidget::itemChanged(QTreeWidgetItem *item, int)
{
changeItemState(item);
}
 
void MyWidget::changeItemState(QTreeWidgetItem *item)
{
if (!item)
return;
 
for (int i = 0; i < item->childCount(); ++i) {
QTreeWidgetItem *child = item->child(i);
child->setCheckState(0, item->checkState(0));
changeItemState(child);
}
}
 


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: pastor от Февраль 24, 2009, 18:32
Инеторатор упростит вот этот код:

           
Код
C++ (Qt)
for(register int i=0; i<item -> childCount(); ++i)
{
QTreeWidgetItem* childItem = item -> child(i);
if(childItem == 0) continue;
Qt::CheckState check = (childItem -> checkState(column) == 2 || childItem -> checkState(column) == 1) ?
Qt::Unchecked : Qt::Checked;
childItem -> setCheckState(column, check);
treeItemPress(childItem, column);
}

и будет выглядеть примерно так:

Код
C++ (Qt)
QTreeWidgetItemIterator it(item);
while (*it) {      
   Qt::CheckState check = ((*it) -> checkState(column) == 2 || (*it) -> checkState(column) == 1) ?
Qt::Unchecked : Qt::Checked;
   (*it)->setCheckState(column, check);
   ++it;
}

Но даже в этом коде есть вопросы. Если не исполуется tristate для чек боксов (а судя по коду этот так), тогда ненужна проверка checkState(column) == 1. Более того что из скрина в первом посте видно, что свой-во сheckable используется для первого столбца. Имхо тогда нужно так:

Код
C++ (Qt)
QTreeWidgetItemIterator it(item);
while (*it) {      
   Qt::CheckState check = ((*it) -> checkState(0) == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
   (*it)->setCheckState(0, check);
   ++it;
}


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 18:53
pastor, я правильно Вас понял, что итератор сам пройдется по родительской ветке? Если нет, то в нем не вижу смысла.
А на счет колонки - Вы правильно поняли, но в слоте все-равно есть этот параметр, даже учитывая, что он по-умолчанию 0, поэтому я
Код
C++ (Qt)
пишу setCheckState(column, Qt::Unchecked); // или же Checked
!
spirit, спасибо. Мне понравилось решение с
Код
C++ (Qt)
item -> checkState(column)
. Более элегантно, чем у меня. Принял к сведению.


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 19:07
Вот более адекватный вариант.

Код
C++ (Qt)
/// Нажатие на элемент дерева
void TLV::treeItemPress(QTreeWidgetItem* item, int column)
{
if(item == 0) return;
Qt::CheckState check((item -> checkState(column) == Qt::Checked) ? Qt::Unchecked : Qt::Checked);
for(register int i=0; i<item -> childCount(); ++i)
{
QTreeWidgetItem* childItem = item -> child(i);
if(childItem == 0) continue;
childItem -> setCheckState(column, check);
treeItemPress(childItem, column);
}
QTreeWidgetItem* parentItem = item -> parent();
if(parentItem == 0) return;
parentItem -> setCheckState(column, check);
}

Но все же есть некоторые некорректности:
1) когда я нажимаю на корень, выделяются(снимаются выделения) с узлов, а на листьях - остаются.
2) когда в узле  не один лист, а несколько - то при нажатии на лист - выделение затрагивает и узел.

Я понимаю, что у меня эти ситуации и не учтены в коде. Но вот хотел бы учесть. Буду благодарен за помощь!


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: lit-uriy от Февраль 24, 2009, 19:18
итератор проходит по всем элементам


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 19:28
Цитата: lit-uriy
итератор проходит по всем элементам
Код:
/// Нажатие на элемент дерева
void TLV::treeItemPress(QTreeWidgetItem* item, int column)
{
if(item == 0) return;
Qt::CheckState check((item -> checkState(column) == Qt::Checked) ? Qt::Unchecked : Qt::Checked);
QTreeWidgetItemIterator it(item);
while(*it)
{
(*it) -> setCheckState(column, check);
++it;
}
}
Вот в таком виде - его работа меня меня не устраивает - более неадекватная версия. Результат совсем другой, что в предыдущем коде.


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 19:35
Итератор, который проходит все элементы, начиная с item! Почему он не считает элемент item базовым, т.е. максимальная проходимость - это родитель элемента item? Как обрезать его дальнейший проход?


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 24, 2009, 21:24
Кто-нибудь, помогите, пожалуйста!


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: pastor от Февраль 24, 2009, 22:56
Итератор, который проходит все элементы, начиная с item! Почему он не считает элемент item базовым, т.е. максимальная проходимость - это родитель элемента item? Как обрезать его дальнейший проход?

Что-то неопнятны вопросы... QTreeWidgetItemIterator пройдет по всем подчиненным айтемам и подчиненным айтемам подчиненных айтемов и т.д.  :)

Уточни свои вопросы.

ЗЫ: Приаттач свой компилябельный код, чтобы самому не писать экзампл.


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: Sergeich от Февраль 24, 2009, 23:32
При нажатии на чекбокс выделяюся все потомки, при снятии галочки все дочерние соответсвенно помечаются ненажатыми, плюс прмежуточное состояние, когда отмечено не все:

objecttreemodel.h
Код:
#ifndef OBJECT_TREE_MODEL_H
#define OBJECT_TREE_MODEL_H

#include <QStandardItemModel>

class ObjectTreeModel : public QStandardItemModel
{
Q_OBJECT
public:
ObjectTreeModel( QObject* parent = 0 );
protected slots:
void onItemChanged( QStandardItem* item );
};

#endif // OBJECT_TREE_MODEL_H

objecttreemodel.cpp
Код:
#include "objecttreemodel.h"

ObjectTreeModel::ObjectTreeModel( QObject* parent )
: QStandardItemModel( parent )
{
connect( this, SIGNAL(itemChanged(QStandardItem*)), SLOT(onItemChanged(QStandardItem*)) );
}

void ObjectTreeModel::onItemChanged( QStandardItem* item )
{
if ( !item->isCheckable() || item->column() != 0 )
return;

Qt::CheckState state = item->checkState();
if ( state == Qt::Checked || state == Qt::Unchecked ) {
for ( int i = 0; i < item->rowCount(); i++ ) {
QStandardItem* child = item->child(i);
if ( child->isCheckable() && child->checkState() != state )
child->setCheckState(state);
}
}

QStandardItem* parent = item->parent();
if ( parent && parent->isCheckable() ) {
state = parent->child(0)->checkState();
if ( state == Qt::PartiallyChecked )
parent->setCheckState( state );
else {
int i = 1;
while ( i < parent->rowCount() && parent->child(i)->checkState() == state )
i++;
if ( i != parent->rowCount() )
state = Qt::PartiallyChecked;
parent->setCheckState( state );
}
}

}


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 25, 2009, 10:29
Цитата: Sergeich
При нажатии на чекбокс выделяюся все потомки, при снятии галочки все дочерние соответсвенно помечаются ненажатыми, плюс прмежуточное состояние, когда отмечено не все:
Sergeich, cпасибо. Попробую

Цитировать
Уточни свои вопросы.

ЗЫ: Приаттач свой компилябельный код, чтобы самому не писать экзампл.
Так spirit накатал компилябельный код. Осталось main добавить и усе!
pastor, что именно уточнять и не знаю. Все вроде бы сказал. Мне неясно, почему итератор идет по всем оставшимся после item узлам. Мне казалось, в нем должен быть немного другой принцип работы....


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 25, 2009, 10:41
Sergeich, я правильно понял, что мне следует сделать представление вместо виджета, т.е. QTreeView вместо QTreeWidget. А в качестве модели задать созданную Вами на основе QStandardItemModel?


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: spirit от Февраль 25, 2009, 10:43
имхо, алгоритм Сергеича можно адаптировать к вашей задачи не используя модели.


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 25, 2009, 11:10
Цитата: spirit
имхо, алгоритм Сергеича можно адаптировать к вашей задачи не используя модели.
Это и пытался сделать, но нет у QTreeWidgetItem функции rowCount(), а без нее самому считать? Или как?


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: spirit от Февраль 25, 2009, 11:12
childCount == rowCount


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 25, 2009, 12:42
Sergeich, спасибо большое за идею. Чтобы не использовать модель, по совету spiritа постарался подкорректировать алгоритм под свой QTreeWidgetItem. Единственное, что мне в том алгоритме не нужно было - это третье состояние. Пользователей оно введет в транс, им оно не нужно. Поэтому его нафиг убрал. После обработки напильником, рубанком и наждачной бумагой вышло такое: :)
Код
C++ (Qt)
/// Нажатие на элемент дерева
void TLV::itemPress(QTreeWidgetItem* item, int column)
{
if(item == 0) return;
 
Qt::CheckState state((item -> checkState(column) == Qt::Checked) ? Qt::Unchecked : Qt::Checked);
for(register int i=0; i<item -> childCount(); ++i)
{
QTreeWidgetItem* child = item -> child(i);
if(child == 0) continue;
if(child -> checkState(column) != state) child -> setCheckState(column, state);
for(register int j=0; j<child -> childCount(); ++j)
{
QTreeWidgetItem* grandchild = child -> child(j);
if(grandchild == 0) continue;
if(grandchild -> checkState(column) != state) grandchild -> setCheckState(column, state);
}
}
 
QTreeWidgetItem* parent = item -> parent();
if(parent == 0) return;
parent -> setCheckState(column, state);
}
 

Понимаю, алгоритм получился не самым удачным. Была бы вложенность листьев равна 5-6 или более, то такая штука не прокатила бы, но через рекурсию как было показано в ранних постах, не прокатывает. Если это делать через модель, то думаю, алгоритм Sergeicha подошел бы идеально.
Осталось чуть скорректировать работу отметки предка и все нормуль будет! :)


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: pastor от Февраль 25, 2009, 12:48
Мне неясно, почему итератор идет по всем оставшимся после item узлам.

"после" имеется в виду по тем, которые с ним на одном уровне вложенности?


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 25, 2009, 12:58
Цитировать
"после" имеется в виду по тем, которые с ним на одном уровне вложенности?
Ну не совсем. Проверка всех элементов того же уровня вложенности и его родителя. Не более. Никаких соседей учитывать не надо, а итератор учитывает...


Сделал окончательный вариант. Получилось такое чудо:
Код
C++ (Qt)
/// Нажатие на элемент дерева
void TLV::itemPress(QTreeWidgetItem* item, int column)
{
if(item == 0) return;
 
Qt::CheckState state((item -> checkState(column) == Qt::Checked) ? Qt::Unchecked : Qt::Checked);
for(register int i=0; i<item -> childCount(); ++i)
{
QTreeWidgetItem* child = item -> child(i);
if(child == 0) continue;
if(child -> checkState(column) != state) child -> setCheckState(column, state);
for(register int j=0; j<child -> childCount(); ++j)
{
QTreeWidgetItem* grandchild = child -> child(j);
if(grandchild == 0) continue;
if(grandchild -> checkState(column) != state) grandchild -> setCheckState(column, state);
}
}
 
QTreeWidgetItem* parent = item -> parent();
if(parent == 0) return;
bool all = true;
for(register int i=0; i<parent -> childCount(); ++i)
{
QTreeWidgetItem* child = parent -> child(i);
if(child == 0) break;
if(item != child && child -> checkState(column) != Qt::Unchecked)
{ all = false; break; }
}
if(all) parent -> setCheckState(column, state);
}
 


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: pastor от Февраль 25, 2009, 13:57
Да, с итератором там все понятно.. )))

Немного передалал твой код, вернее только его первую часть. Теперь она способна "выдержать" любой уровень вложенности и без рекурсии. Я законектил этот слот на itemClicked вместо itemPressed (т.к. наблюдались глюки при быстром кликанье на узле)

Код
C++ (Qt)
void TreeWidget::treeItemPress(QTreeWidgetItem *item, int column)
{
   if (!item) return;
 
   Qt::CheckState check = item->checkState(0);
   QList<QTreeWidgetItem *> items;
   items << item;
 
   while (!items.isEmpty()) {
       QTreeWidgetItem *itm = items.takeFirst();
       for (int i = 0; i < itm->childCount(); ++i) {
           QTreeWidgetItem *child = itm->child(i);
           child->setCheckState(0, check);
           items << child;
       }
   }
 
   QTreeWidgetItem* parent = item -> parent();
   if(parent == 0) return;
   bool all = true;
   for(register int i=0; i<parent -> childCount(); ++i)
   {
       QTreeWidgetItem* child = parent -> child(i);
       if(child == 0) break;
       if(item != child && child -> checkState(column) != Qt::Unchecked)
       { all = false; break; }
   }
   if(all) parent -> setCheckState(column, check);
}

Вторую часть кода я не трогал, так как несовсем понял что нужно получить в итоге. Если установлено состояние для айтема как checked то и для родителя устанавливается точно такое-же состояние. А вот для прародтеля нет. И это несовсем понятно (логично).

Я бы восользовался 3 состояниями:

checked - выделены все айтемы
unchecked - не выделен ниодин
partially checked - выделены не все айтемы


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: spirit от Февраль 25, 2009, 14:01
Цитировать
Я бы восользовался 3 состояниями:

checked - выделены все айтемы
unchecked - не выделен ниодин
partially checked - выделены не все айтемы
+1


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 25, 2009, 14:16
Да, с итератором там все понятно.. )))

Немного передалал твой код, вернее только его первую часть. Теперь она способна "выдержать" любой уровень вложенности и без рекурсии. Я законектил этот слот на itemClicked вместо itemPressed (т.к. наблюдались глюки при быстром кликанье на узле)

Вторую часть кода я не трогал, так как несовсем понял что нужно получить в итоге. Если установлено состояние для айтема как checked то и для родителя устанавливается точно такое-же состояние. А вот для прародтеля нет. И это несовсем понятно (логично).

Я бы восользовался 3 состояниями:

checked - выделены все айтемы
unchecked - не выделен ниодин
partially checked - выделены не все айтемы
ООО, вот тоже такие глюки наблюдаю. Спасибо, попробую! :)

Спасибо, попробую этот код. Нет, 3 состояния - перебор. У летчиков мозги съедут. Если хотя-бы один элемент (лист) (т.е. название файла) присутствует в этапе полета (узел), тогда этот элемент выделен. Да и потом на таком принципе удобнее дальнейшую обработку вести (в смысле когда 2 состояния)!


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: spirit от Февраль 25, 2009, 14:18
ну тебе виднее, но логичнее всего и правилнее -- это как сказл pastor иметь три состояния. ;)


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: BRE от Февраль 25, 2009, 14:27
Нет, 3 состояния - перебор. У летчиков мозги съедут.
Это надуманная причина (нельзя недооценивать наших летчиков).  ;D

Да и потом на таком принципе удобнее дальнейшую обработку вести (в смысле когда 2 состояния)!
А вот это явная причина... (удобней тебе).  ;)


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 25, 2009, 14:35
Это надуманная причина (нельзя недооценивать наших летчиков).  ;D

А вот это явная причина... (удобней тебе).  ;)
Да не недооцениваю я летчиков. Сам к ним в некотором роде отношусь! :) Летчики - консерваторы. На старой программе было два состояния. Увидят три состояния испугаются. Не будут понимать, что за 3 состояние, откуда взялось! Чем проще работать с программой, тем большее количество людей ей пользуются....


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: Sergeich от Февраль 25, 2009, 23:50
Насчет кода: код из работающего проекта, писался и отлаживался в течении получаса, причем по моей ленности была использована QStandardItemModel вместо QAbstractItemModel. Вроде работает.
По поводу трех состояний: без третьего никак нельзя. Поясняю: если (не)отмечаются все потомки у родителя ставится (снимается) галочка. Что делать если потомки выбраны через одного? Именно для этого и был придуман т.н. tristate.


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 26, 2009, 12:20
Цитата: Sergeich
Насчет кода: код из работающего проекта, писался и отлаживался в течении получаса, причем по моей ленности была использована QStandardItemModel вместо QAbstractItemModel. Вроде работает.
По поводу трех состояний: без третьего никак нельзя. Поясняю: если (не)отмечаются все потомки у родителя ставится (снимается) галочка. Что делать если потомки выбраны через одного? Именно для этого и был придуман т.н. tristate.
Есть несколько вопросов. В связи с некоторыми деталями при работе с деревом этапов, увиденными сегодня, возникло желание перейти от QTreeWidget к QTreeView. Соответственно, хочется сделать так, как в указанном Вами коде. При этом сделать более корректно, т.е. используя QAbstractItemModel. Но проблема в том, что у этого класса нет сигнала itemChanged и им подобных. Как поступить в этом случае?


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: spirit от Февраль 26, 2009, 12:23
как это нету? все есть  :)
Цитировать
void QAbstractItemModel::dataChanged ( const QModelIndex & topLeft, const QModelIndex & bottomRight )
This signal is emitted whenever the data in an existing item changes. The affected items are those between topLeft and bottomRight inclusive (of the same parent).
Note that this signal must be emitted explicitly when reimplementing the setData() function.
See also headerDataChanged(), setData(), and layoutChanged().


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: pastor от Февраль 26, 2009, 12:32
Есть несколько вопросов. В связи с некоторыми деталями при работе с деревом этапов, увиденными сегодня, возникло желание перейти от QTreeWidget к QTreeView. Соответственно, хочется сделать так, как в указанном Вами коде. При этом сделать более корректно, т.е. используя QAbstractItemModel.

А зачем переходить на QTreeView? Помоему QTreeWidget справляется с задачей неплохо, или ваша задача подразумевает оч большой объем данных?


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 26, 2009, 14:14
Посмотрел я на QAbstractItemModel и решил, что запутаюсь - решил, остаться на QStandardItemModel! :)

А зачем переходить на QTreeView? Помоему QTreeWidget справляется с задачей неплохо, или ваша задача подразумевает оч большой объем данных?
Дело в том, что при переходе на модель-представление, очень большой кусок кода вынесется из класса TLV, который и так чересчур большой. Да и обработка отдельно взятого элемента, а не списка мне будет удобнее.


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: AD от Февраль 26, 2009, 16:06
Насчет кода: код из работающего проекта, писался и отлаживался в течении получаса, причем по моей ленности была использована QStandardItemModel вместо QAbstractItemModel. Вроде работает.
По поводу трех состояний: без третьего никак нельзя. Поясняю: если (не)отмечаются все потомки у родителя ставится (снимается) галочка. Что делать если потомки выбраны через одного? Именно для этого и был придуман т.н. tristate.
Еще раз спасибо. Сделал через модель - представление. Подставил Ваш класс. Все работает на ура! :))))


Название: Re: QTreeWidget - нажатие на узел дерева
Отправлено: Makss от Июль 30, 2010, 21:21
тоже понадобилось такая весч, реализовывал сам, потом тему эту увидил, вот выкладываю, мож кому понадобится:
Код:
    if(item->checkState(0) == Qt::Checked) {
        selectItem(item);
    } else if(item->checkState(0) == Qt::Unchecked) {
        unselectItem(item);
    }
    QTreeWidgetItem *it = item;
    while(it->parent()) {
        const int count = it->parent()->childCount();
        bool hasPartiallyChecked = false,
             hasChecked = false,
             hasUnchecked = false;
        for(int i = 0; i < count; i++) {
            QTreeWidgetItem *itt = it->parent()->child(i);
            switch (itt->checkState(0)) {
            case Qt::Checked: hasChecked = true; break;
            case Qt::Unchecked: hasUnchecked = true; break;
            case Qt::PartiallyChecked: hasPartiallyChecked = true; break;
            }

            if(hasPartiallyChecked || (hasChecked && hasUnchecked)) {
                hasPartiallyChecked = true;
                break;
            }
        }
        it->parent()->setCheckState(0, hasPartiallyChecked ? Qt::PartiallyChecked :
                                    (!hasChecked ? Qt::Unchecked : Qt::Checked));
        if(it->parent()->checkState(0) == Qt::Checked ||
           it->parent()->checkState(0) == Qt::Unchecked) {
            for(int i = 0; i < count; i++) {
                it->parent()->child(i)->setCheckState(0, it->parent()->checkState(0));
            }
        }
        it = it->parent();
    }

Функции selectItem и unselectItem ставят и убирают соответственно, галочки у дочерних элементов,думаю ни кому не составит труда их написать, поэтому их не выкладываю

Код вполне рабочий, по крайней мере ситуаций отличных от правильной работы я не встречал