PDA

View Full Version : UserCheckable property in QTreeWidget



npc
16th February 2007, 07:49
Hi,

I am using QTreeWidget with one parent and one child QTreeWidgetItem, both are user checkable items.

if the user checked the parent item, the children item also be checked. How to do this ?

Thanks,
**pc**

npc
16th February 2007, 13:46
for this I wrote a slot which emits when the treewidget is clicked.
but I can find any method to set check children of a QTreeWidgetItem.

How to set check all child when theparent item is checked ?

jacek
16th February 2007, 18:35
How to set check all child when theparent item is checked ?
Just iterate over children and check them too. You will need QTreeWidgetItem::childCount() and QTreeWidgetItem::child().

jpn
17th February 2007, 23:00
The problem is that there is no simple and easy way to know when particularly the check state has changed. The Trolls were suggested to add QTreeWidget::itemCheckStateChanged() signal (http://www.trolltech.com/developer/task-tracker/index_html?method=entry&id=110172) but unfortunately the idea got rejected.

Here's a workaround:


//
// MyTreeWidgetItem
//
class MyTreeWidgetItem : public QTreeWidgetItem
{
public:
// <contructors>

// reimplemented QTreeWidgetItem::setData(), as suggested
virtual void setData(int column, int role, const QVariant& value);
};

void MyTreeWidgetItem::setData(int column, int role, const QVariant& value)
{
if (role == Qt::CheckStateRole)
{
Qt::CheckState newState = static_cast<Qt::CheckState>(value.toInt());
Qt::CheckState oldState = static_cast<Qt::CheckState>(data(column, role).toInt());

QTreeWidgetItem::setData(column, role, value);

if (newState != oldState)
{
MyTreeWidget* tree = qobject_cast<MyTreeWidget*>(treeWidget());
if (tree)
{
emit tree->itemCheckStateChanged(this);
}
}
}
else
{
QTreeWidgetItem::setData(column, role, value);
}
}

//
// MyTreeWidget
//
class MyTreeWidget : public QTreeWidget
{
Q_OBJECT
friend class MyTreeWidgetItem;

public:
...

signals:
void itemCheckStateChanged(MyTreeWidgetItem* item);
};


Just notice that the checkable items must be instances of MyTreeWidgetItem, otherwise the signal wont get emitted. QTreeWidgetItemIterator might be handy for iterating the children..

bpetty
4th April 2007, 22:40
It is all in how you write the code.

Make a method that auto. (un)checks your child boxes like so:


void ConfigurationForm::checkGroupChildren(QTreeWidgetI tem* pItem, enum Qt::CheckState eCheckState)
{
if (pItem)
{
int nChildCount = pItem->childCount();
for (int i = 0; i < nChildCount; i++)
{
pItem->child(i)->setCheckState(0,eCheckState);
}

checkSiblingsSetParent(pItem); // If it is a child, set the parent check state accordingly
}
}


The next thing you need to do is send the right signal... itemClicked().


connect(ui.treewMode, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(modeItemChecked(QTreeWidgetItem*,int)));


To get this to work as intended you need to write modeItemChecked() like this:


void ConfigurationForm::modeItemChecked(QTreeWidgetItem * pItem, int nColumn )
{
if (pItem != NULL && nColumn != -1)
{
enum Qt::CheckState eCheckState = pItem->checkState(0);
checkGroupChildren(pItem, eCheckState); // Check Items Children
}
}


So the theory is that when ever you click the text of the item... it will call this method. In that case it will not matter... nothing will change unless your children are not of the same check state. That is the main draw back of this design... it is not that bad though. When you do (un)check the check box... it will pick it up and (un)check the children. This is a lot easier solution than the one give above... especially if you are using Qt Designer.

Hope that helps.

EDITED:

I also had to add this function:


void ConfigurationForm::checkSiblingsSetParent(QTreeWid getItem* pItem)
{
QTreeWidgetItem* pParentItem = NULL;
enum Qt::CheckState eCheckState = Qt::Unchecked;

if (pItem != NULL) // Is a valid Item
{
pParentItem = pItem->parent();
if (pParentItem != NULL) // Item was a child
{
int nChildCount = pParentItem->childCount();
for (int i = 0; i < nChildCount; i++)
{
// See if any siblings are checked
if (pParentItem->child(i)->checkState(0) == Qt::Checked)
{
eCheckState = Qt::Checked;
break;
}
}

pParentItem->setCheckState(0, eCheckState); // Set parent according to children status
}
}
}


This way... when you (un)check a child box... the parent will reflect the correct change. I modified my original post code to use this function. It has been tested and works great.