Russian Qt Forum
Июнь 16, 2024, 02:27 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: QTreeWidget - нажатие на узел дерева  (Прочитано 29805 раз)
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);
}
 

если что-то непонятно, то тут можно посмотреть!

Записан
spirit
Гость
« Ответ #1 : Февраль 24, 2009, 17:37 »

нет, это не стандартное поведение. нужно реализовывать самому.
Записан
AD
Гость
« Ответ #2 : Февраль 24, 2009, 17:42 »

Почему не стандартное? В чем нестандартность заключается? Если все-же нестандартное, то поможете реализовать корректно?
Записан
spirit
Гость
« Ответ #3 : Февраль 24, 2009, 17:44 »

ну в Qt такое поведение не предусмотрено.
Записан
AD
Гость
« Ответ #4 : Февраль 24, 2009, 17:47 »

За время существования данного элемента в Qt, разве подобная задача не решалась совсем ни разу? Я думаю, решали. Искал гуглом, но не нашел. Может у кого-то уже есть подобное, может поделитесь?
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #5 : Февраль 24, 2009, 17:50 »

Первое что кинулось в глаза - это рекурсия. Откройте для себя QTreeWidgetItemIterator
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
AD
Гость
« Ответ #6 : Февраль 24, 2009, 17:52 »

Я клоню к тому, что, наверняка, кто-нибудь уже решал эту задачку. Поделитесь, пожалуйста, кодом. А называю способ стандартным, ну потому что он естественен по идее!!!

Заранее спасибо.
Записан
AD
Гость
« Ответ #7 : Февраль 24, 2009, 18:12 »

Первое что кинулось в глаза - это рекурсия. Откройте для себя QTreeWidgetItemIterator
А как правильно написать приведенной мною кусок кода? Каким способом этот итератор может помочь?
Записан
spirit
Гость
« Ответ #8 : Февраль 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);
}
}
 
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #9 : Февраль 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;
}
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
AD
Гость
« Ответ #10 : Февраль 24, 2009, 18:53 »

pastor, я правильно Вас понял, что итератор сам пройдется по родительской ветке? Если нет, то в нем не вижу смысла.
А на счет колонки - Вы правильно поняли, но в слоте все-равно есть этот параметр, даже учитывая, что он по-умолчанию 0, поэтому я
Код
C++ (Qt)
пишу setCheckState(column, Qt::Unchecked); // или же Checked
!
spirit, спасибо. Мне понравилось решение с
Код
C++ (Qt)
item -> checkState(column)
. Более элегантно, чем у меня. Принял к сведению.
« Последнее редактирование: Февраль 24, 2009, 18:55 от AD » Записан
AD
Гость
« Ответ #11 : Февраль 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) когда в узле  не один лист, а несколько - то при нажатии на лист - выделение затрагивает и узел.

Я понимаю, что у меня эти ситуации и не учтены в коде. Но вот хотел бы учесть. Буду благодарен за помощь!
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #12 : Февраль 24, 2009, 19:18 »

итератор проходит по всем элементам
Записан

Юра.
AD
Гость
« Ответ #13 : Февраль 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;
}
}
Вот в таком виде - его работа меня меня не устраивает - более неадекватная версия. Результат совсем другой, что в предыдущем коде.
Записан
AD
Гость
« Ответ #14 : Февраль 24, 2009, 19:35 »

Итератор, который проходит все элементы, начиная с item! Почему он не считает элемент item базовым, т.е. максимальная проходимость - это родитель элемента item? Как обрезать его дальнейший проход?
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.53 секунд. Запросов: 22.