Disable toplevel item of QTreeWidget
-
Hi everyone and happy new year to you all !!
In my project i have a QTreeWidget filled with QTreeWidgetItems, each element of my tree has a checkbox (not the widget i just use the checkboxes of QTreeWidgetItem). And each toplevel item has one or several children.
My question is can i disable a toplevel item without disabling it's children ? I want the toplevel item to be grayed out and non-clickable while still being able the see it's children and check/uncheck them.
So far i can't seem to do that simply, adding a widget inside my QTreeWidgetItem and disabling that instead of the QTreeWidgetItem would work but seem like a hassle just for that. The other way would be to "simulate" the disable by catching keyboards/mouse events and changing the visuals manually but that also seems like a lot of work for not much.
Thanks in advance for the reply :)
-
Hi
You should be able to change its flags for the parent itemhttps://doc.qt.io/qt-5/qtreewidgetitem.html#flags
-
First, thanks for the reply !
I've already parsed the doc you linked times and times again and, unless i'm missing something, what you suggested was the first thing i tried, here's the constructor for my test project:this->setWindowTitle("QTreeWidget test"); QTreeWidget* treeA = new QTreeWidget(this); treeA->setHeaderHidden(true); QTreeWidgetItem* parentItemA = new QTreeWidgetItem(treeA, QStringList(QString("parent 1"))); QTreeWidgetItem* childItemA1 = new QTreeWidgetItem(parentItemA, QStringList(QString("child 1"))); QTreeWidgetItem* childItemA2 = new QTreeWidgetItem(parentItemA, QStringList(QString("child 2"))); QTreeWidgetItem* childItemA3 = new QTreeWidgetItem(childItemA1, QStringList(QString("child 3"))); QTreeWidgetItem* childItemA4 = new QTreeWidgetItem(childItemA1, QStringList(QString("child 4"))); QHBoxLayout* layout = new QHBoxLayout(this); layout->addWidget(treeA); childItemA1->setFlags(childItemA1->flags() & ~Qt::ItemIsEnabled); childItemA3->setFlags(childItemA3->flags() | Qt::ItemIsEnabled);
It's simply a QTreeWidget filled with some QTreeWidgetItems. Here's the output :
Child 1 is disabled but child 3 and 4 also are. I even manually re-set child 3's flag to IsEnabled to no avail.
At this point i'm not sure if what i'm looking for is actually possible. It's not really important since i still managed to get the results i wanted but i would've preferred a cleaner solution.
-
Hmm I must recall wrong and flags actually affect children also - to be "helpful" since in many cases it makes sense
that if the parent is disabled, children are also.
Sorry for the goose chase then :)Yep it does.
void QTreeWidgetItem::setFlags(Qt::ItemFlags flags) { const bool enable = (flags & Qt::ItemIsEnabled); const bool changedState = bool(itemFlags & Qt::ItemIsEnabled) != enable; const bool changedExplicit = d->disabled != !enable; d->disabled = !enable; if (enable && par && !(par->itemFlags & Qt::ItemIsEnabled)) // inherit from parent itemFlags = flags & ~Qt::ItemIsEnabled; else // this item is explicitly disabled or has no parent itemFlags = flags; if (changedState && changedExplicit) { // if the propagate the change to the children QStack<QTreeWidgetItem*> parents; parents.push(this); while (!parents.isEmpty()) { QTreeWidgetItem *parent = parents.pop(); for (int i = 0; i < parent->children.count(); ++i) { QTreeWidgetItem *child = parent->children.at(i); if (!child->d->disabled) { // if not explicitly disabled parents.push(child); if (enable) child->itemFlags = child->itemFlags | Qt::ItemIsEnabled; else child->itemFlags = child->itemFlags & ~Qt::ItemIsEnabled; child->itemChanged(); // ### we may want to optimize this } } } } itemChanged(); }
-
QTreeWidget(Item) is a convenience model. If it does not suit for the usecase then you have to implement a model on your own.
-
@Christian-Ehrlicher said in Disable toplevel item of QTreeWidget:
QTreeWidget(Item) is a convenience model. If it does not suit for the usecase then you have to implement a model on your own.
Yeah i feel that's what i'll have to do eventually. I recently picked up a project without much prior Qt experience, amongst many refactor i removed the QCheckBoxes inside the QTreeWidgetItems (to facilitate keyboard use with the tree since i didn't want to bother myself with keyboard events back then) and now i'll feel like i'll have to retrace back, oh well.
True, but it's not selectable, which is at least what the OP asked for:
My original issue was only a visual one since i already caught mouse and keyboard events to do what i want.
All in all thanks for your replies, what i wanted is in fact not possible so i'll have to find workarounds. Marking the post as solved.
-
@Mummoc
Yes, I believe what we are saying is: disabling aQTreeWidgetItem
means disabling its descendants, which seems pretty reasonable. It is therefore not possible to have descendants which are themselves enabled.That's why I suggested all you can use would be selectability (
Qt::ItemIsSelectable
) as that is allowed to vary such that a parent may be unselectable itself while a descendant is still selectable. -
Yes, I believe what we are saying is: disabling a QTreeWidgetItem means disabling its descendants, which seems pretty reasonable. It is therefore not possible to have descendants which are themselves enabled.
Yes this seems pretty reasonable and expected as a behavior.
That's why I suggested all you can use would be selectability (Qt::ItemIsSelectable) as that is allowed to vary such that a parent may be unselectable itself while a descendant is still selectable.
I was already playing with this flag (and overriding mouse and keyboards events) for various reasons so my original problem was solely a visual one, so to simulate the graying i used QTreeWidgetItem->setForeground() with a gray color.
So far it does what i need (the checkbox of my QTreeWidgetItem isn't grayed out but this detail is so minor that i'm not bothering with that). So i'm calling it quit now.