Question

On the button created on QML the relative position of the image and the text need to be changed dynamically. So I created a layout property to change this position. When I initialise the button with any position it works fine, but when I change the position programmatically there is an error.

  • layout = 0: image on top of text
  • layout = 1: text on top of image
  • layout = 2: text on right of image
  • layout = 3: image on right of text
  • layout = 4: text on front of image

When I change the layout from 0 to 1 and vice versa there is no error.
When I change the layout from 2 to 3 and vice versa there is no error.
If I change the layout to 5 between any change of layout works. When I change the Layout to 5 all the anchors properties are reset.

Clearly there is something wrong with the anchors properties binding but I don't know what it is. If anyone has a code that works or could tell me what is the problem I would appreciate.

The code:

Rectangle {
    Gradient {
        id:myGradient
        GradientStop { position: 0.0; color: neoButton.color }
        GradientStop { position: 1.0; color: Qt.darker(neoButton.color,1.5) }
    }
    Gradient {
        id:myDarkyGradient
        GradientStop { position: 0.0; color: Qt.darker(neoButton.color,1.7) }
        GradientStop { position: 1.0; color: Qt.darker(neoButton.color,1.7) }
    }
    property string image
    property color fontColor
    property int fontSize:70
    property int layout:2
    property string text:"Button"

    clip: true
    id:neoButton
    width: 300
    height: 160
    x:50
    y:50

    border.color : "black"
    border.width: 1
    radius: 5
    Rectangle{
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
        implicitWidth:{
            if((neoButton.layout==0)||(neoButton.layout==1)||(neoButton.layout==4)){
               return Math.max(buttonLabel.implicitWidth, buttonImage.implicitWidth)
            }else{
                return buttonLabel.implicitWidth+buttonImage.implicitWidth
            }
        }
        implicitHeight:{
            if((neoButton.layout==0)||(neoButton.layout==1)){
              return  buttonLabel.implicitHeight + buttonImage.implicitHeight
            }else{
               return Math.max(buttonLabel.implicitHeight, buttonImage.implicitHeight)
            }
        }
        color: "blue"
        Image{
            id:buttonImage
            anchors.horizontalCenter:{
                if((neoButton.layout==0)||(neoButton.layout==1)||(neoButton.layout==4)){
                  console.log("Image horizontalCenter:parent.horizontalCenter" )
                    return parent.horizontalCenter
                }else{
                   console.log("Image horizontalCenter:undefined" )
                    return undefined
                }
            }
           anchors.verticalCenter: {
               if((neoButton.layout==2)||(neoButton.layout==3)||(neoButton.layout==4)){
                 console.log("Image verticalCenter:parent.verticalCenter" )
                   return parent.verticalCenter
               }else{
                   console.log("Image verticalCenter:undefined" )
                   return undefined
                }
           }
            source:"file:///D:/QT Projects/build-PutCppAndQmlTogether-Desktop_Qt_5_1_1_MinGW_32bit-Debug/MyTempFiles/Images/B_0_0_0.png"
            anchors.top: {
                if(neoButton.layout == 1){
                    console.log("Image top:buttonLabel.bottom" )
                    return buttonLabel.bottom
                } else if(neoButton.layout == 0){
                    console.log("Image top:parent.top" )
                    return parent.top
                }else{
                    console.log("Image top:undefined" )
                    return undefined
                 }
            }
            anchors.left: {
                if(neoButton.layout == 3){                        
                    return buttonLabel.right
                }
                else if(neoButton.layout == 2){                       
                    return parent.left
                }else{                        
                    return undefined
                 }
            }
        }
        Text{
            id: buttonLabel
            font.pixelSize:20

            anchors.horizontalCenter:{
                if((neoButton.layout==0)||(neoButton.layout==1)||(neoButton.layout==4)){                         
                  return  parent.horizontalCenter
                }else{                        
                    return undefined
                 }
            }
           anchors.verticalCenter: {
               if((neoButton.layout==2)||(neoButton.layout==3)||(neoButton.layout==4)){                      
                   return parent.verticalCenter
               }else{                       
                   return undefined
                }
           }
           anchors.top: {
               if(neoButton.layout == 0){                       
                   return buttonImage.bottom
               }
               else if(neoButton.layout == 1){                       
                   return parent.top
               }else{                       
                   return undefined
                }
           }
           anchors.left: {
               if(neoButton.layout == 2){                       
                   return buttonImage.right
               } else if(neoButton.layout == 3){                      
                   return parent.left
               }else{                       
                   return undefined
                }
           }
            text: neoButton.text                
        }
    }

    signal buttonClick()
    onButtonClick: {
        console.log(buttonLabel.text + " clicked" )
        layout=2
    }

    MouseArea{
        id:buttonMouseArea
        anchors.fill: parent
        onClicked: parent.buttonClick()
        hoverEnabled: true
        onEntered:{
            parent.border.width= 2
        }
        onCanceled:{
            parent.border.width= 1
        }
        onExited: {
            parent.border.width= 1                             
        }
    }
    gradient: buttonMouseArea.pressed ? myDarkyGradient : myGradient
}
Was it helpful?

Solution

If you add some more debugging output, you can observe the order in which the properties change, then you set a new layout.

Example 0 -> 2

/* Console log output
'Text Button' clicked: Change layout 0 to 2
Label horizontalCenter: undefined
Label verticalCenter: parent.verticalCenter
Label top: undefined
Label left: buttonImage.right
Image horizontalCenter:undefined
Image verticalCenter:parent.verticalCenter
Image top: undefined
Image left: parent.left
Rectangle implicitWidth: Sum
Rectangle implicitHeight: Max
*/

That means the outer rectangle is recalculated last. Thus all the other alignments happen relative to the old rectangle.

To reset the anchors I'd implement the auto-generated function 'onLayoutChanged':

onLayoutChanged: {
    console.log("Layout changed to new id: " + layout + ". Time to reset alignments using javascript")

    switch(layout) {
    case 0:
        // do stuff
        break;
    case 1:
        // do stuff
        break;
    case 2:
        // do stuff
        break;
    case 3:
        // do stuff
        break;
    case 4:
        // do stuff
        break;
    default:
        console.log("Invalid layout id.")
        break;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top