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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Дерево с чекбоксами.  (Прочитано 5920 раз)
White Owl
Гость
« : Декабрь 19, 2014, 00:30 »

Qt 5.2.0 и 5.4.0

Мне нужно дерево, каждая ветка и лист которого имеет чекбокс. Галочки на каждой ветке/листе должны зависеть от состояния родителей/детей.
Делаю на основе QTreeWidget:

Код:
twiBranch = new QTreeWidgetItem("branch");
twiBranch->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |  Qt::ItemIsTristate);
twiRoot->addChild(twiBranch);

twiChild = new QTreeWidgetItem("branch");
twiChild->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
twiBranch->addChild(twiChild);
Остальные листья и ветки делаются так-же.

Никаких сигналов не перехватываю.

Полученное дерево хорошо реагирует на установку/снятие галочек на листах. Все ветки вплоть до корня правильно меняют свои состояния между Unchecked, PartiallyChecked и Checked.
А вот если я кликаю (мышой или с клавиатуры) на ветку, то эта ветка меняет статус: Unchecked, PartiallyChecked, Checked, Unchecked, PartiallyChecked и дальше по кругу. При этом, когда ветка принимает значение PartiallyChecked, то и все дети тоже становятся PartiallyChecked.

Спрашивается, кто виноват и что делать? Как убедить ветки дерева чтобы они при клику по этой ветке меняли свое значение только между Checked и Unchecked?
Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #1 : Декабрь 19, 2014, 00:58 »

Как убедить ветки дерева чтобы они при клику по этой ветке меняли свое значение только между Checked и Unchecked?

Цитировать
Qt::ItemIsTristate   Отмечаемый элемент с тремя различными состояниями.

Т.е. вам нужно только Qt::ItemIsUserCheckable использовать.
Записан

__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #2 : Декабрь 19, 2014, 08:19 »

Убрать родителю частичный чек. если не поможет, то отлавливать его сигнал изменения и оперировать детьми
Записан
White Owl
Гость
« Ответ #3 : Декабрь 19, 2014, 19:13 »

Если я убираю с ветки Qt::ItemIsTristate, то она (ветка) никогда и не становится PartiallyChecked, даже когда половина детей отмечана, а половина не отмечена.

Ну вот собственно говоря. Простенький пример с которым я играюсь:
Код:
#include <QtGui>
#include <QtWidgets>

class TestWindow: public QWidget {
    QTreeWidget *tree;
public:
    TestWindow(QWidget *parent = 0);
    ~TestWindow() {delete tree;}
};

TestWindow::TestWindow(QWidget *parent) : QWidget(parent) {
    tree = new QTreeWidget();
    tree->setHeaderHidden(true);
    tree->setRootIsDecorated(true);


    QTreeWidgetItem *twiAll;
    twiAll = new QTreeWidgetItem();
    twiAll->setText(0,"all");
    twiAll->setCheckState(0, Qt::Unchecked);
    twiAll->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |  Qt::ItemIsTristate);
    tree->addTopLevelItem(twiAll);
    twiAll->setExpanded(true);

    QTreeWidgetItem *twiParent = new QTreeWidgetItem();
    twiParent->setText(0,"Parent 1");
    twiParent->setCheckState(0, Qt::Unchecked);
    twiParent->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |  Qt::ItemIsTristate);
    twiAll->addChild(twiParent);
    twiParent->setExpanded(true);

    QTreeWidgetItem *twiChild = new QTreeWidgetItem();
    twiChild->setText(0, "child a");
    twiChild->setCheckState(0, Qt::Unchecked);
    twiChild->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
    twiParent->addChild(twiChild);

    twiChild = new QTreeWidgetItem();
    twiChild->setText(0, "child b");
    twiChild->setCheckState(0, Qt::Unchecked);
    twiChild->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
    twiParent->addChild(twiChild);

    twiParent = new QTreeWidgetItem();
    twiParent->setText(0,"Parent 2");
    twiParent->setCheckState(0, Qt::Unchecked);
    twiParent->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |  Qt::ItemIsTristate);
    twiAll->addChild(twiParent);
    twiParent->setExpanded(true);

    twiChild = new QTreeWidgetItem();
    twiChild->setText(0, "child c");
    twiChild->setCheckState(0, Qt::Unchecked);
    twiChild->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
    twiParent->addChild(twiChild);

    twiChild = new QTreeWidgetItem();
    twiChild->setText(0, "child d");
    twiChild->setCheckState(0, Qt::Unchecked);
    twiChild->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
    twiParent->addChild(twiChild);

    QVBoxLayout *vlayout = new QVBoxLayout();
    vlayout->addWidget(tree);
    this->setLayout(vlayout);

    tree->setCurrentItem(tree->topLevelItem(0));
}

int main(int argc, char **argv) {
    QApplication a(argc, argv);
    TestWindow *window = new TestWindow();
    window->show();
    return a.exec();
}
При смене галочек на "child" элементах, галочки на "parent" и "all" ведут себя правильно. А клики на "parent" и "all" ведут себя не правильно...
Попробуйте пожалуйста этот код на Qt ранее чем 5.2, может это свеженький баг? В принципе я могу попробовать откатится на 4.8, но не уверен стоит ли.

Может кто-нибудь писал правильно ведущую себя checkbox-tree модель?
Записан
White Owl
Гость
« Ответ #4 : Декабрь 19, 2014, 19:22 »

Убрать родителю частичный чек. если не поможет, то отлавливать его сигнал изменения и оперировать детьми
Пробовал... Но тут я застрял на вопросе: а как понять где юзер чекнул?
Если я перехватываю сигнал itemChanged(QTreeWidgetItem*,int), а потом меняю галочки на детях - дети сами получают itemChanged сигнал. Но кроме детей мне надо обновить и родителей... А вот тут и начинается чехарда с рекурсией. Когда каждый ребенок получает itemChanged сигнал, и в свою очередь пытается обновить своих родителей. А родители тоже все считают что чекнули их и идут обновлять детей и родителей...
В общем, я запутался, извините...
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #5 : Декабрь 21, 2014, 01:58 »

Вы же можете понять, кто нажат, родитель или потомок... Если родитель, то оперировать с детьми. Если потомок, то проверить что с остальными потомками и дать действие родителю.
Записан
_OLEGator_
Гость
« Ответ #6 : Декабрь 21, 2014, 13:03 »

Я бы не городил огород и изначально отделил модель и преставление, взяв QTreeView и QAbstractItemModel.
И чтобы не было рекурсии, достаточно проверять, изменил ли свое состояние элемент или оно равно текущему.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Декабрь 21, 2014, 13:12 »

А вот тут и начинается чехарда с рекурсией.
Она начинается и в исходниках Qt, т.е. это нормально. Заводится флажок, если он установлен то itemChanged игнорируется. А вообще как-то грустно что такое заслужило обсуждения. Вывел формулу
Цитировать
мощность_инструментария * усилия_программиста = постоянная_величина
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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