将 ListView currentItem 信息传递给外部组件

Pass ListView currentItem info to external component

我正在使用 Qt 逻辑作为 backbone 应用程序开发 QML,我遇到以下情况: 在启动时,QML ApplicationWindow 与其 StatusBar 一起显示,其中包含两个状态图标和一个可检查的 Button,名为 UeStaffSelector 用于工作人员登录。当我按下 UeStaffSelector 时,Window named ueStaffView(它包含 ListView named ueListViewWorkers)弹出并从 ueListViewWorkers 用户选择登录过程, 如下截图所示:

现在,我有另一个自定义 QML Item,名为 UeKeypad,代表用户的 pin 输入,因此 he/she 可以成功登录系统。从ListView中选择delegate后,必须弹出此UeKeypad。 问题是,我从哪里调用 UeKeypad?从 delegateListView 还是 ApplicationWindow?另外,如何将用户信息(用户图像、用户名和用户密码)传递给 UeKeypad?

QML 绑定很酷,非常酷。您可以声明键盘类型与当前委托内的类型之间的直接连接,即当前 Image 和 user/password,而不是强制传递数据。这样,一旦选择了代表,就会设置键盘内的相应变量。

这个结果可以使用 States 来实现。我们定义了两个 States,一个 VISIBLE 状态用于向用户显示 image/username 的键盘和一个 HIDDEN 状态用于隐藏键盘,当没有选择可用时。明智地使用 when 子句,即以互斥的方式,我们可以确保永远不会命中默认值 - 空字符串 - State ,因此组件的整体 state 总是持续的。

使用 States 的一个副作用是我们可以很容易地定义一个 Transition 在两个 States 之间移动,从而定义你感兴趣的那种滑动效果中。另外,通过以声明的方式定义所有关联,表单仍然可以与设计者edited/viewed。使用命令式代码这是不可能的。

可以通过以下方式访问当前委托中的实际值 currentItem 中的值(如果在顶级类型中不可用,则 aliased)或通过模型 get。注意 index 的用法,RepeaterListView 的附加 属性。

以下示例总结了这种方法,还提供了两种访问 ListView 数据的方法。

import QtQuick 2.0
import QtQuick.Controls 1.3
import QtQuick.Extras 1.4
import QtQuick.Layouts 1.2
import QtQuick.Window 2.2

ApplicationWindow {
    width: 600
    height: 800
    visible: true

    Column {
        id: keypad
        x: parent.width - width     // put in the corner
        z: 2
        Row {
            width: 200
            spacing: 10
            Image {
                id: keyImage
                width: 100
                height: 100
            }
            Text {
                id: keyText
                anchors.verticalCenter: parent.verticalCenter
                font.pixelSize: 30
            }
        }

        Grid{
            columns: 3
            columnSpacing: 5
            rowSpacing: 5
            Repeater {
                model: 9
                Button {
                    text: index + 1
                    onClicked: console.info(text + " " + keyText.text)
                }
            }
        }

        states: [
            State {
                name: "HIDDEN"
                PropertyChanges {
                    target: keypad
                    y: keypad.parent.height
                }
                when: list.currentIndex < 0
            },
            State {
                name: "VISIBLE"
                PropertyChanges {
                    target: keypad
                    y: keypad.parent.height / 2 - keypad.height / 2
                }
                PropertyChanges {
                    target: keyImage
                    source: list.model.get(list.currentIndex).image//list.currentItem.imagePath
                }
                PropertyChanges {
                    target: keyText
                    text: list.model.get(list.currentIndex).user//list.currentItem.label
                }
                when: list.currentIndex >= 0
            }
        ]

        transitions: Transition {
            NumberAnimation {
                properties: "y";
                duration: 1000
                easing.type: Easing.InQuad
            }
        }
    }


    ListView {
        id: list
        anchors.fill: parent
        currentIndex: -1
        model: ListModel{
            ListElement {
                image: "http://www.theapricity.com/forum/image.php?u=9098&dateline=1442619767"
                user: "first"
            }

            ListElement {
                image: "http://a.dilcdn.com/bl/wp-content/uploads/sites/8/2013/10/angry-cat-200x200.jpg"
                user: "second"
            }

            ListElement {
                image: "http://images.all-free-download.com/images/graphicthumb/walking_sand_cat_516744.jpg"
                user: "third"
            }
        }

        delegate: Rectangle {
            width: ListView.view.width
            height: 220
            property alias imagePath: img.source
            property alias label: label.text
            RowLayout {
                anchors.fill: parent
                Image {
                    id: img
                    width: 100
                    height: 100
                    fillMode: Image.PreserveAspectFit
                    source: image
                    Layout.alignment: Qt.AlignLeft
                    Layout.preferredWidth: 100
                }

                Text {
                    id: label
                    Layout.fillWidth: true
                    Layout.alignment: Qt.AlignCenter
                    text: user
                    font.pixelSize: 30
                }
                MouseArea{
                    anchors.fill: parent
                    onClicked: list.currentIndex = index   //set the current item
                }
            }
            color: ListView.isCurrentItem  ? "steelblue" : "transparent"
            scale: ListView.isCurrentItem ? 1 : 0.7
        }
    }
}

正如我们上面所讨论的,与命令式方法相比,这种方法显然具有许多优势。主要是因为 更自然 在 QML 中定义(某种)执行工作流的方式。您仍然可以(有时更容易)为此目的定义命令式代码。请注意,在大多数情况下,如果您遵循命令式方式,那么您只是 "doing it wrong".