QML嵌套ListView无/有ListModel时如何存储数据并实现持久化恢复
结论先行
- 你最初认为「整数model场景下无法借助model存储数据」的认知不正确,但你切换为ListModel的方案是更合理的选择,当前用ListModel的场景完全可以实现notesLabel数据的持久化存储。
- 之前滚动丢失内容的核心原因是你把备注数据存在了视图层(委托的Label控件属性),而ListView委托销毁时会清空视图层所有状态,只要把数据统一存在Model层就能解决滚动丢失问题,再通过本地存储模块就能实现跨重启持久化。
具体实现步骤
第一步:调整ListModel结构,新增note存储字段
你当前的三层ListModel只有基础的时间维度字段,需要在小时维度的model元素中新增note字段用于存储备注内容,建议同时将三层ListModel改为嵌套结构,更符合日历的层级逻辑,避免独立model索引匹配出错:
ListModel{ id:monthlistModel Component.onCompleted:{ for (var k=0; k <=11; k++){ // 每个月份元素下挂载对应日期的ListModel let dayModel = createDayModel() append({ monthName : k, dayModel: dayModel }) } } function createDayModel(){ let dayModel = ListModel.create() for (var j=0; j <= 31; j++){ // 每个日期元素下挂载对应小时的ListModel let hourModel = createHourModel() dayModel.append({ day : j, hourModel: hourModel }) } return dayModel } function createHourModel(){ let hourModel = ListModel.create() for (var i = 0; i <24; i++){ hourModel.append({ hour : i, note: "" // 新增note字段,初始为空 }) } return hourModel } }
三层ListView的model对应绑定嵌套的model即可:
- 月份ListView的model绑定
monthlistModel - 日期ListView的model绑定
model.dayModel - 小时ListView的model绑定
model.hourModel
第二步:绑定视图控件到model数据,不要直接操作视图属性
将小时委托中的notesLabel的text属性直接绑定到model的note字段,所有数据修改都操作model层,不要直接修改控件属性:
Label{ id:notesLabel anchors.left:hourweeklistviewLabel.right anchors.leftMargin: 30 text: model.note // 直接绑定model数据,委托重建时会自动从model拉取数据 }
在根组件新增几个临时属性用于弹窗传值,避免通过不稳定的currentItem拿视图数据:
property int currentMonthIdx: 0 property int currentDayIdx: 0 property int currentHourIdx: 0 property string currentEditingNote: ""
小时条目的MouseArea点击逻辑改为:
onClicked:{ currentMonthIdx = monthofdayCalendar.currentIndex currentDayIdx = dayCalendar.currentIndex currentHourIdx = index currentEditingNote = model.note windowLoader.active = true }
第三步:修改弹窗保存逻辑,直接修改model数据
弹窗中的TextField初始值直接绑定currentEditingNote,保存按钮的点击逻辑改为直接修改对应model的note字段,修改后视图会自动同步更新:
Button { id: button text: qsTr("Add Note") anchors.centerIn:parent onClicked: { // 直接修改model层数据,视图自动同步 monthlistModel.get(currentMonthIdx).dayModel.get(currentDayIdx).hourModel.get(currentHourIdx).note = title.text windowLoader.active = false } }
这一步完成后,滚动ListView导致委托销毁重建时,notesLabel会自动从model拉取数据,不会再出现内容丢失的问题。
第四步:实现跨重启持久化存储
借助Qt.labs.settings模块将model数据序列化存储到本地,应用启动时读取回填即可:
- 首先引入Settings模块:
import Qt.labs.settings 1.0
- 在根组件添加Settings实例:
Settings { id: appSettings property string calendarNotes: "" }
- 应用关闭时,将三层model中的note数据序列化为JSON字符串存入Settings:
ApplicationWindow{ id:appwindow onClosing: { let notesData = [] for(let m=0;m<monthlistModel.count;m++){ let monthItem = monthlistModel.get(m) notesData[m] = [] for(let d=0;d<monthItem.dayModel.count;d++){ let dayItem = monthItem.dayModel.get(d) notesData[m][d] = [] for(let h=0;h<dayItem.hourModel.count;h++){ notesData[m][d][h] = dayItem.hourModel.get(h).note } } } appSettings.calendarNotes = JSON.stringify(notesData) } }
- 应用启动、model初始化完成后,读取存储的JSON数据回填到model:
Component.onCompleted: { if(appSettings.calendarNotes !== ""){ let notesData = JSON.parse(appSettings.calendarNotes) for(let m=0;m<notesData.length;m++){ let monthItem = monthlistModel.get(m) for(let d=0;d<notesData[m].length;d++){ let dayItem = monthItem.dayModel.get(d) for(let h=0;h<notesData[m][d].length;h++){ dayItem.hourModel.get(h).note = notesData[m][d][h] } } } } }
内容的提问来源于stack exchange,提问作者cgiannakidis
相关产品推荐
相关产品推荐

