[SOLVED] Creating a QML Image that will load different source if one source fails to load



  • I am trying to create a QML Element that has three sources:

    source1: This is the first source that will be attempted to be loaded
    source2: If source1 is empty or it fails loading this source will be used
    sourceError: If source1 and source2 fail to load this one will be used.

    I have tried doing this with states, but get errors like
    <Unknown File>: QML StateGroup: Can't apply a state change as part of a state definition.

    I get that error when I change the state when the image status changes to Image.Error.

    So I tried just updating the source property. I am seeing two issues:

    1. If i do the following the status remains Image.Null
      @
      souce = "/img/path/does/not/exist/img.png"

    console.log("status " + (status == Image.Null)); // logs 'status true'
    @

    1. So I try setting the source on the "onStatusChanged" signal; if status == Image.Error change to the next source. This works with 2 source just fine, but when I add in the third source it only attempts to load the first two. I'm assuming it doesn't want to emit the onStatusChanged signal within an onStatusChanged signal.

    Has anyone tried to do this with success. Any hints would be great.


    I believe I could get this to work If I could add property changes to the end of the event queue ("AWT calls is that, not sure what qt calls is")


  • Moderators

    When you say you've tried it using states, how did you try it?



  • Logic with states:

    I had 3 states:

    1. "source1":
    • changed the image source to source1 property
    1. "source2":
    • changed the image source to source2 property
    1. "sourceError"
    • changed the image source to sourceError property

    on status changed to Image.Error I check the current state and changed it next in line. For example, if the current state was "source1" I would change it to "source2". This would give me the following error:
    <Unknown File>: QML StateGroup: Can’t apply a state change as part of a state definition.


  • Moderators

    I was able to get it to work using the following (though I'm sure there are a lot better ways):

    @
    import QtQuick 1.0

    Rectangle {
    width: 360
    height: 360

    Image {
    id: img
    property string source1: "!red.png"
    property string source2: "!green.png"
    property string source3: "blue.png"

      property int curr: 1
    
      signal failedToLoad
    
      anchors.centerIn:  parent
    
      source: source1
    
      onStatusChanged: {
         console.log("Status changed to " + status);
         if (status == Image.Error)
         {
            console.log("source: " + source + ": failed to load");
            source = "";
            failedToLoad()
         }
      }
    
      onFailedToLoad: {
         curr++;
      }
    
      onCurrChanged: {
         if      (curr == 1) { source = source1; }
         else if (curr == 2) { source = source2; }
         else if (curr == 3) { source = source3; }
         else { console.log("Cannot open"); }
      }
    

    }

    }
    @

    Quick and dirty, but it seems to work.



  • I haven't tested it, but maybe something like this?

    @
    Image {
    id: image
    property int errorCount: 0
    property string altSource
    property string errorSource

        onStatusChanged: {
            if (image.status == Image.Error) {
                errorCount += 1;
                if (errorCount == 1)
                    image.source = image.altSource;
                else
                    image.source = image.errorSource;
            }
        }
    }
    

    @


  • Moderators

    [quote author="Bradley" date="1310511624"]I haven't tested it, but maybe something like this?

    [/quote]

    That seemed to suffer from the same problem that he mentioned before. I think what's happening is that for some reason, if the status == Image.Error, and you try to load another image with an error, the status never changes from Image.Error, thus never triggering the onStatusChanged again. A workaround solution seems to be to reset the image source to "" in between load attempts, thus changing the status to Image.Null in the interim.

    I tweaked your code to the following:
    @
    Image {
    id: image
    property int errorCount: 0
    property string altSource
    property string errorSource

       anchors.centerIn:  parent
    
       onStatusChanged: {
           if (image.status == Image.Error) {
               errorCount += 1;
               if (errorCount == 1) {
                   image.source = ""  // Gotta clear the source 
                   image.source = image.altSource;
               } else {
                   image.source = image.errorSource;
               }
           }
       }
    

    }
    @

    and it worked.

    Edit to add: And much more cleanly than my original kludgy workaround. :)



  • That was the problem.

    Thanks for you help


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.