Q_INVOKABLE QAbatractListModel* dataChanged() only updating once
-
Hello,
I've created a custom c++ model called ISettingModel that is derived from QAbstractListmodel. This model is created via Q_INVOKABLE.
Q_INVOKABLE ISettingModel* createISettingModel(const NavigationManager::Page); ISettingModel* ISettingPresenter::createISettingModel(NavigationManager::Page subset) { qDebug() << " creating new setting model for page: " << subset; ISettingModel *model = new ISettingModel(subset,this); return model; }
QML snippet:
function resetListByIndex(ind){ presenter.settingsSaved = true; if(ind === 0){isettingpresenter.resetUnsavedSettings(NavigationManager.UserAccessPage);} else if(ind === 1) {console.log("no settings on reset comm module page");} else {console.log("Invalid index, will not reset unsaved values")} } SwipeView { id: view currentIndex: index height: parent.height anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.bottom: indicator.top property int prevIndex: index onCurrentIndexChanged: { console.log("current index changed, prev index " + view.prevIndex + " current index " + currentIndex); isettingpresenter.clearUserAccessSettings(); if(view.prevIndex != currentIndex){ resetListByIndex(view.prevIndex); view.prevIndex = currentIndex; } } Item { id: userAccess SettingBrowser { height: parent.height width: parent.width parent_popupheight: parent.height * 3 parent_popupwidth: parent.width * 3 name: "User Access Settings" settingBrowserModel: isettingpresenter.createISettingModel(NavigationManager.UserAccessPage) onSaveClicked: { console.log("credientialsPage " +" onSavedClick: disableTabBar()") appWindow.disableTabBar() //disable so user can't go to home before creating control. must be before sendUserAccessSettings() console.log("calling sendUserAccessSettings()") isettingpresenter.sendUserAccessSettings(); //this call UserAccessConfig* } onSendUserAccessValue: { console.log("id: " + id + " " + "idValue: " + idvalue) isettingpresenter.writeUserAccessSettings(id, idvalue) } } } Item { id: resetCommModulePasswordScreen Rectangle { width: parent.width height: parent.height anchors.top: header_resetCommModulePassword.bottom Rectangle{ id: button_resetCommModulePassword anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter width: parent.width * .6 height: parent.height * .4 color: mouseArea_resetCommModulePassword.pressed ? Qt.darker(Variables.seLifeGreen) : Variables.seLifeGreen Text{ id: buttonText_resetCommModulePassword width: parent.width height: parent.height text: "RESET Communication Module Password" color: Variables.ultraLightGrey2 font.pixelSize: 18 wrapMode: Text.WordWrap font.family: opensansregular.name verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } } } }
The model gets created fine and I'm able to interact and save and update settings fine. The issue is when I need to reset unsaved settings when swiping to another screen. When I first launch the program I'm able to change some settings , swipe and have them reset as expected. However, when I exit that page (ie go to homepage) and go back to that page I am unable to reset settings. More specifically, I can see that the dataChanged() signal is emitted but I see no new calls to data() to reset the settings. Again, it only seems to work when the page is first accessed. After that swiping no longer seems to reset properly. Does anyone have any idea why this could happen?
void ISettingModel::resetUnsavedSettings(NavigationManager::Page subset) { if(subset == mList){ qDebug() << "ISettingModel::resetUnsavedSettings()::mList: " << mList; QVector<int> list = mSettingPresenter->getListByName(mList); if(!list.empty()){ bool reset = false; for(int i=0; i<list.length(); i++){ SettingBase *setting = (mSettingPresenter->allSettingsMap).value(list.at(i)); qDebug() << "reset setting: " << setting->getIndex(); reset = setting->resetUnsavedValue();// sets temp value equal to value QModelIndex index = QAbstractListModel::createIndex(i,0); if (reset){ qDebug() << "Value reset setting name "<<setting->getLabel(); reset = false; emit dataChanged(index, index, QVector<int>()); qDebug() << "dataChanged emitted(index, index, QVector<int>() << role): " << index ; qDebug() << "datachanged() in list: " <<mList; m_dependencyManager->updateDependents(static_cast<Settings::Parameter>(setting->getIndex()),setting->getValue()); } } } else{ qDebug()<<"list " << mList << "is an empty list, no settings to reset"; } } }
Here you can see output from the qDebug() statements
My one thought is that dataChanged() is getting emitted but its referencing another model? I'm not entirely sure how QML's garbage collector works. I saw that the destructor for ISettingModel doesn't get called every time the page is destroyed.
-
Hello,
I've created a custom c++ model called ISettingModel that is derived from QAbstractListmodel. This model is created via Q_INVOKABLE.
Q_INVOKABLE ISettingModel* createISettingModel(const NavigationManager::Page); ISettingModel* ISettingPresenter::createISettingModel(NavigationManager::Page subset) { qDebug() << " creating new setting model for page: " << subset; ISettingModel *model = new ISettingModel(subset,this); return model; }
QML snippet:
function resetListByIndex(ind){ presenter.settingsSaved = true; if(ind === 0){isettingpresenter.resetUnsavedSettings(NavigationManager.UserAccessPage);} else if(ind === 1) {console.log("no settings on reset comm module page");} else {console.log("Invalid index, will not reset unsaved values")} } SwipeView { id: view currentIndex: index height: parent.height anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.bottom: indicator.top property int prevIndex: index onCurrentIndexChanged: { console.log("current index changed, prev index " + view.prevIndex + " current index " + currentIndex); isettingpresenter.clearUserAccessSettings(); if(view.prevIndex != currentIndex){ resetListByIndex(view.prevIndex); view.prevIndex = currentIndex; } } Item { id: userAccess SettingBrowser { height: parent.height width: parent.width parent_popupheight: parent.height * 3 parent_popupwidth: parent.width * 3 name: "User Access Settings" settingBrowserModel: isettingpresenter.createISettingModel(NavigationManager.UserAccessPage) onSaveClicked: { console.log("credientialsPage " +" onSavedClick: disableTabBar()") appWindow.disableTabBar() //disable so user can't go to home before creating control. must be before sendUserAccessSettings() console.log("calling sendUserAccessSettings()") isettingpresenter.sendUserAccessSettings(); //this call UserAccessConfig* } onSendUserAccessValue: { console.log("id: " + id + " " + "idValue: " + idvalue) isettingpresenter.writeUserAccessSettings(id, idvalue) } } } Item { id: resetCommModulePasswordScreen Rectangle { width: parent.width height: parent.height anchors.top: header_resetCommModulePassword.bottom Rectangle{ id: button_resetCommModulePassword anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter width: parent.width * .6 height: parent.height * .4 color: mouseArea_resetCommModulePassword.pressed ? Qt.darker(Variables.seLifeGreen) : Variables.seLifeGreen Text{ id: buttonText_resetCommModulePassword width: parent.width height: parent.height text: "RESET Communication Module Password" color: Variables.ultraLightGrey2 font.pixelSize: 18 wrapMode: Text.WordWrap font.family: opensansregular.name verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } } } }
The model gets created fine and I'm able to interact and save and update settings fine. The issue is when I need to reset unsaved settings when swiping to another screen. When I first launch the program I'm able to change some settings , swipe and have them reset as expected. However, when I exit that page (ie go to homepage) and go back to that page I am unable to reset settings. More specifically, I can see that the dataChanged() signal is emitted but I see no new calls to data() to reset the settings. Again, it only seems to work when the page is first accessed. After that swiping no longer seems to reset properly. Does anyone have any idea why this could happen?
void ISettingModel::resetUnsavedSettings(NavigationManager::Page subset) { if(subset == mList){ qDebug() << "ISettingModel::resetUnsavedSettings()::mList: " << mList; QVector<int> list = mSettingPresenter->getListByName(mList); if(!list.empty()){ bool reset = false; for(int i=0; i<list.length(); i++){ SettingBase *setting = (mSettingPresenter->allSettingsMap).value(list.at(i)); qDebug() << "reset setting: " << setting->getIndex(); reset = setting->resetUnsavedValue();// sets temp value equal to value QModelIndex index = QAbstractListModel::createIndex(i,0); if (reset){ qDebug() << "Value reset setting name "<<setting->getLabel(); reset = false; emit dataChanged(index, index, QVector<int>()); qDebug() << "dataChanged emitted(index, index, QVector<int>() << role): " << index ; qDebug() << "datachanged() in list: " <<mList; m_dependencyManager->updateDependents(static_cast<Settings::Parameter>(setting->getIndex()),setting->getValue()); } } } else{ qDebug()<<"list " << mList << "is an empty list, no settings to reset"; } } }
Here you can see output from the qDebug() statements
My one thought is that dataChanged() is getting emitted but its referencing another model? I'm not entirely sure how QML's garbage collector works. I saw that the destructor for ISettingModel doesn't get called every time the page is destroyed.
@MattC24
My suspicion from code reading is thatresetUnsavedSettings()
isn't invoked by the QML code at all, because it isn't Q_INVOKABLE. Maybe it gets called upon construction ofISettingsModel
, which would explain why it's called only once. -
Hello,
I've created a custom c++ model called ISettingModel that is derived from QAbstractListmodel. This model is created via Q_INVOKABLE.
Q_INVOKABLE ISettingModel* createISettingModel(const NavigationManager::Page); ISettingModel* ISettingPresenter::createISettingModel(NavigationManager::Page subset) { qDebug() << " creating new setting model for page: " << subset; ISettingModel *model = new ISettingModel(subset,this); return model; }
QML snippet:
function resetListByIndex(ind){ presenter.settingsSaved = true; if(ind === 0){isettingpresenter.resetUnsavedSettings(NavigationManager.UserAccessPage);} else if(ind === 1) {console.log("no settings on reset comm module page");} else {console.log("Invalid index, will not reset unsaved values")} } SwipeView { id: view currentIndex: index height: parent.height anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.bottom: indicator.top property int prevIndex: index onCurrentIndexChanged: { console.log("current index changed, prev index " + view.prevIndex + " current index " + currentIndex); isettingpresenter.clearUserAccessSettings(); if(view.prevIndex != currentIndex){ resetListByIndex(view.prevIndex); view.prevIndex = currentIndex; } } Item { id: userAccess SettingBrowser { height: parent.height width: parent.width parent_popupheight: parent.height * 3 parent_popupwidth: parent.width * 3 name: "User Access Settings" settingBrowserModel: isettingpresenter.createISettingModel(NavigationManager.UserAccessPage) onSaveClicked: { console.log("credientialsPage " +" onSavedClick: disableTabBar()") appWindow.disableTabBar() //disable so user can't go to home before creating control. must be before sendUserAccessSettings() console.log("calling sendUserAccessSettings()") isettingpresenter.sendUserAccessSettings(); //this call UserAccessConfig* } onSendUserAccessValue: { console.log("id: " + id + " " + "idValue: " + idvalue) isettingpresenter.writeUserAccessSettings(id, idvalue) } } } Item { id: resetCommModulePasswordScreen Rectangle { width: parent.width height: parent.height anchors.top: header_resetCommModulePassword.bottom Rectangle{ id: button_resetCommModulePassword anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter width: parent.width * .6 height: parent.height * .4 color: mouseArea_resetCommModulePassword.pressed ? Qt.darker(Variables.seLifeGreen) : Variables.seLifeGreen Text{ id: buttonText_resetCommModulePassword width: parent.width height: parent.height text: "RESET Communication Module Password" color: Variables.ultraLightGrey2 font.pixelSize: 18 wrapMode: Text.WordWrap font.family: opensansregular.name verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } } } }
The model gets created fine and I'm able to interact and save and update settings fine. The issue is when I need to reset unsaved settings when swiping to another screen. When I first launch the program I'm able to change some settings , swipe and have them reset as expected. However, when I exit that page (ie go to homepage) and go back to that page I am unable to reset settings. More specifically, I can see that the dataChanged() signal is emitted but I see no new calls to data() to reset the settings. Again, it only seems to work when the page is first accessed. After that swiping no longer seems to reset properly. Does anyone have any idea why this could happen?
void ISettingModel::resetUnsavedSettings(NavigationManager::Page subset) { if(subset == mList){ qDebug() << "ISettingModel::resetUnsavedSettings()::mList: " << mList; QVector<int> list = mSettingPresenter->getListByName(mList); if(!list.empty()){ bool reset = false; for(int i=0; i<list.length(); i++){ SettingBase *setting = (mSettingPresenter->allSettingsMap).value(list.at(i)); qDebug() << "reset setting: " << setting->getIndex(); reset = setting->resetUnsavedValue();// sets temp value equal to value QModelIndex index = QAbstractListModel::createIndex(i,0); if (reset){ qDebug() << "Value reset setting name "<<setting->getLabel(); reset = false; emit dataChanged(index, index, QVector<int>()); qDebug() << "dataChanged emitted(index, index, QVector<int>() << role): " << index ; qDebug() << "datachanged() in list: " <<mList; m_dependencyManager->updateDependents(static_cast<Settings::Parameter>(setting->getIndex()),setting->getValue()); } } } else{ qDebug()<<"list " << mList << "is an empty list, no settings to reset"; } } }
Here you can see output from the qDebug() statements
My one thought is that dataChanged() is getting emitted but its referencing another model? I'm not entirely sure how QML's garbage collector works. I saw that the destructor for ISettingModel doesn't get called every time the page is destroyed.
@MattC24 There's too much and not enough info there.
The swiping screens, resetting models stuff is not helping understand the issue.
We don't see how the model is used in QML.
With the limited info we have here I'd check the addresses of the the model. Is dataChanged emitted for the same model where data is called?
try to make minimal reproducible example to focus on the important stuff.
-
@MattC24
My suspicion from code reading is thatresetUnsavedSettings()
isn't invoked by the QML code at all, because it isn't Q_INVOKABLE. Maybe it gets called upon construction ofISettingsModel
, which would explain why it's called only once.@Axel-Spoerl apologies I didn't want to send all of the ISettingPresenter because I'm refactoring the class. but to inform on some missing pieces.
void ISettingPresenter::resetSettingList(NavigationManager::Page subset) { emit resetUnsavedSettings(subset); }
this signal is connected in the constructor of ISettingModel.
ISettingModel::ISettingModel(NavigationManager::Page subset, ISettingPresenter *isettingpresenter, QObject *parent) : QAbstractListModel(parent) { qDebug()<<"Setting Model Initialized"; m_dependencyManager = new ModelDependencyManager(this); mSettingPresenter = isettingpresenter; setList(subset); connect(mSettingPresenter, &ISettingPresenter::settingPropertyChanged, //used for just updating setting if on page this, &ISettingModel::updateSetting); connect(mSettingPresenter, &ISettingPresenter::resetUnsavedSettings, this, &ISettingModel::resetUnsavedSettings); connect(m_dependencyManager, &ModelDependencyManager::updateDependentValue, //used for updating depdendents on screen via setData i.e enable/disable this, &ISettingModel::updateDependentSettingOnScreen); }
So whenever that signal is emitted it's getting called. Just that it only seems to work only when I first open that page. IF I close the page and go back to it, it'll get called but not update properly
-
@Axel-Spoerl apologies I didn't want to send all of the ISettingPresenter because I'm refactoring the class. but to inform on some missing pieces.
void ISettingPresenter::resetSettingList(NavigationManager::Page subset) { emit resetUnsavedSettings(subset); }
this signal is connected in the constructor of ISettingModel.
ISettingModel::ISettingModel(NavigationManager::Page subset, ISettingPresenter *isettingpresenter, QObject *parent) : QAbstractListModel(parent) { qDebug()<<"Setting Model Initialized"; m_dependencyManager = new ModelDependencyManager(this); mSettingPresenter = isettingpresenter; setList(subset); connect(mSettingPresenter, &ISettingPresenter::settingPropertyChanged, //used for just updating setting if on page this, &ISettingModel::updateSetting); connect(mSettingPresenter, &ISettingPresenter::resetUnsavedSettings, this, &ISettingModel::resetUnsavedSettings); connect(m_dependencyManager, &ModelDependencyManager::updateDependentValue, //used for updating depdendents on screen via setData i.e enable/disable this, &ISettingModel::updateDependentSettingOnScreen); }
So whenever that signal is emitted it's getting called. Just that it only seems to work only when I first open that page. IF I close the page and go back to it, it'll get called but not update properly
@MattC24
Then I have to agree with @GrecKo, that there is too little code of a too large project involved here.
I not entirely sure, what you mean byit'll get called but not update properly
Maybe it's a good idea to narrow the issue down to a minimal, compilable reproducer, that is small enough to be posted here in its entirety.
-
@MattC24 There's too much and not enough info there.
The swiping screens, resetting models stuff is not helping understand the issue.
We don't see how the model is used in QML.
With the limited info we have here I'd check the addresses of the the model. Is dataChanged emitted for the same model where data is called?
try to make minimal reproducible example to focus on the important stuff.
-
@MattC24
Then I have to agree with @GrecKo, that there is too little code of a too large project involved here.
I not entirely sure, what you mean byit'll get called but not update properly
Maybe it's a good idea to narrow the issue down to a minimal, compilable reproducer, that is small enough to be posted here in its entirety.
@Axel-Spoerl I will try and reproduce at a smaller scale.
-
@MattC24 There's too much and not enough info there.
The swiping screens, resetting models stuff is not helping understand the issue.
We don't see how the model is used in QML.
With the limited info we have here I'd check the addresses of the the model. Is dataChanged emitted for the same model where data is called?
try to make minimal reproducible example to focus on the important stuff.