PDA

View Full Version : Model-View, where to start?



soul_rebel
26th January 2008, 20:20
I have a large Number of items that should each be represented by an Item in a Tree.
I used QTreeWidget up until now, but have to / want to use a Model-View-Thing instead.

Where do I start? As far as I understood I shouldnt need to reimplement QTreeView, only the QstandardItemModel, or is it sufficient to keep QStandardItemModel and just subclass QStandardItem?

For a better understanding I'll try to describe my situation in more detail:
I have a QList <QMyObject*> of about 18K Objects. Each of those is currently represented by one
class QMyListItem : public QObject, public QTreeWidgetItemThese Items contain some Members (i.e. a Pointer to the QMyObject they represent) and need to be Qobjects to stay "informed" about updates in their QMyObjects (through Signals'n'Slots).
The TreeWidget has 3 columns, the contents is set by the QMyListItems themself.

The QMyListItems are sorted into about 70 categories (simple QTreeWidgetItems).

How would I achieve similar behaviour with a custom "Model-View-Thing"?

Thank you for your help!

wysota
26th January 2008, 21:05
Do you need those items to inherit QObject? Please take time to think about it before you answer, this is really important. The model inherits QObject so if you just need signals and slots for communication, you can do that through the model and not the items.

soul_rebel
26th January 2008, 22:42
Do you need those items to inherit QObject? Please take time to think about it before you answer, this is really important. Why should they not inherit QObject? QMyObjects contain lots of different data and the ListItem needs to know when that data changes. Also the QMyObjects live in a different thread, so the new information must be transmitted through signals and cannot be fetched normally after state-change.
It seems natural for me to solve it like this.

The model inherits QObject so if you just need signals and slots for communication, you can do that through the model and not the items. Hm, but the Model doesnt know the senders of the objects. I would have to change the whole underlying structure to make QMyObjects emit a pointer to themselves in addtion to all the dataChanged-signals. Also the Model would have to search for the corresponding item every time one property of an underlying QMyObject changes.
That doesnt sound reasonable...

wysota
26th January 2008, 22:50
Why should they not inherit QObject?
For multiple reasons, weight being one of them, modularity being another.


QMyObjects contain lots of different data and the ListItem needs to know when that data changes.
That's exactly what the model is for.


Also the QMyObjects live in a different thread, so the new information must be transmitted through signals and cannot be fetched normally after state-change.
"Must" and "cannot" are such strong words :)


It seems natural for me to solve it like this.
I wouldn't do that if you want them to be represented by a model unless you have no other choice. Making 20000 signal-slot connections is not what I'd call lightweight :)


Hm, but the Model doesnt know the senders of the objects. I would have to change the whole underlying structure to make QMyObjects emit a pointer to themselves in addtion to all the dataChanged-signals.
No, this would make the model useless. Communicate with the items through the model, that's exactly what it's for. See my post here: http://blog.wysota.eu.org/index.php/2007/12/17/itemviews-data-redundancy/



Also the Model would have to search for the corresponding item every time one property of an underlying QMyObject changes.
It wouldn't have to search for anything if you'd make changes only through the model interface.

soul_rebel
26th January 2008, 23:33
Hm, the whole point is that QMyObjects live in a different thread. However they are not thread-safe. That is done intentionally because mutexing them would cause a lot of overhead. This means the UI cannot call myobject->property1(), because it isnt safe (it could change while be called).

