动态创建QML状态

时间:2017-03-24 11:01:46

标签: qt qml

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

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属性动态地在states定义rawStates属性中?

也许是这样的:

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
            }
        }
    }
}

2 个答案:

答案 0 :(得分:3)

我不使用States而是使用普通的javascript关联数组。 您无法使用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 } } } } 。没有任何事情可以通过行为来完成,但在大多数情况下它已经足够了。

<h1>Weekly Pay Calculator</h1>




    <script>

        function myFunction() {

        var user = document.getElementById("user").value;
        var hours = document.getElementById("hours").value;
        var total = hours * 10;
        document.getElementById("result").innerHTML = user + " " + "£" + total + " " + "is your total pay for the shifts.";
        };


        function clearForm()
        {
            $(':input').not(':button, :submit, :reset, :hidden, :checkbox, :radio').val('');
            $(':checkbox, :radio').prop('checked', false);
        };


    </script>













    User ID <input type="text" id="user" maxlength="4" size="4"><br>


    <h3>Weekly Hours at (£10 per hour)</h3>

    <select id ="hours">
      <option value="">0</option>
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="4">4</option>
      <option value="5">5</option>
    </select>


    <br>


    <p>&nbsp;</p>


    <br>


    <p>&nbsp;</p>

    <input type="submit" value="Net Pay" onclick="myFunction()">
    <input type="submit" value="Clear Screen" onclick="clearForm()">

    <p>&nbsp;</p>

    <h4 id="result"></h4>

答案 1 :(得分:1)

也许这会对你有所帮助:

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
            }
        }
    }
}

似乎不太可能直接将State添加到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'
        }
    ]
}