【问题标题】:Creating QML States dynamically动态创建 QML 状态
【发布时间】:2017-03-24 11:01:45
【问题描述】:

我想制作一个图标组件,根据它的状态改变它的图片和颜色:

StateIcon.qml:

import QtQuick 2.0
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0

Item {
    Layout.preferredWidth: appLayout.icon.prefWidth
    Layout.preferredHeight: appLayout.icon.prefHeight

    property variant stateImage: stateImageInstance
    Image {
        id: stateImageInstance
        width: appLayout.icon.prefWidth
        height: appLayout.icon.prefWidth

        sourceSize.width: width
        sourceSize.height: height
    }

    property variant imageOverlay: imageOverlayInstance
    ColorOverlay {
        id: imageOverlayInstance
        anchors.fill: stateImage
        source: stateImage
    }

    transitions: Transition {
        SequentialAnimation {
            NumberAnimation {
                target: stateImage; property: "scale"
                to: 0; duration: 100
            }
            PropertyAction {
                target: stateImage; property: "source"
            }
            PropertyAction {
                target: imageOverlay; property: "color"
            }
            NumberAnimation {
                target: stateImage; property: "scale"
                to: 1; duration: 100
            }
        }
    }
}

问题是我必须在组件实例中定义状态:

main.qml:

StateIcon {
    id: stateIcon
    states: [
        State {
            name: "state1";
            PropertyChanges {
                target: stateIcon.stateImage
                source: "qrc:/resources/icons/icon1.svg"
            }
            PropertyChanges {
                target: stateIcon.imageOverlay; color: "gray"
            }

        },
        State {
            name: "state2";
            PropertyChanges {
                target: stateIcon.stateImage
                source: "qrc:/resources/icons/icon2.svg"
            }
            PropertyChanges {
                target: stateIcon.imageOverlay; color: "green"
            }
        }
        ...
    ]

    state: "state1"
}

现在我想知道是否可以在某个数组中只定义状态名称、颜色和来源:

main.qml:

StateIcon {
    id: stateIcon
    rawStates: [
           {
               name: "state1",
               iconSource: "qrc:/resources/icons/state1.svg",
               color: "green"
           },
           {
               name: "state2",
               iconSource: "qrc:/resources/icons/state2.svg",
               color: "green"
           },
           ...
       ]

    state: "state1"
}

并在StateIcon.qml 中使用rawStates 属性动态定义states 属性?

也许是这样的:

StateIcon.qml:

import QtQuick 2.0
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0

Item {
    property variant rawStates

    Layout.preferredWidth: appLayout.icon.prefWidth
    Layout.preferredHeight: appLayout.icon.prefHeight

    Image {
        id: stateImage
        width: appLayout.icon.prefWidth
        height: appLayout.icon.prefWidth

        sourceSize.width: width
        sourceSize.height: height
    }

    ColorOverlay {
        id: imageOverlay
        anchors.fill: stateImage
        source: stateImage
    }

    states: [
        for(var i=0; i<rawStates.length; ++i) {
            ?
        }
    ]

    transitions: Transition {
        SequentialAnimation {
            NumberAnimation {
                target: stateImage; property: "scale"
                to: 0; duration: 100
            }
            PropertyAction {
                target: stateImage; property: "source"
            }
            PropertyAction {
                target: imageOverlay; property: "color"
            }
            NumberAnimation {
                target: stateImage; property: "scale"
                to: 1; duration: 100
            }
        }
    }
}

【问题讨论】:

  • 您是否尝试过Instantiator 来创建状态,并将它们填充到states 中?我不知道这是否可能,但现在几乎没有时间尝试。
  • 我尝试使用Components 创建states 数组。但我没有成功。也许其他人可以做到。
  • 为什么需要在这里使用状态?您可以使用关联数组属性轻松做到这一点。
  • @GrecKo 你能写一个小例子吗?

标签: qt qml


【解决方案1】:

我将使用普通的 javascript 关联数组,而不是使用 States。 您不能使用transitions,但可以使用Behavior。行为无法解决任何问题,但大多数时候已经足够了。

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQml 2.2