Now background threads might change the data in one of those QMyObjects. This Object will have to emit a signal that it has changed state and what to, so that the front-end (in this case the UI) knows whats going on and specific things change (i.e. the treeview representation of the object).
Connecting all these signals to the Model instead of the item will not reduce the number of connections, it will only create another step between "dataChanged" and " visual represention changed".
Now I am aware that 20000 qobjects as list items are a little more expensive than simple "non-q"-objects, but considering that I need these specific signals from the QMyObjects in other places, I think it a fair trade-off.
It actually works rather well with the QTreeWidget, its just that that wont let me do proper filtering :(
Also a Model might be handy, when implemting a second view for doing content-based searches on QMyObjects...

wysota
27th January 2008, 01:04
Hm, the whole point is that QMyObjects live in a different thread.
I don't perceive it as a problem. We have synchronization methods available. Or you can use a "proxy" object that would live in the same thread as those items.


That is done intentionally because mutexing them would cause a lot of overhead. This means the UI cannot call myobject->property1(), because it isnt safe (it could change while be called).
So how did you make it work with a tree widget? It's not thread safe you know...


Now background threads might change the data in one of those QMyObjects.
This Object will have to emit a signal that it has changed state and what to, so that the front-end (in this case the UI) knows whats going on and specific things change (i.e. the treeview representation of the object).
The usual way of doing that is to modify the object through the model interface and emitting appropriate signals from the model. This way threads can change data as much as they want, but only through the model interface.


It actually works rather well with the QTreeWidget, its just that that wont let me do proper filtering :(
Also a Model might be handy, when implemting a second view for doing content-based searches on QMyObjects...

You can start with QStandardItemModel which is basically the same functionality you had in the tree widget only that it is a separate object. Then when you feel comfortable with the model, you can move on and extend it with whatever you need.

Valheru
27th January 2008, 01:12
Hm, the whole point is that QMyObjects live in a different thread. However they are not thread-safe. That is done intentionally because mutexing them would cause a lot of overhead. This means the UI cannot call myobject->property1(), because it isnt safe (it could change while be called).

Now background threads might change the data in one of those QMyObjects. This Object will have to emit a signal that it has changed state and what to, so that the front-end (in this case the UI) knows whats going on and specific things change (i.e. the treeview representation of the object).
Connecting all these signals to the Model instead of the item will not reduce the number of connections, it will only create another step between "dataChanged" and " visual represention changed".
Now I am aware that 20000 qobjects as list items are a little more expensive than simple "non-q"-objects, but considering that I need these specific signals from the QMyObjects in other places, I think it a fair trade-off.
It actually works rather well with the QTreeWidget, its just that that wont let me do proper filtering :(
Also a Model might be handy, when implemting a second view for doing content-based searches on QMyObjects...


If you are writing a multi-threaded application and you want to access data from multiple thread then you are going to have to use mutex locks when you change data. Well, you don't have to, but it isn't going to make your program very usable or stable if you don't.


Why do you consider mutex locks to be expensive if I may ask? As far as I know they aren't that expensive. And they are necessary if you want to access data from multiple threads.


As wysota said, you should access your data via the model, using QModelIndex's. And I would suggest not arranging your data into QStandardWidgetItems, but rather implementing the data(), index() and parent() functions of a QAbstractItemModel
in such a way that you existing data structure is accurately represented to any view interfacing with the model.

soul_rebel
27th January 2008, 16:32
If you are writing a multi-threaded application and you want to access data from multiple thread then you are going to have to use mutex locks when you change data. Well, you don't have to, but it isn't going to make your program very usable or stable if you don't.Well, i don't have to use mutexes if only the "owner-thread" changes data directly. All other threads communicate with the "owner-thread" through QueuedConnections. That is a great benefit of Qt4 over Qt3's Thread Handling. Also I dont want to put the Model inside this owner-thread because it isn't needed there at all.

However, I think I will just try implementing QAbstractItemModel or QStandardItemModel and report back if/when I run into problems.

wysota
27th January 2008, 17:28
All other threads communicate with the "owner-thread" through QueuedConnections.
When an event is queued, the queue has to be synchronized with the two threads, so you are using mutexes even if you didn't specifically ask for them yourself.

soul_rebel
2nd March 2008, 21:11
When an event is queued, the queue has to be synchronized with the two threads, so you are using mutexes even if you didn't specifically ask for them yourself. Well, no, the mutexes are only used when the event is queued. The event is only queued when it is received by a different thread, so for events emitted by the same thread there is no overhead, because they aren't queued...

Anyway, I got a model based on standartitemmodel and treeview set up.
The Problem is that only the top-level-items are displayed. They are displayed as expendable, but when expanding one, only "..." appear below the "expanded" item. What is really strange, is that the scrollbar is actually resized, although no new items appear in the view.
I know that the sub-items are added, but they aren't there :(

Also a checkbox is displayed infront of the top-level items although I explicetly setCheckable(false) in the constructor....

Thanks for help!!

wysota
3rd March 2008, 00:07
Well, no, the mutexes are only used when the event is queued.
Which is 100% of cases when transferring events across threads...


The Problem is that only the top-level-items are displayed. They are displayed as expendable, but when expanding one, only "..." appear below the "expanded" item. What is really strange, is that the scrollbar is actually resized, although no new items appear in the view.
I know that the sub-items are added, but they aren't there :(
They are, they just don't fit into their cells, hence the "...".


Also a checkbox is displayed infront of the top-level items although I explicetly setCheckable(false) in the constructor....
Constructor of items? Don't set it then. By the way, there is a high chance you don't need to subclass the item...

soul_rebel
3rd March 2008, 00:54
Which is 100% of cases when transferring events across threads... well yes, but I have both cases, where something is done inside the thread and where it is done between threads. Just putting mutexes around the action will cause extra overhead when they are called inside the thread.... Anyway that isnt really the issue ;)



They are, they just don't fit into their cells, hence the "...".

Hm, I don't understand. How can they not fit in? They just contain a String, just like the top-level items.


Constructor of items? Don't set it then. By the way, there is a high chance you don't need to subclass the item...
I need to subclass them.... And I just set the value because it was already showing the boxes.... However they can't even be checked, they are just there...

Thanks for your help!

Ok, I got it. Had to setColumnCount(3) on all the top-level-items.
Now the children are displayed... but all items still have the (check)box...
Maybe it will dissappear if I setIcon()...

wysota
3rd March 2008, 02:11
How can they not fit in? They just contain a String, just like the top-level items.
Yes, but this + the checkbox + a bug in recent Qt releases equals the effect you experience.


I need to subclass them....
What for?


However they can't even be checked, they are just there...
You must have enabled them. They are not shown by default. You must have used setCheckState() or similar...


Maybe it will dissappear if I setIcon()...
No, it won't.

soul_rebel
3rd March 2008, 03:18
Ok I am changing the structure, so that in the end I wont need subclassed Items.
However I dont really understand how to do the following:
* the whole itemmodel has 3 columns.
* the toplevel items dont need column 1 and 2 (only column 0)
* the sub-items need all columns

I add the top-level items through invisibleRootItem()->appendRow() and add the sub-items by topLevelItem->appendRow()....
But how do I get the snd and trd column? subItem->addColumn() add children to it :confused:

Or would these actually be children of the non-existent snd-column-item to the toplevelitem :confused:

Thanks for your help!

soul_rebel
3rd March 2008, 04:24
Wow, I got it working....
Somehow it was much easier than I thought.... Wasted a lot of time, trying to do it the hard way :S

Oh well, thanks for your help and for "insisting" on not subclassing QStandardItem!