【问题标题】:Pass ListView currentItem info to external component将 ListView currentItem 信息传递给外部组件
【发布时间】:2015-10-05 13:01:41
【问题描述】:
我正在使用 Qt 逻辑作为主干应用程序开发 QML,我遇到以下情况:
在启动时,QML ApplicationWindow 与其StatusBar 一起显示,其中包含两个状态图标和一个可检查的Button,名为UeStaffSelector 用于工作人员登录。当我按下UeStaffSelector 时,弹出Window 名为ueStaffView(它包含ListView 名为ueListViewWorkers)并从ueListViewWorkers 中选择用户进行登录过程,如下图所示:
现在,我有另一个自定义 QML Item,命名为 UeKeypad,代表用户的 pin 输入,因此他/她可以成功登录系统。这个UeKeypad必须在delegate从ListView中选择后弹出。
问题是,我在哪里打电话给UeKeypad?来自delegate、ListView 或ApplicationWindow?另外,如何将用户信息(用户图像、用户名和用户密码)传递给UeKeypad?
【问题讨论】:
标签:
qt
qml
qtquick2
qt-signals
【解决方案1】:
QML 绑定很酷,非常酷。您可以声明键盘类型与当前委托中的类型(即当前Image 和用户/密码)之间的直接连接,而不是强制传递数据。这样一来,只要选择了一个委托,就会设置小键盘内的相应变量。
这个结果可以使用States 来实现。我们定义了两个States,一个VISIBLE 状态用于向用户显示图像/用户名的键盘,一个HIDDEN 状态用于隐藏键盘,当没有可用选择时。明智地使用when 子句,即以互斥的方式,我们可以确保默认的空字符串State 永远不会被命中,因此组件的整体state 始终是一致的。
使用States 的一个副作用是我们可以很容易地定义一个Transition 在两个States 之间移动,从而定义您感兴趣的滑动效果。此外,通过定义所有以声明的方式关联,仍然可以使用设计器编辑/查看表单。这对于命令式代码是不可能的。
可以通过以下方式访问当前委托中的实际值
currentItem 中的值(aliased 如果在顶级类型中不可用)或通过模型get。请注意index 的用法,这是Repeater 和ListView 的附加属性。
以下示例总结了这种方法,还提供了访问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 中定义(某种)执行工作流的更自然方式。您仍然可以(有时更容易)为此目的定义命令式代码。请注意,在大多数情况下,如果您遵循命令式的方式,那么您只是“做错了”。