Qt View/Model/Data Paradigm: How to modify data? - qt

I just read the Model/View documentation for Qt 4.8. I believe to understand how the Model/View (Delegates/SelectionModel) work. One thing that I'm unsure about is how to manipulate data when I have a for example a TreeView.
Imagine having a TreeView to display a list and buttons to remove elements from this list when an item/row is selected. I see two approaches here
1) In the slot of the PushButton I retrieve the SelectionModel and the ItemModel of the TreeView and call model->removeRow(index.row ...). This way the model (that i subclassed from QAbstractItemModel) manipulates the data that it is supposed to represent.
2) In the slot of the PushButton I remove the item directly from the data source, that the TreeView's model represents. Then I can link the data with the model via signals/slot, such that the model can then tell the TreeView that the underlying data has changed.
The same scenario can be imagined with adding elements. Should I add the new element to the data which signals its changed state to the ItemModel which the informs the TreeView, or should I add the new item through the ItemMode?
I haven't found any Best Practices documentation on this. The two approaches differ strongly, such I would like to know in advanced which one is preferable.
Does anybody have a suggestion which path to follow?
Thanks

1) is preferable - you should probably avoid manipulating your data source directly from the UI code - your life will be better if you go through the model. At the very least add a method to your model to do the data manipulation, and call that method from your UI code.
You will find that some of Qt's methods are protected such that they can only be called from the model itself (e.g. endInsertRows etc.)

Related

Data driven selection in Qt view

I am looking for an elegant way to change the selection in a Qt TreeView based on the data of the underlying model. So my dynamic data contains information about the currently active element which should be selected in the TreeView.
Background: I have a setup with a 3d viewer for a bunch of objects and a Qt TreeView that lists the objects. The user should be able to select objects by klicking them either in the TreeView or in the 3d viewer. The 3d viewer is non-Qt code and modifies the data directly and sets the a flag indicating the selection.
I implemented a dataModel and a selectionModel (as I have to synchronize two views on the data).
My current idea is to emit a signal from the dataModel to the selectionModel to modify the selection when the data has changed. But this seems awkward to me...
Is there a recommended Qt way of doing this?

Specifying Delegate class for a QAbstractItemModel item

I have a Qt C++ application that uses several different models (ultimately) based on QAbstractItemModel.
Several of the items in these models use a custom Delegate to render them properly, these work well.
However, I'm not sure how best to specify which of these Delegate classes should be used to render the data.
At present, I'm calling QAbstractItemView::setItemDelegateForColumn() in each of the forms that contain a view.
This feels very clumsy, because it relies on the form classes knowing which delegate should be used for each column in every model - and if that changes in the future, I have to update every form.
Furthermore, in some cases a View is switching between two different models that require different Delegates, so for these the form class has to handle that switch as well.
Is there a better way to do this?
The model must not know about representation, so you should deal with the view. You can subclass involved view class (e.g. QTableView) and reimplement setModel virtual method. In your implementation call the parent class implementation and adjust item delegates based on specified model. Put objects of this class inside all your forms. So forms will not know about delegates. I think this approach agrees with the Model-View conception.
AFAIK, there's no better way.
However, instead of updating manually every form, i used to have an enum which holds the columns index, which is used both in the model and in the view to retrieve data and apply delegates.

Problems with displaying data in QListView

Good day!
There are instances of classes QListView and QTreeView.
Both of the instances loads data from model (QStandardItemModel).
QTreeView displays positions (For example: Chief, Manager, Developer, etc).
Clicking on the title of position a list of employees revealed.
QListView displays only positions of staff.
Question:
How can I display a full list of names of employees in QListView not showing their positions?
Which methods I need to override?
What can you advise in this situation?
P.S. Thanks!
I don't think you are going to be able to do that with a single model.
This thread suggests using a proxy model to flatten the original one without having to maintain two instances of that data. But the implementation pointed to (KDE's KReparentingProxyModel) isn't exactly trivial.
There is some documentation on proxy models, and the QSortFilterProxyModel might be usable in your context, although I think you'll need something more specific.
You might also find the classes attached to the third response on this thread: ModelView - how to use proxies to filter this data? interesting as a starting point.
(Sorry this isn't very specific. Searching for "qt flatten tree model" will give you other ideas.)
Try to use QListWidget, is easier than QListView.

Updating a QListView when objects change externally

I've a simple question regarding the update of a QTreeView (or any subclass of QAbstractItemView) when a model object changes externally. Let's say that a list shows a subclass of QAbstractItemModel, and an item of that model gets changed outside of the list window, and we would like to update the list with the change. What is the usual strategy to achieve something like this ? I've looked at the Qt documentation of QAbstractItemModel and there is a signal named 'dataChanged' that is (or should be) emited when data from the model changes. But since this signal (as all QAbstractItemModel functions/signals/slots) work with a QModelIndex, which is not persistent as the documentation clearly says, am i supposed to store somehow a mapping of my data to QPersistentModelIndex(es), so when my data change i will be able to find the corresponding QPersistenModelIndex and use that as argument to the various QAbstractItemModel functions ? Is that what QPersistentModelIndex(es) are used for ? Or am i missing something ?
Thank you.
ps: I guess i could just reload the QTreeView, but then i wouldn't know which items were expanded or which were selected. Is there an strategy to overcome this problem and just reload the list ?
QTreeView already handles the case in which the underlying model's data changed (i.e. the model has emitted the dataChanged() signal). That means you don't need to do any additional work on the view.
If you're implementing your own model (a derived class of QAbstractItemView), and you're making a change to the contents of the model, you simply need to emit the dataChanged() signal when your change is complete. The signal/slot mechanism will automatically inform the view using that signal.

Checkbox in Flex Datagrid Broken on Scrolling

I have a checkbox in a Flex DataGrid, and when I scroll, other rows are randomly checked/unchecked.
After reading over: Creating a column of RadioButtons in Adobe Flex
it's clear that the itemRenderers are getting recycled, but the problem I have with the solution presented there is it moves info about the view into the model.
Does anyone have a better way of solving it, that doesn't force me to put information for the UI into my actionscript model classes? (in my case, I am converting incoming XML data to actionscript classes, and these are getting bound to my datagrid).
Thanks for the help.
thanks everyone. great tips. unfortunately it was becoming too much overhead to keep the model pure, so i just polluted the model like the link in my original post. :( at least it works.
Chetan, neat idea.. i tried working with this for almost an entire day with no luck though.
brd6644, good thoughts on separating the two model classes.. i might go back and do this later.
You could create a subclass of DataGrid that internally stores what rows are checked/unchecked (Array/Collection of Boolean) but you would have a devil of a time keeping that in sync with the dataProvider when it is sorted or filtered. I suppose you could use a Dictionary that is keyed by the object in each index of the dataProvider and valued with a Boolean to indicate whether it's selected. That would at least isolate you from the sorting / filtering issues. This will not work if you have duplicate references in your dataProvider.
Alternatively, you could create a subclass of your ActionScript model class and add the "selected" property to it, then write some simple utility methods to "convert" between the two. That way your View deals only with the "ViewModel" class and other layers (especially the server side) deals only with the real "Model" class.
Adding to what cliff.meyers said, there is a third option of creating a custom IList class as described in this blog post by Alex Harui. It is pretty clever actually, and is cleaner as it doesn't require subclassing the component or polluting your model classes.

Resources