Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Dynamically update QML Image
Forum Updated to NodeBB v4.3 + New Features

Dynamically update QML Image

Scheduled Pinned Locked Moved Unsolved General and Desktop
13 Posts 5 Posters 9.3k 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.
  • fcarneyF fcarney

    Create 2 images in your image provider (pointing to the same image data) and cycle between them in the QML Image:Source. Perhaps use a signal to trigger this change in QML when the image is updated. I believe its a caching thing on the QML side that prevents it re-fetching the data.

    There may be more appropriate ways of doing this.

    B Offline
    B Offline
    Bits-n-Flips
    wrote on last edited by
    #3

    @fcarney said in Dynamically update QML Image:

    Create 2 images in your image provider (pointing to the same image data) and cycle between them in the QML Image:Source. Perhaps use a signal to trigger this change in QML when the image is updated. I believe its a caching thing on the QML side that prevents it re-fetching the data.

    There may be more appropriate ways of doing this.

    This is kind of what I have been doing now.
    What I have been doing is that every time a new image is generated, I have it write to a file and then a signal is called to set the property of the image such as...

    img.setProperty("source",new_img_src)
    

    and it just cycles through a buffer of 3 images.
    Is there any better way to do this without needing to use the filesystem?
    I'd like to read in bytes directly from memory and apply it right to the QML image dynamically every second. So far I don't see a good solution to do this?

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

      Where, when are you writing to file? I did the image provider trick completely in memory. You just have to provide a QImage object. It can be completely in memory. I did this in C++, and unfortunately I don't have the code on hand.

      I think this:

      Image{
          id: img
          objectName: "img"
          anchors.fill:parent
          source: "image://myprovider/test.png"
          }
      

      Is all in memory. The test.png is just an identifier for the source. Unless you are doing something different somewhere else.

      C++ is a perfectly valid school of magic.

      B 1 Reply Last reply
      0
      • fcarneyF fcarney

        Where, when are you writing to file? I did the image provider trick completely in memory. You just have to provide a QImage object. It can be completely in memory. I did this in C++, and unfortunately I don't have the code on hand.

        I think this:

        Image{
            id: img
            objectName: "img"
            anchors.fill:parent
            source: "image://myprovider/test.png"
            }
        

        Is all in memory. The test.png is just an identifier for the source. Unless you are doing something different somewhere else.

        B Offline
        B Offline
        Bits-n-Flips
        wrote on last edited by
        #5

        @fcarney said in Dynamically update QML Image:

        Where, when are you writing to file? I did the image provider trick completely in memory. You just have to provide a QImage object. It can be completely in memory. I did this in C++, and unfortunately I don't have the code on hand.

        I think this:

        Image{
            id: img
            objectName: "img"
            anchors.fill:parent
            source: "image://myprovider/test.png"
            }
        

        Is all in memory. The test.png is just an identifier for the source. Unless you are doing something different somewhere else.

        Thank you for clearing that up. I scrolled back up to your previous reply and re-read it. So if I created say 2 empty QImages (or maybe an array of 3 to create some kind of generated image buffer). My ImageProvider class would need to have these QImages within the requestImage function? I'm not entirely sure how I would implement a QImage to a ImageProvider and have it update. I understand the singals/slots concept though. I use it all the time. Not entirely sure about just how to get this image provider working dynamically.

        J.HilkJ 1 Reply Last reply
        0
        • fcarneyF Offline
          fcarneyF Offline
          fcarney
          wrote on last edited by fcarney
          #6

          When you are setting the source to: "image://myprovider/test.png" you are just telling the imageprovider to give you the image represented by test.png. So what I did was create 2 images in my image provider that pointed to the same data. When I updated the data in the image provider then a new request would get the data. However, Image will not request the new data unless the source string changes. I then setup a timer to change the source string to a different name that still pointed to the same data in the imageprovider.

          I only suggested a messaging scheme to make this maybe more efficient and change only when the image changes. The way I did is definitely hackish and might not be the best way, but I did get it to work.

          It looks like your imageprovider is ignoring p_str which is the "test.png" string. So just changing the "source" string in the Image component in QML should make it update whenever that string changes.

          C++ is a perfectly valid school of magic.

          1 Reply Last reply
          0
          • B Bits-n-Flips

            @fcarney said in Dynamically update QML Image:

            Where, when are you writing to file? I did the image provider trick completely in memory. You just have to provide a QImage object. It can be completely in memory. I did this in C++, and unfortunately I don't have the code on hand.

            I think this:

            Image{
                id: img
                objectName: "img"
                anchors.fill:parent
                source: "image://myprovider/test.png"
                }
            

            Is all in memory. The test.png is just an identifier for the source. Unless you are doing something different somewhere else.

            Thank you for clearing that up. I scrolled back up to your previous reply and re-read it. So if I created say 2 empty QImages (or maybe an array of 3 to create some kind of generated image buffer). My ImageProvider class would need to have these QImages within the requestImage function? I'm not entirely sure how I would implement a QImage to a ImageProvider and have it update. I understand the singals/slots concept though. I use it all the time. Not entirely sure about just how to get this image provider working dynamically.

            J.HilkJ Offline
            J.HilkJ Offline
            J.Hilk
            Moderators
            wrote on last edited by
            #7

            hi @Bits-n-Flips
            maybe you're making that more comlicated than it needs to be.

            do you emit a signal (from your image provider class) when the image is changed ?

            if yes, than you can do the following, inside your qml file (excerpt from a project/challenge of mine)

            Image {
                    id: img
                    property bool counter: false
            
                    asynchronous: false
                    source: "image://live/image"
                    anchors.fill: parent
                    fillMode: Image.PreserveAspectFit
                    cache: false
            
                    function reload() {
                        counter = !counter
                        source = "image://live/image?id=" + counter
                    }
            
                    Connections{
                        target: liveImageProvider
                        onImageChanged: img.reload()
                   }
                }
            

            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            P 1 Reply Last reply
            0
            • J.HilkJ J.Hilk

              hi @Bits-n-Flips
              maybe you're making that more comlicated than it needs to be.

              do you emit a signal (from your image provider class) when the image is changed ?

              if yes, than you can do the following, inside your qml file (excerpt from a project/challenge of mine)

              Image {
                      id: img
                      property bool counter: false
              
                      asynchronous: false
                      source: "image://live/image"
                      anchors.fill: parent
                      fillMode: Image.PreserveAspectFit
                      cache: false
              
                      function reload() {
                          counter = !counter
                          source = "image://live/image?id=" + counter
                      }
              
                      Connections{
                          target: liveImageProvider
                          onImageChanged: img.reload()
                     }
                  }
              
              P Offline
              P Offline
              Puya
              wrote on last edited by
              #8

              @J-Hilk said in Dynamically update QML Image:

              hi @Bits-n-Flips
              maybe you're making that more comlicated than it needs to be.

              do you emit a signal (from your image provider class) when the image is changed ?

              if yes, than you can do the following, inside your qml file (excerpt from a project/challenge of mine)

              Image {
                      id: img
                      property bool counter: false
              
                      asynchronous: false
                      source: "image://live/image"
                      anchors.fill: parent
                      fillMode: Image.PreserveAspectFit
                      cache: false
              
                      function reload() {
                          counter = !counter
                          source = "image://live/image?id=" + counter
                      }
              
                      Connections{
                          target: liveImageProvider
                          onImageChanged: img.reload()
                     }
                  }
              

              @J-Hilk, I think that is missing initialization of counter. Also that seems a bit hacky (thought the cleanest solution I have seen so far). Is it not possible to just do onImageChanged: img.sourceChanged(); ?

              J.HilkJ 1 Reply Last reply
              0
              • P Puya

                @J-Hilk said in Dynamically update QML Image:

                hi @Bits-n-Flips
                maybe you're making that more comlicated than it needs to be.

                do you emit a signal (from your image provider class) when the image is changed ?

                if yes, than you can do the following, inside your qml file (excerpt from a project/challenge of mine)

                Image {
                        id: img
                        property bool counter: false
                
                        asynchronous: false
                        source: "image://live/image"
                        anchors.fill: parent
                        fillMode: Image.PreserveAspectFit
                        cache: false
                
                        function reload() {
                            counter = !counter
                            source = "image://live/image?id=" + counter
                        }
                
                        Connections{
                            target: liveImageProvider
                            onImageChanged: img.reload()
                       }
                    }
                

                @J-Hilk, I think that is missing initialization of counter. Also that seems a bit hacky (thought the cleanest solution I have seen so far). Is it not possible to just do onImageChanged: img.sourceChanged(); ?

                J.HilkJ Offline
                J.HilkJ Offline
                J.Hilk
                Moderators
                wrote on last edited by
                #9

                Hi @Puya and welcome,

                I think that is missing initialization of counter

                not really QML doesn't really do uninitialized. The best you can have is that type casting fails and you get a var = undefined

                that said this line

                property bool counter: false

                defines counter to be false after Component.onCompletion

                Is it not possible to just do onImageChanged: img.sourceChanged(); ?

                I don't think so. From a quick look into the source code, I would say, you have to call the virtual load function of QQuickImage which is protected.
                So the only way to do it from the outside is to change the source or derive your own class from it and expose the function.


                Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                Q: What's that?
                A: It's blue light.
                Q: What does it do?
                A: It turns blue.

                L 2 Replies Last reply
                1
                • J.HilkJ J.Hilk

                  Hi @Puya and welcome,

                  I think that is missing initialization of counter

                  not really QML doesn't really do uninitialized. The best you can have is that type casting fails and you get a var = undefined

                  that said this line

                  property bool counter: false

                  defines counter to be false after Component.onCompletion

                  Is it not possible to just do onImageChanged: img.sourceChanged(); ?

                  I don't think so. From a quick look into the source code, I would say, you have to call the virtual load function of QQuickImage which is protected.
                  So the only way to do it from the outside is to change the source or derive your own class from it and expose the function.

                  L Offline
                  L Offline
                  LS-KS
                  wrote on last edited by
                  #10
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • J.HilkJ J.Hilk

                    Hi @Puya and welcome,

                    I think that is missing initialization of counter

                    not really QML doesn't really do uninitialized. The best you can have is that type casting fails and you get a var = undefined

                    that said this line

                    property bool counter: false

                    defines counter to be false after Component.onCompletion

                    Is it not possible to just do onImageChanged: img.sourceChanged(); ?

                    I don't think so. From a quick look into the source code, I would say, you have to call the virtual load function of QQuickImage which is protected.
                    So the only way to do it from the outside is to change the source or derive your own class from it and expose the function.

                    L Offline
                    L Offline
                    LS-KS
                    wrote on last edited by
                    #11

                    @J-Hilk I found this thread by googling. I need to update three images by button or when a Dialog is opened.
                    the source is calculated by row /col of my tablemodel.

                    The ''bool trick' only works only two times:

                    • first the url ends with 'false'
                    • second time the url end with 'true'

                    I had the idea to change he counter to an int because i already ignore the value in mey requestImage(). But this worked only once when counter is 0.

                    Here are some snippets:

                    Column{
                                    leftPadding: 5
                                    Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
                                    id: slotB
                                    Text{
                                        id: slotBtext
                                        text: "Slot B: Detected ID: "+ main_rect.slotid_b
                                    }
                                    Rectangle{
                                        width: main_rect.width/2 -15
                                        height: 125
                                        radius: 5
                                        border.width: 2
                                        border.color: 'black'
                                        Image{
                                            id: slotBImage
                                            property int counter: 0
                                            anchors.fill: parent
                                            fillMode: Image.PreserveAspectFit
                                            cache: false
                    
                                        }
                                    }
                                }
                    

                    loadImages()

                        function loadImages(){
                            //
                    
                            slotAImage.counter += slotAImage.counter
                            let a_sourcestring = "image://stockimage/"+ main_rect.row + "_" + main_rect.col +"_A.png" + slotAImage.counter
                            slotAImage.counter += slotBImage.counter
                            let b_sourcestring = "image://stockimage/"+ main_rect.row + "_" + main_rect.col +"_B.png" + slotBImage.counter
                            slotAImage.counter += palletImage.counter
                            let pallet_string = "image://stockimage/" + main_rect.row + "_" + main_rect.col +"_Pallet.png" + slotBImage.counter
                            slotAImage.source = a_sourcestring
                            slotBImage.source = b_sourcestring
                            palletImage.source = pallet_string
                        }
                    

                    Any idea how to get this working?

                    J.HilkJ 1 Reply Last reply
                    0
                    • L LS-KS

                      @J-Hilk I found this thread by googling. I need to update three images by button or when a Dialog is opened.
                      the source is calculated by row /col of my tablemodel.

                      The ''bool trick' only works only two times:

                      • first the url ends with 'false'
                      • second time the url end with 'true'

                      I had the idea to change he counter to an int because i already ignore the value in mey requestImage(). But this worked only once when counter is 0.

                      Here are some snippets:

                      Column{
                                      leftPadding: 5
                                      Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
                                      id: slotB
                                      Text{
                                          id: slotBtext
                                          text: "Slot B: Detected ID: "+ main_rect.slotid_b
                                      }
                                      Rectangle{
                                          width: main_rect.width/2 -15
                                          height: 125
                                          radius: 5
                                          border.width: 2
                                          border.color: 'black'
                                          Image{
                                              id: slotBImage
                                              property int counter: 0
                                              anchors.fill: parent
                                              fillMode: Image.PreserveAspectFit
                                              cache: false
                      
                                          }
                                      }
                                  }
                      

                      loadImages()

                          function loadImages(){
                              //
                      
                              slotAImage.counter += slotAImage.counter
                              let a_sourcestring = "image://stockimage/"+ main_rect.row + "_" + main_rect.col +"_A.png" + slotAImage.counter
                              slotAImage.counter += slotBImage.counter
                              let b_sourcestring = "image://stockimage/"+ main_rect.row + "_" + main_rect.col +"_B.png" + slotBImage.counter
                              slotAImage.counter += palletImage.counter
                              let pallet_string = "image://stockimage/" + main_rect.row + "_" + main_rect.col +"_Pallet.png" + slotBImage.counter
                              slotAImage.source = a_sourcestring
                              slotBImage.source = b_sourcestring
                              palletImage.source = pallet_string
                          }
                      

                      Any idea how to get this working?

                      J.HilkJ Offline
                      J.HilkJ Offline
                      J.Hilk
                      Moderators
                      wrote on last edited by
                      #12

                      hi @LS-KS and welcome

                      It's been a while since I last dealed with this!

                      You never increase slotBImage.counter but only ever add to slotAImage.counter is that intended ?

                      If you wan't a working example, I have this old project of mine:

                      https://github.com/DeiVadder/Sandepile-Challenge-QML.git

                      as you can see the c++ function takes the counter as String so, there's no reason for it not also working with a real counter.

                      But, IIRC, you'll need a different ID each time or the QML component doesn't update, but continues to show the cached Image rather than fetching the data anew from qml


                      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                      Q: What's that?
                      A: It's blue light.
                      Q: What does it do?
                      A: It turns blue.

                      L 1 Reply Last reply
                      1
                      • J.HilkJ J.Hilk

                        hi @LS-KS and welcome

                        It's been a while since I last dealed with this!

                        You never increase slotBImage.counter but only ever add to slotAImage.counter is that intended ?

                        If you wan't a working example, I have this old project of mine:

                        https://github.com/DeiVadder/Sandepile-Challenge-QML.git

                        as you can see the c++ function takes the counter as String so, there's no reason for it not also working with a real counter.

                        But, IIRC, you'll need a different ID each time or the QML component doesn't update, but continues to show the cached Image rather than fetching the data anew from qml

                        L Offline
                        L Offline
                        LS-KS
                        wrote on last edited by LS-KS
                        #13

                        @J-Hilk Thank you!
                        You are absolutely right.
                        I was a bit fast to change the property to int. Here is the refactored and working function:

                        function loadImages(){
                                slotAImage.counter += 1
                                let a_sourcestring = "image://stockimage/"+ main_rect.row + "_" + main_rect.col +"_A.png" + slotAImage.counter
                                slotBImage.counter += 1
                                let b_sourcestring = "image://stockimage/"+ main_rect.row + "_" + main_rect.col +"_B.png" + slotBImage.counter
                                palletImage.counter += 1
                                let pallet_string = "image://stockimage/" + main_rect.row + "_" + main_rect.col +"_Pallet.png" + slotBImage.counter
                                slotAImage.source = a_sourcestring
                                slotBImage.source = b_sourcestring
                                palletImage.source = pallet_string
                            }
                        

                        First issue was the cpoy/paste error of the counters. second issue was not to increase by 1 or anything else. So the counter would always be 0.

                        But i can confirm that it wont work if the property is bool, something like that:

                            function loadImages(){
                                slotAImage.counter = !slotAImage.counter 
                                let a_sourcestring = "image://stockimage/"+ main_rect.row + "_" + main_rect.col +"_A.png" + slotAImage.counter
                                slotBImage.counter = !slotBImage.counter
                                let b_sourcestring = "image://stockimage/"+ main_rect.row + "_" + main_rect.col +"_B.png" + slotBImage.counter
                                palletImage.counter = !palletImage.counter 
                                let pallet_string = "image://stockimage/" + main_rect.row + "_" + main_rect.col +"_Pallet.png" + slotBImage.counter
                                slotAImage.source = a_sourcestring
                                slotBImage.source = b_sourcestring
                                palletImage.source = pallet_string
                            }
                        

                        As described it works two times. Is it possible that all source strings get stored somehow? Actually i have nt much time to spend on this but i looked for a possibility to purge the Image from the QML Type -without success yet.

                        1 Reply Last reply
                        0

                        • Login

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