ApplicationWindow {
    id: mainWindow
    visible: true
    minimumWidth: 500
    minimumHeight: 500

    Row {
        Rectangle {
            id: rect
            width: 100
            height: 100

            property var stateDescriptors: {
                'state0': {color: 'green'},
                'state1': {color: 'red'},
                'state2': {color: 'blue'},
                'state3': {color: 'purple'},
                'state4': {color: 'orange'}
            }
            property string iconState: "state0"

            Text {
                anchors.fill: parent
                text: parent.iconState
            }
            color: stateDescriptors[iconState].color
            Behavior on iconState {
                SequentialAnimation {
                    NumberAnimation {
                        target: rect; property: "scale"
                        to: 0; duration: 100
                    }
                    PropertyAction { } //actually change the iconState here, since the color is binded to it, it will also change between the 2 scale animations
                    NumberAnimation {
                        target: rect; property: "scale"
                        to: 1; duration: 100
                    }
                }
            }
        }

        Button {
            text: 'change state'
            property int count: 0
            onClicked: {
                count = (count + 1) % Object.keys(rect.stateDescriptors).length
                rect.iconState = 'state' + count
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    也许这对你有帮助:

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    import QtQml 2.2
    
    ApplicationWindow {
        id: mainWindow
        visible: true
        minimumWidth: 500
        minimumHeight: 500
    
        Row {
            Rectangle {
                id: rect
                width: 100
                height: 100
    
                Text {
                    anchors.fill: parent
                    text: parent.state
                }
    
                property var myStates: []
                states: myStates
    
                onStateChanged: console.log(Object.keys(rect.states))
            }
    
            Button {
                text: 'add state'
                onClicked: {
                    rect.myStates.push(statePrototype.createObject(rect,
                                                               {
                                                                   name: 'state' + count,
                                                                   color: Qt.rgba(Math.random(count),
                                                                                  Math.random(count),
                                                                                  Math.random(count),
                                                                                  Math.random(count))
                                                               }))
                    rect.myStatesChanged()
                    count++
                }
            }
    
            Button {
                text: 'change state'
                onClicked: {
                    rect.state = 'state' + (count1 % count)
                    count1++
                }
            }
    
        }
    
        property int count: 0
        property int count1: 0
        Component {
            id: statePrototype
            State {
                id: st
                property color color
                PropertyChanges {
                    target: rect
                    color: st.color
                }
            }
        }
    }
    

    直接将States 加到states 上似乎不太容易。随着对自定义property var myStates 的加倍努力,它突然起作用了。 别忘了告诉大家,那个myStatesChanged()加完东西!

    编辑 再一次,使用 JS 对象列表和实例化器。方法一样

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    import QtQml 2.2
    
    ApplicationWindow {
        id: mainWindow
        visible: true
        minimumWidth: 500
        minimumHeight: 500
    
        Row {
            Rectangle {
                id: rect
                width: 100
                height: 100
    
                Text {
                    anchors.fill: parent
                    text: parent.state
                }
    
    
    
                property var myStates: []
                states: myStates
                onStateChanged: console.log(Object.keys(rect.states))
            }
    
            Button {
                text: 'change state'
                property int count: 0
                onClicked: {
                    rect.state = 'state' + count % rect.myStates.length
                    count ++
                }
            }
    
            Button {
                text: 'add states'
                onClicked: {
                    stateDescriptors.push( { name: 'state' + stateDescriptors.length, color: Qt.rgba(Math.random(1),
                                                                                                            Math.random(2),
                                                                                                            Math.random(3),
                                                                                                            Math.random(4)) })
                    stateDescriptorsChanged()
                }
            }
        }
    
        Instantiator {
            model: stateDescriptors
            delegate: State {
                name: modelData.name
                PropertyChanges {
                    target: rect
                    color: modelData.color
                }
                Component.onCompleted: {
                    console.log('created', modelData.name)
                    rect.myStates.push(this)
                    rect.myStatesChanged()
                }
                Component.onDestruction: {
                    console.log('destroy', modelData.name)
                    rect.myStates.pop()
                }
            }
        }
    
        property var stateDescriptors: [
            {
                name: 'state0',
                color: 'green'
            },
    
            {
                name: 'state1',
                color: 'red'
            },
    
            {
                name: 'state2',
                color: 'blue'
            },
    
            {
                name: 'state3',
                color: 'purple'
            },
    
            {
                name: 'state4',
                color: 'orange'
            }
        ]
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多