PDA

View Full Version : Need help understanding QTreeWidget data structure



AusSkiller
23rd September 2013, 13:48
I'm currently working on an update to an old application I made ages ago and as part of the update I want to scrap whatever Microsoft GUI system I was using before and instead use Qt which seems MUCH more functional. I managed to work out how to get the QTreeWidget to behave the way I want, but I'm really struggling to figure out where the data is and how it's stored. I can follow the basic hierarchical structure of the rows and columns no problem but I can't seem to find any of the data that I filled out in the Qt Designer :(.

Following a few scraps of info I was able to find I tried to get the data for the second column of the first row of the first parent row like this:

ui.treeWidget->topLevelItem(0)->child(0)->data(1, Qt::UserRole)
But it keeps saying the QVariant is an invalid type and I cant figure out why, the data should be an integer or at least text because it still displays correctly.

Ultimately the way I want to use the QTreeWidget is that rather than fill it with the Qt Designer I want to populate it from a database, there will be several collapsible categories that each have a list of data fields and their numerical value, the first column will be an uneditable label for the data field and the second column will be an editable integer that will need to be saved back into the database at some point. As I said I got the behavior working great, the label is uneditable and the value can be edited and is limited to numeric values, but I just can't figure out how to get the data.

Can anyone help me with how to get the data? Also if there's a better way to do things for the way I plan for it to be used I'd love to hear about it.

anda_skoa
23rd September 2013, 14:01
I think what you are trying to do is to get the text that is displayed in the second column, right?

You can either use QTreeWidgetItem::text(int) or, if you prefer to go through data(), use the Qt::DisplayRole to get the displayed string.

The role argument on setData() and data() basically allows you to associate any data with a cell, independent on what is being displayed.

If you have complex data it might be worthwhile to consider subclassing QTreeWidgetItem and storing your data items directly in there.

Cheers,
_

AusSkiller
23rd September 2013, 14:24
You can either use QTreeWidgetItem::text(int) or, if you prefer to go through data(), use the Qt::DisplayRole to get the displayed string.
So the data is just stored as text then? I guess the data set is small enough that the int->string->int conversions aren't going to be a big deal so I'll just do that.


The role argument on setData() and data() basically allows you to associate any data with a cell, independent on what is being displayed.
Ahh cool, that will be good to know for any future projects that I might use Qt for :).


If you have complex data it might be worthwhile to consider subclassing QTreeWidgetItem and storing your data items directly in there.
Fortunately my data is very simple so that isn't likely to be necessary, it's just a string and an int, as well as a category to be sorted into.


Thanks :)

anda_skoa
24th September 2013, 08:19
So the data is just stored as text then? I guess the data set is small enough that the int->string->int conversions aren't going to be a big deal so I'll just do that.

The text that is displayed is stored as a text when using the widget item method.

You can store the integer additionally using setData(). In the model/view method the model would return the string of the number when being asked for the Qt::DisplayRole and the number when being asked for the Qt::EditRole.


Fortunately my data is very simple so that isn't likely to be necessary, it's just a string and an int, as well as a category to be sorted into.


Just in case you need custom sorting, e.g. sort by a column that shows numbers and you want to sort numerically correct (instead of textually correct), then you will need to subclass, because you will have to overwrite operator<()

Cheers,
_

AusSkiller
26th September 2013, 03:39
Things have been going well, but now that I'm loading in the data for another QTreeWidget I'm using I just wanted to check on the ownership of QTreeWidgetItems, for instance in the following example would I need to explicitly delete rootItem somewhere if I removed it from the QTreeWidget via ui.treeWidget->removeItemWidget(rootItem)? Or is it automatically deleted? And what happens to the children of rootItem when I remove it? Are they deleted automatically or do I need to delete them explicitly?


QTreeWidgetItem* rootItem = new QTreeWidgetItem;
rootItem->setText(0, "Root Node");
rootItem->setData(0, Qt::UserRole, integerID);
ui.treeWidget->addTopLevelItem(rootItem);



Edit:
I've been playing around with things and it would seem removeItemWidget doesn't actually remove anything :(. The only way I seem to be able to remove the selected item is to do this:

if (ui.treeWidget->currentItem()->parent() != NULL)
{
ui.treeWidget->currentItem()->parent()->takeChild(ui.treeWidget->currentItem()->parent()->indexOfChild(ui.treeWidget->currentItem()));
}
Surely there's a better way to remove an item from the QTreeWidget, this can't be what I need to do right?

anda_skoa
26th September 2013, 08:17
Once you add an item to the widget it is owned by the widget.
If you take it out, e..g usin QTreeWidget::takeTopLevelWidget(), then you are the owner again.

Same applies to child items, i.e. owned by parent item.

You can explciitly delete items by just calling delete on them, they are then also removed from the view.
I am not sure removeItemWidget() will remove an item that is not a widget, I think it only removes widgets that have been set with setitemWidget() on an already exiting item. basically like clearing the item's value.

In short: once you've added an item you don't have to explicitly delete it nor its children, unless you want to.

Cheers,
_

AusSkiller
26th September 2013, 08:52
Basically I just want to remove the selected item/row when I click a button, so what's the best method for doing that? I've tried searching for how to do it but every article or forum post I've come across refers to takeTopLevelItem, but the top level item is the only item I don't want to be able to remove, not to mention there's no clear indication on how I'm supposed to get the index from the items which seems to be the only way to specify what I want to remove. I don't know what it is about the QTreeWidget but I just can't figure out it's interfaces at all, it's driving me nuts. I was able to solve all my other issues with Qt in a matter of minutes but the solutions for my problems with QTreeWidget seem to elude me :(.

anda_skoa
27th September 2013, 08:14
Basically I just want to remove the selected item/row when I click a button, so what's the best method for doing that?

Just delete it.



not to mention there's no clear indication on how I'm supposed to get the index from the items

Each item knows its parent, each parent can give you the index of a child through indexOfChild()

Cheers,
_

AusSkiller
27th September 2013, 12:28
Just delete it.
Cool that works great :D.