Search code examples
qmlqt5qtquick2qtquickcontrols

Image size different after second click on it


I have following minimal working example, taken from my current project:

import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4

Window {
    visible: true

    width: Screen.width/2
    height: Screen.height/2

    property real ueMinOpacity: 0.00
    property real ueMaxOpacity: 1.00

    Rectangle {
        anchors.fill: parent
        anchors.margins: 8

        border.color: "#4682b4"
        radius: 16

        clip: true

        gradient: Gradient {
            GradientStop {
                position: 0
                color: "#ffffff"
            }   // GradientStop

            GradientStop {
                position: 1
                color: "#303030"
            }   // GradientStop
        }   // Gradient

        Rectangle {
            anchors.fill: parent
            antialiasing: true

            border.color: "#4682b4"
            border.width: 1

            radius: 16
            clip: true

            gradient: Gradient {
                GradientStop {
                    position: 0
                    color: "#ffffff"
                }   // GradientStop

                GradientStop {
                    position: 1
                    color: "#000000"
                }   // GradientStop
            }   // Gradient

            RowLayout {
                spacing: 8
                anchors.fill: parent

                TextField {
                    id: ueProductSearchTextField

                    antialiasing: true

                    Layout.fillWidth: true
                    Layout.fillHeight: true
                    Layout.alignment: Qt.AlignLeft|Qt.AlignVCenter
                    Layout.margins: 8

                    placeholderText: qsTr("Enter product info")
                }   // TextField

                Rectangle {
                    id: ueImageWrapper

                    Layout.fillWidth: true
                    Layout.fillHeight: true
                    Layout.alignment: Qt.AlignRight|Qt.AlignVCenter
                    Layout.margins: 8

                    antialiasing: true

                    border.color: "#4682b4"
                    border.width: 1

                    radius: 16
                    clip: true
                    visible: ueProductSearchTextField.length > 0

                    gradient: Gradient {
                        GradientStop {
                            position: 0
                            color: "#636363"
                        }   // GradientStop

                        GradientStop {
                            position: 1
                            color: "#303030"
                        }   // GradientStop
                    }   // Gradient

                    Image {
                        anchors.fill: parent

                        source: "http://www.clipartbest.com/cliparts/9iR/gEX/9iRgEXXxT.png"

                        antialiasing: true

                        clip: true

                        smooth: true

                        fillMode: Image.PreserveAspectFit

                        horizontalAlignment: Image.AlignHCenter
                        verticalAlignment: Image.AlignVCenter

                        sourceSize.width: 96
                        sourceSize.height: 96
                    }   // Image

                    MouseArea {
                        anchors.fill: parent
                        enabled: ueImageWrapper.visible

                        onClicked: {
                            ueProductSearchTextField.text="";
                        }   // onClicked
                    }   // MouseArea


                    onWidthChanged: {
                        print("ueImageWrapper.width:"+ueImageWrapper.width);
                    }   // onWidthChanged

                    onHeightChanged: {
                        print("ueImageWrapper.height:"+ueImageWrapper.height);
                    }   // onHeightChanged
                }   // Rectangle
            }   // RowLayout
        }   // Rectangle
    }   // Rectangle
}   // Window

Now, the purpose of this Item/Rectangle is to filter database records according to TextField's entered value, which works perfectly. However, once TextField's text is not empty anymore (when user enters some string), on the right side of Layout Image for clearing text is shown via OpacityAnimator. Once the app is launched, I get following screenshot - clear text icon is hidden since there is not text in TextField: App Start Screenshot Then, I enter some text into TextField and clear text icon pops up: Tesxt entered Screenshot Then, for instance, I clear text by clicking on clear text icon and it (icon) is hidden again, which is ok:
Text cleared Screenshot And finally, I reenter text into TextField, clear text icon is visible again, but it has different size: enter image description here Why? I did not change the code. It must be some problem with Layouts, but I simply do not see it! Here is also a debug output from onWidthChanged and onHeightChanged handlers:

qml: ueImageWrapper.width:37.56521739130435
qml: ueImageWrapper.height:480
qml: ueImageWrapper.width:132.92307692307693
qml: ueImageWrapper.width:133.83783783783784


Solution

  • BaCaRoZzo's suggestion works, but I'm also a bit unsure about why it behaves the way it does. If you take a simpler example:

    import QtQuick 2.6
    import QtQuick.Window 2.2
    import QtQuick.Layouts 1.0
    import QtQuick.Controls 1.0
    
    Window {
        visible: true
        width: 800
        height: 800
    
        Shortcut {
            sequence: "Ctrl+Q"
            onActivated: Qt.quit()
        }
    
        Item {
            id: boundary
            width: 400
            height: 400
            anchors.centerIn: parent
    
            RowLayout {
                anchors.fill: parent
    
                Rectangle {
                    Layout.fillWidth: true
                    Layout.fillHeight: true
                    color: "steelblue"
                }
    
                Rectangle {
                    id: rect
                    Layout.fillWidth: true
                    Layout.fillHeight: true
                    color: "salmon"
                    visible: false
                }
            }
        }
    
        Rectangle {
            anchors.fill: boundary
            color: "transparent"
            border.color: "black"
        }
    
        Button {
            text: "Toggle visibility"
            onClicked: rect.visible = !rect.visible
        }
    }
    

    The second rectangle starts off being invisible, and is then shown/hidden by clicking the button. However, when it starts off as invisible, it never gets a size once shown. On the other hand, if it starts off visible, then it gets half the width of the layout.

    If you read the documentation carefully, it doesn't say that it's necessary to set a preferredWidth/preferredHeight if you just want to make an item fill the available space. For that reason, it seems like a bug in how layouts handle initial visibility of their items. I'd suggest filing a bug report.