Forwarding signals from QSortFilterProxyModel to source model
-
I have code where a source model (QAbstractListModel) implements its public add/remove/modify interface through slots. I'm trying to add a QSortFilterProxyModel between the view (which is in QML if it matters) and the source model. Obviously I still need to be able to add, remove, and modify items through the slot interface. Clearly the view should have no idea whether the underlying model is a proxy model or not so it seems the only solution is to subclass QSortFilterProxyModel and reimplement the public interface for QAbstractListModel. This is fine but I'm working with a whole model hierarchy which expose slightly different interfaces so each one will probably need its own subclassed proxy model.
All this is certainly doable but I just can't help but shake the feeling that I'm missing a much simpler way of doing this. If any one has any suggestions I'd appreciate it.
-
Hi,
The view normally has absolutely no idea if a derived QAbstractListModel or QSortFilterProxy is attached! When implementing the QSortFilter this will be placed between the view and the model. There is a good Model/View doc on this site, it's explains the proper functioning of the QSortFilter.
No problem with using slots as normal member functions as well! It's the same, only Qt did some slot implementation. C++ execution is the same!
So if the QSortFilterProxy is calling the virtual functions it will be the same as you calling them via signal/slot method from other parts of your program.
I might misinterpreted you? Or maybe helped a lot ;-)
Greetz -
Right, I realize that I can always just forward function calls to the source model. That much is fine. The issue is that it seems like a bit of a maintenance issue if you have to subclass a QSortFilterProxyModel for every model class just to present the same interface to the view (the original model derived classes might have an interface that expands on the virtual base class interface, for example). It seems like there would be an easier way to forward all signals directed at one object to another object but maybe this isn't true.
Something like:
@
connect_all(&proxyModel, &sourceModel)
@ -
you don't have to subclass all proxies. Instead write some function to return proper (and already casted) model from view.
@template<typename T> T * GET_MODEL(QAbstractItemView * ui)
{
QAbstractProxyModel * model
= qobject_cast<QAbstractProxyModel*>(ui->model());
T * theModel = 0;
if (model) //we know that proxy is between model and view
theModel = qobject_cast<T*>(model->sourceModel());
else //we know that model is directly connected to view
theModel = qobject_cast<T*>(ui->model());
return theModel;
}MyModel * model = GET_MODEL<MyModel>(ui->someView);
if (model) {
model->insert(...);
}
@ -
That's a very intriguing idea....it doesn't allow the concept of possibly stacking n-number of proxy models in front of the source model, but it seems like that could be easily corrected by a recursive call when the model->sourceModel() result is another QAbstractProxyModel.
The other issue I just discovered is that (in the case of editing an existing item, for example) if an index from the proxy model is provided, the proxy model needs to be used to map the proxy index to the source index.
My main point in asking this question is basically trying to figure out if the method of using slots in a source model to provide this type of interface is correct. It seems to be pretty standard for QML-based views but it seems like it could result in code duplication when models are stacked (if you do, in fact, have to forward the whole interface through proxy models).
-
The proxy should NEVER be used (derived) to alter the underlying model data if you ask me. You can add multiple proxies to the same model and any signal it emits will be used by all connected proxies.
Sorry, just don't get the point here. Sorry, might just be me. -
I will provide a very simple example. Let's say you have the following setup:
View <------> ProxyModel <-------> SourceModel
Now in the View/UI a user selects an item in the view and wants to edit a string that is presented in the view. How would you do that? The index presented in the view is not guaranteed to match the index from the source model (because of the proxy model). So from my perspective you can do a couple things:
-
You can emit an edit signal from the view for example:
@
signal edit(int index, string newString)
@
This is the scenario I'm facing right now. The index ISN'T a source model index so the signal CAN'T just be passed to the source model, the proxy model has to translate it. -
You can assign each list item some sort of unique id (a UUID for example) that the view can use to reference the edited item rather than the index and emit a signal:
@
signal edit(UUID id, string newString)
@
The downside to this is that you still need some sort of intermediary object that knows to forward the received signal to the source model and bypass the proxy model.
My issue is more that I just don't see how this problem is usually addressed. This must be a common scenario when using views and models in Qt, so it seems there must be a common pattern for dealing with this.
-