Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. [Solved] Editing and saving indexed roles to Settings
Qt 6.11 is out! See what's new in the release blog

[Solved] Editing and saving indexed roles to Settings

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
6 Posts 2 Posters 448 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • MarkkyboyM Offline
    MarkkyboyM Offline
    Markkyboy
    wrote on last edited by Markkyboy
    #1

    Hi, I want to create a user editable menu.

    The idea is the user can edit the price, name and type of the label and when the app is closed/opened, the edited data remains.

    I'm struggling, as this involves indexes and I'm not sure how to access/edit/save these elements (roles of list element) and save them for next time the app is opened.

    What am I missing?, not doing?

    Here's what I have so far;

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.12
    import Qt.labs.settings 1.1
    
    ApplicationWindow {
        id: mainWindow
        visible: true
        width: 960
        height: 540
        color: "darkgreen"
        title: qsTr("Pudding price list")
    
        Flickable {
            anchors.fill: parent
            contentHeight: grid.height
    
            Grid {
                id: grid
                rows: 2
                rowSpacing: 60            
                columns: 2
                columnSpacing: 60
                topPadding: 30
                anchors.horizontalCenter: parent.horizontalCenter
                Repeater {
                    model: ListModel {
                        id: sweetModel
                        ListElement {
                            name: "Fudge Cake"
                            type: "cake"
                            price: "3"
                            image: "images/fudge-cake.jpg"
                        }
                        ListElement {
                            name: "Gateaux"
                            type: "sponge cake"
                            price: "4"
                            image: "images/gateaux.jpg"
                        }
                        ListElement {
                            name: "Cookies"
                            type: "biscuits"
                            image: "images/choc-chip-cookies.jpg"
                            price: "4"
                        }
                        ListElement {
                            name: "Ice Cream"
                            type: "dairy"
                            price: "5"
                            image: "images/ice-cream.jpg"
                        }
                    }
                    Rectangle {
                        id: background
                        width: 300
                        height: 200
                        color: "maroon"
                        radius: 10
    
                        TextField {
                            id: cost
                            text: price
                            background: Rectangle {
                                anchors.fill: parent
                                color: "#00000000"
                            }
                            font.pixelSize: 36
                            color: "white"
                            onEditingFinished: sweetModel.get([index]).price = cost.text
                        }
                        TextField {
                            id: label
                            text: name
                            font.pixelSize: 36
                            background: Rectangle {
                                anchors.fill: parent
                                color: "#00000000"
                            }
                            color: "white"
                            anchors {
                                margins: 15
                                bottom: parent.bottom
                                horizontalCenter: parent.horizontalCenter
                            }
                            onEditingFinished: sweetModel.get([index]).name = label.text
                        }
                        TextField {
                            id: kind
                            text: type
                            anchors {
                                bottom: parent.bottom
                                horizontalCenter: parent.horizontalCenter
                            }
                            color: "white"
                            background: Rectangle {
                                anchors.fill: parent
                                color: "#00000000"
                            }
                            font {
                                italic: true
                                pixelSize: 14
                                letterSpacing: 2
                                capitalization: Font.AllUppercase
                            }
                            onEditingFinished: sweetModel.get([index]).type = kind.text
                        }
                        Settings {
                            id: settings
                            category: "Menu"
                        }
                        Component.onCompleted:  {
                            cost.text[index] = settings.value("costText", cost.text[index])
                            console.log("Price: " + " " + sweetModel.get([index]).price);
                            //console.log("Name: " + " " + sweetModel.get([index]).name);
                            //console.log("Type: " + " " + sweetModel.get([index]).type);
                        }                    
                        Component.onDestruction: {
                            settings.setValue("costText", cost.text[index])
                            console.log("Price: " + " " + sweetModel.get([index]).price);
                            //console.log("Name: " + " " + sweetModel.get([index]).name);
                            //console.log("Type: " + " " + sweetModel.get([index]).type);
                        }
                    }
                }
            }
        }
    }
    

    Don't just sit there standing around, pick up a shovel and sweep up!

    I live by the sea, not in it.

    1 Reply Last reply
    0
    • fcarneyF Offline
      fcarneyF Offline
      fcarney
      wrote on last edited by
      #2

      Your indexing for editing seems to be working. I think the settings should be a global and will most likely require serialization.

      import QtQuick 2.12
      import QtQuick.Window 2.12
      import QtQuick.Controls 2.12
      import Qt.labs.settings 1.1
      
      ApplicationWindow {
          id: mainWindow
          visible: true
          width: 960
          height: 540
          color: "darkgreen"
          title: qsTr("Pudding price list")
      
          property bool save: true
      
          onClosing: {
              if(save){
                  let tlist = []
                  for(let idx=0; idx<listmodelsource.model.count; ++idx){
                      let obj = listmodelsource.model.get(idx)
                      let temp = {name:obj.name, type:obj.type, price:obj.price, image:obj.image}
                      tlist.push(temp)
                  }
      
                  let stringed = JSON.stringify(tlist)
                  console.log("written", stringed)
                  listmodelsourcedata = stringed
              }
          }
      
          property string listmodelsourcedata: ""
      
          Settings {
              id: settings
              category: "Menu"
      
              property alias listmodelsource: mainWindow.listmodelsourcedata
          }
      
          Component.onCompleted: {
              if(listmodelsourcedata){
                  let tlist = JSON.parse(listmodelsourcedata)
                  console.log("read", listmodelsourcedata)
                  sweetModel.clear()
                  for(let idx in tlist){
                      sweetModel.append(tlist[idx])
                  }
              }
          }
      
          Flickable {
              anchors.fill: parent
              contentHeight: grid.height
      
              Grid {
                  id: grid
                  rows: 2
                  rowSpacing: 60
                  columns: 2
                  columnSpacing: 60
                  topPadding: 30
                  anchors.horizontalCenter: parent.horizontalCenter
      
                  Repeater {
                      id: listmodelsource
                      model: ListModel {
                          id: sweetModel
                          ListElement {
                              name: "Fudge Cake"
                              type: "cake"
                              price: "3"
                              image: "images/fudge-cake.jpg"
                          }
                          ListElement {
                              name: "Gateaux"
                              type: "sponge cake"
                              price: "4"
                              image: "images/gateaux.jpg"
                          }
                          ListElement {
                              name: "Cookies"
                              type: "biscuits"
                              image: "images/choc-chip-cookies.jpg"
                              price: "4"
                          }
                          ListElement {
                              name: "Ice Cream"
                              type: "dairy"
                              price: "5"
                              image: "images/ice-cream.jpg"
                          }
                      }
                      Rectangle {
                          id: background
                          width: 300
                          height: 200
                          color: "maroon"
                          radius: 10
      
                          TextField {
                              id: cost
                              text: price
                              background: Rectangle {
                                  anchors.fill: parent
                                  color: "#00000000"
                              }
                              font.pixelSize: 36
                              color: "white"
                              onEditingFinished: sweetModel.get([index]).price = cost.text
                          }
                          TextField {
                              id: label
                              text: name
                              font.pixelSize: 36
                              background: Rectangle {
                                  anchors.fill: parent
                                  color: "#00000000"
                              }
                              color: "white"
                              anchors {
                                  margins: 15
                                  bottom: parent.bottom
                                  horizontalCenter: parent.horizontalCenter
                              }
                              onEditingFinished: sweetModel.get([index]).name = label.text
                          }
                          TextField {
                              id: kind
                              text: type
                              anchors {
                                  bottom: parent.bottom
                                  horizontalCenter: parent.horizontalCenter
                              }
                              color: "white"
                              background: Rectangle {
                                  anchors.fill: parent
                                  color: "#00000000"
                              }
                              font {
                                  italic: true
                                  pixelSize: 14
                                  letterSpacing: 2
                                  capitalization: Font.AllUppercase
                              }
                              onEditingFinished: sweetModel.get([index]).type = kind.text
                          }
      
                          /*
                          Component.onCompleted:  {
                              cost.text[index] = settings.value("costText", cost.text[index])
                              console.log("Price: " + " " + sweetModel.get([index]).price);
                              //console.log("Name: " + " " + sweetModel.get([index]).name);
                              //console.log("Type: " + " " + sweetModel.get([index]).type);
                          }
                          Component.onDestruction: {
                              settings.setValue("costText", cost.text[index])
                              console.log("Price: " + " " + sweetModel.get([index]).price);
                              //console.log("Name: " + " " + sweetModel.get([index]).name);
                              //console.log("Type: " + " " + sweetModel.get([index]).type);
                          }
                          */
                      }
                  }
              }
          }
      }
      

      I found this SO approach. I tried serializing a QObject. It didn't like it at all.
      https://stackoverflow.com/questions/48730166/how-to-save-and-restore-the-content-of-a-listmodel

      C++ is a perfectly valid school of magic.

      1 Reply Last reply
      1
      • MarkkyboyM Offline
        MarkkyboyM Offline
        Markkyboy
        wrote on last edited by
        #3

        Wow!, thank you. There is little to no way i would have worked that lot out. I looked at so many examples, created many examples but my head was starting to hurt and I was getting very muddled.

        One more question if you don't mind; I've added a 'quit' button to the UI, but upon 'quitting' the app, any data that has been changed, say a price from 7 to 8, is not updated. . . . What do I need to add to my 'close' button to apply the change?

                /* other code */
                contentHeight: grid.height + -180
        
                Rectangle {
                    id: close
                    width: 20
                    height: width
                    color: "red"
                    radius: width/2
                    x: 10; y: x
                }
                Label {
                    text: "X"
                    color: "white"
                    anchors.centerIn: close
                }
        
                MouseArea {
                    anchors.fill:  close
                    onClicked: {
                        Qt.quit()
                    }
                }
        
                Grid {
                    id: grid
                    /* etc. . .  */
        

        Regards,

        Don't just sit there standing around, pick up a shovel and sweep up!

        I live by the sea, not in it.

        1 Reply Last reply
        0
        • fcarneyF Offline
          fcarneyF Offline
          fcarney
          wrote on last edited by
          #4

          Since you are using TextFields you have to get the onEditingFinished to fire. In order to do that you have to press enter or have the TextField lose focus.

          https://doc.qt.io/qt-5/qml-qtquick-controls-textfield.html#editingFinished-signal

          So you could cause another Item to gain focus at the beginning of the onClosing method. I don't know if that is setActiveFocus or another call. Maybe just setting an Item's focus to true might do it.

          C++ is a perfectly valid school of magic.

          1 Reply Last reply
          1
          • fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on last edited by
            #5

            I made a dummy object and set the focus on it at the start of the onClosing function:

            onClosing: {
                    dummyfocus.focus = true
            
                    if(save){
                        let tlist = []
                        for(let idx=0; idx<listmodelsource.model.count; ++idx){
                            let obj = listmodelsource.model.get(idx)
                            let temp = {name:obj.name, type:obj.type, price:obj.price, image:obj.image}
                            tlist.push(temp)
                        }
            
                        let stringed = JSON.stringify(tlist)
                        console.log("written", stringed)
                        listmodelsourcedata = stringed
                    }
                }
            
                Item {
                    id: dummyfocus
                }
            

            This takes focus from any currently being edited objects. Of course a button would probably do this if pressed as well. So it probably would have sorted itself out. But at least you can force it this way.

            C++ is a perfectly valid school of magic.

            MarkkyboyM 1 Reply Last reply
            1
            • fcarneyF fcarney

              I made a dummy object and set the focus on it at the start of the onClosing function:

              onClosing: {
                      dummyfocus.focus = true
              
                      if(save){
                          let tlist = []
                          for(let idx=0; idx<listmodelsource.model.count; ++idx){
                              let obj = listmodelsource.model.get(idx)
                              let temp = {name:obj.name, type:obj.type, price:obj.price, image:obj.image}
                              tlist.push(temp)
                          }
              
                          let stringed = JSON.stringify(tlist)
                          console.log("written", stringed)
                          listmodelsourcedata = stringed
                      }
                  }
              
                  Item {
                      id: dummyfocus
                  }
              

              This takes focus from any currently being edited objects. Of course a button would probably do this if pressed as well. So it probably would have sorted itself out. But at least you can force it this way.

              MarkkyboyM Offline
              MarkkyboyM Offline
              Markkyboy
              wrote on last edited by
              #6

              @fcarney - thanks again, this is taking shape now. There are a few odd behaviours which I will try to nail down, but largely, I am now able to edit price, name and type, close and open again with all my changes being present! yay!

              Regards,

              Don't just sit there standing around, pick up a shovel and sweep up!

              I live by the sea, not in it.

              1 Reply Last reply
              1

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved