Singal not working correct when filtering in QSortFilterProxyModel
-
That I understood, my question is really: why selecting a synonym should trigger an update to the fungus proxy ?
The thing is:
- select a fungus
- update the synonym filter
That is logic.
Then:
- select a synonym
- update the fungus filter
Why ? As you said, you have a set of synonym that matches one fungus. So why should it have any influence on the current fungus selection ?
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
Then:
select a synonym
update the fungus filterWhy ?
I have to query the data that belong to the synonym and are stored in the mushroom table and I do that by filtering the ID in the mFungusProxyModel. I hope I didn't miss the answer again. I am glad about your help
Do you have any idea how I can make it better?
-
That's the thing that is confusing: you already filtered the fungus model since you have the synonyms. So there's no need to filter it again. Just grab the data you want directly.
-
I'm not clear where you see the mFungusProxyModel's filtering? If I select "Synonyms" in the QComboBox and then click on one, I don't have the data from the mFungusProxyModel yet, but only the data from the mSynonymProxyModel or am I missing something here?
-
Wait, do you mean you may have the synonyms "unfiltered" ?
The logic as I understand it is:
- Fungus is the central model
- If none is selected, no synonyms shall be available
- Select a fungus
- Synonyms get populated/filtered
- Select a synonym
- Grab the data from fungus
Why do you need to grab the data on synonym selection rather than directly when you select a fungus ?
-
I'll try again to explain in abstract terms what I'm trying to do. I have a QListView in which names are to be displayed. It should be possible to distinguish between mushroom names, synonym names and German names. The whole thing I realize via QComboBox where I can select which model should be displayed (mFungusProxyModel, mSynonymProxyModel or mGermanNameModel). If for example in the QComboBox "Mushroom name" is selected and I choose one of thousands of mushrooms, all related data should be displayed in my QLineEdits etc. (see screenshot). If I select "Synonyms" in the QComboBox and select one out of thousands, all related data should appear.
A small example for this: I have a mushroom with the name "ABC" which has the associated synonym "XYZ". If I select "Mushroom names" in the QComboBox and then click on the mushroom "ABC", all data should appear. If I select then e.g. in the QComboBox "Synonyms" and click on the synonym "XYZ" the same data should appear as before with the mushroom "ABC".
And exactly for this I use the filtering in the mFungusProxyModel in the function synonymItemChanged()
Am I doing the whole thing correctly then or are there any suggestions for improvement?
-
Ok, clearer now.
Did you consider using a QDataWidgetMapper to populate your widgets ?
That would simplify the data population part.
Set it to the correct entry on your table and voila.
Beside that, you need to decouple things a bit. You are trying to do too many things at the same time.
From the looks of it:
- One model per possibility which are independent from each other as they have different purposes. The ones you use to populate your QListView
- On selection, either extract the data from the index directly to populate your widgets or use QDataWidgetMapper to point to the correct records of the main model(s)
You can even consider using three QListView rather than swapping your proxies.
-
Ok, clearer now.
Did you consider using a QDataWidgetMapper to populate your widgets ?
That would simplify the data population part.
Set it to the correct entry on your table and voila.
Beside that, you need to decouple things a bit. You are trying to do too many things at the same time.
From the looks of it:
- One model per possibility which are independent from each other as they have different purposes. The ones you use to populate your QListView
- On selection, either extract the data from the index directly to populate your widgets or use QDataWidgetMapper to point to the correct records of the main model(s)
You can even consider using three QListView rather than swapping your proxies.
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
Did you consider using a QDataWidgetMapper to populate your widgets ?
Yes, I use QDataWidgetMapper to populate my widgets
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
Beside that, you need to decouple things a bit. You are trying to do too many things at the same time.
What exactly do you mean by that? Can you explain that a bit more precisely and especially at what point?
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
One model per possibility which are independent from each other as they have different purposes. The ones you use to populate your QListView
I have that. mFungusProxyModel is for the table fungus, mSynonymProxyModel is for the table synonyms and mGermanNameProxyModel is for german name table.
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
On selection, either extract the data from the index directly to populate your widgets or use QDataWidgetMapper to point to the correct records of the main model(s)
What you say makes sense, but I don't know how to filter by ID if I'm only working with the QModelIndex, for example. Can you explain this to me in more detail? Maybe also with an example?
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
You can even consider using tree QListView rather than swapping your proxies.
Do you mean a QTreeView?
If I then put all the models in one QTreeView, how does the selection of the correct model work?
-
My bad, three QListView not tree.
Get the source index from what was selected and then use QDataWidgetMapper::setCurrentModelIndex.
-
My bad, three QListView not tree.
Get the source index from what was selected and then use QDataWidgetMapper::setCurrentModelIndex.
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
My bad, three QListView not tree.
I almost thought that you meant three QListViews, but then I wasn't sure. The only question that comes to my mind is: How can I change the three QListViews? Since my GUI was created via the designer. How do I hide the ui->listview and how do I activate the QListView *secondList = new QListView; so that it fits into my layout?
-
Put them in a QStackedWidget or QStackedLayout and switch the one to view based on your combo box selection.
-
Put them in a QStackedWidget or QStackedLayout and switch the one to view based on your combo box selection.
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
Put them in a QStackedWidget
I managed to do that and it works as expected.
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
Get the source index from what was selected and then use QDataWidgetMapper::setCurrentModelIndex.
I'm just not quite sure how you mean that. In my constructor I do this:
secondList = new QListView; thirdList = new QListView; firstList = new QListView; firstList->setModel(mFungusProxyModel); firstList->setModelColumn(1); secondList->setModel(mSynonymProxyModel); secondList->setModelColumn(1); thirdList->setModel(mGermanNameProxyModel); thirdList->setModelColumn(0); ui->stackedWidget->addWidget(firstList); ui->stackedWidget->addWidget(secondList); ui->stackedWidget->addWidget(thirdList); connect(ui->modelSelection, QOverload<int>::of(&QComboBox::activated), ui->stackedWidget, &QStackedWidget::setCurrentIndex); connect(firstList->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::fungusItemChanged); connect(secondList->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::synonymItemChanged);
And my two slot's looks like this:
void MainWindow::fungusItemChanged(const QModelIndex &index) const { const int id = mFungusProxyModel->data(index.siblingAtColumn(Column::Id)).toInt(); const QString redlist = mFungusProxyModel->data(index.siblingAtColumn(Column::Assignment)).toString(); if(redlist.isEmpty()){ ui->redlist->setCurrentIndex(Index::None); } mSynonymFilterModel->setFilterRegularExpression(idFilter(id)); mSynonymFilterModel->setFilterKeyColumn(Column::FungusId); ui->synonymList->setModel(mSynonymFilterModel); ui->synonymList->setModelColumn(Column::Name); mMapper->setCurrentModelIndex(index); //mMapper is QDataWidgetMapper }
void MainWindow::synonymItemChanged(const QModelIndex &index) const { const int id = mSynonymProxyModel->data(index.siblingAtColumn(Column::FungusId)).toInt(); mFungusProxyModel->setFilterRegularExpression(idFilter(id)) ; mFungusProxyModel->setFilterKeyColumn(Column::Id); mSynonymFilterModel->setFilterRegularExpression(idFilter(id)); mSynonymFilterModel->setFilterKeyColumn(Column::FungusId); ui->synonymList->setModel(mSynonymFilterModel); ui->synonymList->setModelColumn(Column::Name); QModelIndex fungusIndex = mFungusProxyModel->index(0,0); const QString redlist = mFungusProxyModel->data(fungusIndex.siblingAtColumn(Column::Assignment)).toString(); if(redlist.isEmpty()){ ui->redlist->setCurrentIndex(Index::None); } mMapper->setCurrentModelIndex(fungusIndex); //mMapper is QDataWidgetMapper }
If I take now for example the secondList (synonym list) and select a synonym I receive the QModelIndex (by the connect it calls me the slot synonymItemChanged(QModelIndex)). But now it is not clear to me, how I should get from this QModelIndex of the mSynonymProxyModel to the one record of the mFungusProxyModel via the QModelIndex. Can you explain this to me?
-
Which model did you set on your mapper ?
-
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
Which model did you set on your mapper ?
mFungusProxyModel. My mapping looks like this:
mFungusProxyModel->setSourceModel(mFungusDataModel); mMapper->setModel(mFungusProxyModel); mMapper->setItemDelegate(new ProxySqlRelationalDelegate(mMapper)); mMapper->addMapping(ui->number, mFungusDataModel->fieldIndex("ID"), "text"); mMapper->addMapping(ui->fullname, mFungusDataModel->fieldIndex("Vollname")); mMapper->addMapping(ui->genus, mFungusDataModel->fieldIndex("Gattung")); mMapper->addMapping(ui->kind, mFungusDataModel->fieldIndex("Art")); mMapper->addMapping(ui->family, mFungusDataModel->fieldIndex("Familie")); mMapper->addMapping(ui->order, mFungusDataModel->fieldIndex("Ordnung")); mMapper->addMapping(ui->notes, mFungusDataModel->fieldIndex("Anmerkung")); mMapper->addMapping(ui->redlist, mFungusDataModel->fieldIndex("Zuordnung"));
-
@Gabber said in Singal not working correct when filtering in QSortFilterProxyModel:
mFungusDataModel
Your mapper should rather be set on that model so it has all data available.
Then you essentially get the source index from your fungus proxy. For the homonyms, since they are on top of a different model, get the ID and then find the index in mFungusDataModel.
-
@Gabber said in Singal not working correct when filtering in QSortFilterProxyModel:
mFungusDataModel
Your mapper should rather be set on that model so it has all data available.
Then you essentially get the source index from your fungus proxy. For the homonyms, since they are on top of a different model, get the ID and then find the index in mFungusDataModel.
@SGaist
I'm sorry, I can't quite follow you yet. Now I have changed the mapper to mFungusDataModelmMapper->setModel(mFungusDataModel); mMapper->setItemDelegate(new QSqlRelationalDelegate(mMapper));
I also know that with mapFromSource(QModelIndex) I can get the mFungusProxyModel index and with mapToSource(QModelIndex) I can get the index of the mFungusDataModel. So far I have understood that.
My other models are:
mFungusDataModel = mDatabaseManager->fungusData(); //QSqlRelationalTableModel mSynonymDataModel = mDatabaseManager->synonymData(); //QSqlTableModel mGermanNameDataModel = mDatabaseManager->germanNameData(); //QSqlRelationalTableModel mFungusProxyModel->setSourceModel(mFungusDataModel); mSynonymProxyModel->setSourceModel(mSynonymDataModel); mGermanNameProxyModel->setSourceModel(mGermanNameDataModel);
Unfortunately, I do not understand:
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
For the homonyms, since they are on top of a different model, get the ID and then find the index in mFungusDataModel.
Here is how I get the mushroom ID:
const int fungusIdFromSynonymProxy = mSynonymProxyModel->data(index.siblingAtColumn(2)).toInt(); //the id from synonymItemChanged(QModelIndex index) auto modelIndex = mFungusProxyModel->mapToSource(index); const int fungusIdFromFungusProxy = modelIndex.siblingAtColumn(0).data().toInt(); //the id from fungusItemChanged(QModelIndex index)
Now, I have the ID.
@SGaist said in Singal not working correct when filtering in QSortFilterProxyModel:
then find the index in mFungusDataModel.
And that is exactly my problem. How do I do it? Via the function void QSqlTableModel::setFilter(const QString &filter) or whats the best/easiest way?
-
One simple way would be to have a simple proxy model that filters on the ID between the fungus model and the data widget mapper. That way the mapper will only have a single entry to show.
-
One simple way would be to have a simple proxy model that filters on the ID between the fungus model and the data widget mapper. That way the mapper will only have a single entry to show.
@SGaist
I'm starting to get a little confused. I mean that I had that so. Can you show me how you mean that in a code snippet for better understanding? -
You are using twice the same proxy model. What I mean is that your QDataWidgetMapper should not reuse the proxy that is already used to show the data on your other widget.
-
Thank you. It now works as expected. But before I mark the thread as solved I would like to know why you should avoid this?
-
In this case separation of concerns.
You have three views that are filtered in different manners using different proxies. Here you try to reuse the same proxy as one of the views but it might not be filtered that way you need it.
The reference index may come from three different views that don't look the same table so you don't want to take one of these proxies for your mapper.
Keep things cleanly separated.