我们知道在QML中,实现ListView是非常简单的一件事,但是如果大家想做一个多项选择的ListView,那么我们怎么办呢?我们可以参照在github上的一个MultipleSelectionListView.在它的实现中,它也使用了VisualDataModel QML Component.大家如果想更多了解该API的用法,用参照它的API介绍.
MultipleSelectionListView在Ubuntu的Core Apps里用的比较多,比如在我们的messaging及address book里都有用到,虽然它并不是我们Ubuntu Components里的一个标准的控件.这里我们想特别把它提出来就是希望有开发者能够在有的应用中需要用到时,参考我们这里的实现.
MultipleSelectionVisualModel.qml
import QtQuick 2.2
VisualDataModel {
id: contactVisualModel
property alias selectedItems: selectedGroup
groups: [
VisualDataGroup {
id: selectedGroup
name: "selected"
}
]
}
这里的定义其实就是一个
VisualDataModel.这里我们不累述.这里特别指出是这里有一个定义的groups.它的作用就是在Delegate的model之中定义了一个subset的项.这些项可以被用来filter我们model.这里我们定义了一个叫做"
selected"名称的 selectedGroup.
MultipleSelectionListView.qml
ListView {
id: listView
/*!
\qmlproperty model selectedItems
This property holds the list of selected items
*/
readonly property alias selectedItems: visualModel.selectedItems
/*!
\qmlproperty bool multipleSelection
This property holds if the selection will accept multiple items or single items
*/
property bool multipleSelection: true
/*!
\qmlproperty model listModel
This property holds the model providing data for the list.
*/
property alias listModel: visualModel.model
/*!
\qmlproperty Component listDelegate
The delegate provides a template defining each item instantiated by the view.
*/
property alias listDelegate: visualModel.delegate
/*!
\qmlproperty bool isInSelectionMode
This property holds a list with the index of selected items
*/
readonly property bool isInSelectionMode: state === "selection"
/*!
This handler is called when the selection mode is finished without be canceled
*/
signal selectionDone(var items)
/*!
This handler is called when the selection mode is canceled
*/
signal selectionCanceled()
/*!
Start the selection mode on the list view.
*/
function startSelection()
{
state = "selection"
}
/*!
Check if the item is selected
Returns true if the item was marked as selected or false if the item is unselected
*/
function isSelected(item)
{
if (item && item.VisualDataModel) {
return (item.VisualDataModel.inSelected === true)
} else {
return false
}
}
/*!
Mark the item as selected
Returns true if the item was marked as selected or false if the item is already selected
*/
function selectItem(item)
{
if (item.VisualDataModel.inSelected) {
return false
} else {
if (!multipleSelection) {
clearSelection()
}
item.VisualDataModel.inSelected = true
return true
}
}
/*!
Remove the index from the selected list
*/
function deselectItem(item)
{
var result = false
if (item.VisualDataModel.inSelected) {
item.VisualDataModel.inSelected = false
result = true
}
return result
}
/*!
Finish the selection mode with sucess
*/
function endSelection()
{
selectionDone(listView.selectedItems)
clearSelection()
state = ""
}
/*!
Cancel the selection
*/
function cancelSelection()
{
selectionCanceled()
clearSelection()
state = ""
}
/*!
Remove any selected item from the selection list
*/
function clearSelection()
{
if (selectedItems.count > 0) {
selectedItems.remove(0, selectedItems.count)
}
}
/*!
Select all items in the list
*/
function selectAll()
{
if (multipleSelection) {
visualModel.items.addGroups(0, visualModel.items.count, ["selected"] )
}
}
model: visualModel
MultipleSelectionVisualModel {
id: visualModel
}
Component.onCompleted: {
// FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
// for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
var scaleFactor = units.gridUnit / 8;
maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
flickDeceleration = flickDeceleration * scaleFactor;
}
}
首先,我们看出它还是一个ListView.在它的里面它使用了一个MultipleSelectionVisualModel.这个Component在我们的上面其实已经介绍过来.它作为一个VisualDataModel,有自己的Model及delegate,所以我们这里的ListView并不提供任何的Model及delegate.为了能够使得MultipleSelectionVisualModel中的数据能够在我们的MultipleSelectionListView外被引用,我们使用了如的alias来实现:
/*!
\qmlproperty model listModel
This property holds the model providing data for the list.
*/
property alias listModel: visualModel.model
/*!
\qmlproperty Component listDelegate
The delegate provides a template defining each item instantiated by the view.
*/
property alias listDelegate: visualModel.delegate
同样地,我们也可以在外面访问所有被选中的items:
/*!
\qmlproperty model selectedItems
This property holds the list of selected items
*/
readonly property alias selectedItems: visualModel.selectedItems
Main.qml
ListModel {
id: fruitModel
ListElement {
name: "apple"
cost: 2.45
}
ListElement {
name: "orange"
cost: 3.25
}
ListElement {
name: "banana"
cost: 1.95
}
ListElement {
name: "grape"
cost: 4.95
}
}
MutipleSelectionListView的使用方法如下:
MultipleSelectionListView {
id: view
clip: true
anchors.fill: parent
listModel: fruitModel
listDelegate: Rectangle {
id: delegate
width: view.width
height: units.gu(10)
Image {
id: fruit
height: units.gu(8)
width: height
source: "images/" + name + ".jpg"
}
Text {
anchors.left: fruit.right
anchors.leftMargin: units.gu(10)
anchors.verticalCenter: parent.verticalCenter
text: "$" + cost
}
Image {
anchors.right: parent.right
anchors.rightMargin: units.gu(1)
anchors.verticalCenter: parent.verticalCenter
height: units.gu(4)
width: height
source: "images/tick.png"
visible: view.isSelected(delegate)
}
MouseArea {
anchors.fill: parent
onClicked: {
if (view.isInSelectionMode) {
if ( view.isSelected(delegate))
view.deselectItem(delegate)
else
view.selectItem(delegate)
}
}
onPressAndHold: {
console.log("start to select....");
view.startSelection()
}
}
}
onSelectionDone: console.debug("Selected items:" + view.selectedItems)
}
在这里,我们给MutipleSelectionListView赋上model及delegate.这是一个非常简单的例子.
运行我们的应用:
当我们选上我们需要的项后,点击"
Get Selection"按钮,我们可以看到如下的输出:
qml: Selected items are:
qml: count: 3
qml: item: [object Object]
qml: item.model: [object Object]
qml: item.model.name: apple
qml: item.model.index: 0
qml: item: [object Object]
qml: item.model: [object Object]
qml: item.model.name: orange
qml: item.model.index: 1
qml: item: [object Object]
qml: item.model: [object Object]
qml: item.model.name: banana
qml: item.model.index: 2
整个项目的源码在: https://github.com/liu-xiao-guo/multipleselectionlistview