带鼠标区域或DropArea的ListView多选
ListView Multiple Selection With Mouse Area or DropArea
我想在 ListView 上进行多项选择。我可以使用 QT.modifier 的 control 或 shift 键来完成此操作。但是我想做的是我想通过用鼠标或触摸屏按住一个项目来启动选择。也就是说,当我按住一个项目时,ListView 将滚动并选择下一个项目。
import QtQuick 2.12
import QtQuick.Controls 2.12
ListView {
id: control
orientation: ListView.Horizontal
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 }
NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: 400 }
}
displaced: Transition {
NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }
}
focus: true
Keys.onSpacePressed: model.insert(0, { "name": "Waypoint " + model.count })
property int mulBegin: 0
signal checkOne(int idx)
signal checkMul(int idx)
Connections{
target: control
onCheckOne: control.mulBegin=idx;
}
clip: true
boundsBehavior: Flickable.StopAtBounds
spacing: 2
model: ListModel {}
delegate: Rectangle{
width: 100; height: 30
border.width: 1
radius:25
Text {
anchors.centerIn: parent
text: name
}
id: item_delegate
property bool checked: false
border.color: "gray"
color: item_delegate.checked? "green" : "red"
Connections{
target: control
onCheckOne: item_delegate.checked=(idx===index);
onCheckMul: {
if(idx>control.mulBegin){
item_delegate.checked=(index>=control.mulBegin&&index<=idx);
}else{
item_delegate.checked=(index<=control.mulBegin&&index>=idx);
}
}
}
MouseArea{
id: item_mousearea
anchors.fill: parent
onClicked: {
switch(mouse.modifiers){
case Qt.ControlModifier:
item_delegate.checked=!item_delegate.checked;
break;
case Qt.ShiftModifier:
control.checkMul(index);
break;
default:
control.checkOne(index);
control.mulBegin=index;
break;
}
}
}
}
ScrollBar.vertical: ScrollBar {
}
}
您可以使用 onPositionChanged
处理程序,但我认为还有许多其他可能性。
我按照你的代码写了一个小例子。关键是将鼠标位置映射到 ListView
.
中找到正确的元素
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 600
height: 600
Rectangle {
id: root
width: 400
height: 400
ListView {
id: control
width: parent.width / 2
height: parent.height
anchors.right: parent.right
property int mulBegin: 0
signal checkOne(int idx)
signal checkMul(int idx)
Connections{
target: control
function onCheckOne(idx)
{
control.mulBegin=idx;
}
}
clip: true
boundsBehavior: Flickable.StopAtBounds
ListModel {
id: myModel
ListElement { number: "1"; extraData: "extra-1-" }
ListElement { number: "2"; extraData: "extra{2}" }
ListElement { number: "3"; extraData: "extra_3_" }
ListElement { number: "4"; extraData: "extra*4*" }
ListElement { number: "5"; extraData: "extra$" }
}
model: myModel
delegate: Item {
id: item_delegate
width: control.width
height: 50
property bool checked: false
Rectangle {
id: rect
width: control.width
height: 50
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
border.color: "gray"
color: item_delegate.checked? "green" : "red"
Connections{
target: control
function onCheckOne(idx) { item_delegate.checked=(idx===index); }
function onCheckMul(idx) {
if(idx>control.mulBegin){
item_delegate.checked=(index>=control.mulBegin&&index<=idx);
}else{
item_delegate.checked=(index<=control.mulBegin&&index>=idx);
}
}
}
Text {
anchors.centerIn: parent
text: number + " / " + extraData
}
}
MouseArea {
id: item_mousearea
anchors.fill: parent
onClicked: {
switch(mouse.modifiers){
case Qt.ControlModifier:
item_delegate.checked=!item_delegate.checked;
break;
case Qt.ShiftModifier:
control.checkMul(index);
break;
default:
control.checkOne(index);
control.mulBegin=index;
break;
}
}
onPressAndHold: {
// It is possible to do the same using the onPress handler
// but then it collides with the current ControlModifier functionality.
// In fact, due to the default case in the onClicked handler, it is not
// strictly necessary to implement this slot.
console.log("onPressAndHold: " + index)
control.checkMul(index)
}
onPositionChanged: {
console.log("onPositionChanged: " + index)
// map the coordinate
var point = mapToItem(control, mouse.x, mouse.y)
console.log("mouse position (x, y): " + mouse.x, mouse.y
+ " mapToItem (x, y): "
+ point.x,
+ point.y)
var item = control.childAt(point.x, point.y)
if(item)
{
var indexAtPoint = control.indexAt(point.x, point.y)
var itemAtIndex = control.itemAtIndex(indexAtPoint)
console.log("item found at index: " + indexAtPoint
+ " data from item model: " + itemAtIndex.ListView.view.model.get(indexAtPoint).extraData)
control.checkMul(indexAtPoint)
}
}
onReleased: {
// another option is to put here the code from onPositionChanged
// but it is actually a different approach with a different behaviour
}
}
}
}
}
}
我想在 ListView 上进行多项选择。我可以使用 QT.modifier 的 control 或 shift 键来完成此操作。但是我想做的是我想通过用鼠标或触摸屏按住一个项目来启动选择。也就是说,当我按住一个项目时,ListView 将滚动并选择下一个项目。
import QtQuick 2.12
import QtQuick.Controls 2.12
ListView {
id: control
orientation: ListView.Horizontal
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 }
NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: 400 }
}
displaced: Transition {
NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }
}
focus: true
Keys.onSpacePressed: model.insert(0, { "name": "Waypoint " + model.count })
property int mulBegin: 0
signal checkOne(int idx)
signal checkMul(int idx)
Connections{
target: control
onCheckOne: control.mulBegin=idx;
}
clip: true
boundsBehavior: Flickable.StopAtBounds
spacing: 2
model: ListModel {}
delegate: Rectangle{
width: 100; height: 30
border.width: 1
radius:25
Text {
anchors.centerIn: parent
text: name
}
id: item_delegate
property bool checked: false
border.color: "gray"
color: item_delegate.checked? "green" : "red"
Connections{
target: control
onCheckOne: item_delegate.checked=(idx===index);
onCheckMul: {
if(idx>control.mulBegin){
item_delegate.checked=(index>=control.mulBegin&&index<=idx);
}else{
item_delegate.checked=(index<=control.mulBegin&&index>=idx);
}
}
}
MouseArea{
id: item_mousearea
anchors.fill: parent
onClicked: {
switch(mouse.modifiers){
case Qt.ControlModifier:
item_delegate.checked=!item_delegate.checked;
break;
case Qt.ShiftModifier:
control.checkMul(index);
break;
default:
control.checkOne(index);
control.mulBegin=index;
break;
}
}
}
}
ScrollBar.vertical: ScrollBar {
}
}
您可以使用 onPositionChanged
处理程序,但我认为还有许多其他可能性。
我按照你的代码写了一个小例子。关键是将鼠标位置映射到 ListView
.
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 600
height: 600
Rectangle {
id: root
width: 400
height: 400
ListView {
id: control
width: parent.width / 2
height: parent.height
anchors.right: parent.right
property int mulBegin: 0
signal checkOne(int idx)
signal checkMul(int idx)
Connections{
target: control
function onCheckOne(idx)
{
control.mulBegin=idx;
}
}
clip: true
boundsBehavior: Flickable.StopAtBounds
ListModel {
id: myModel
ListElement { number: "1"; extraData: "extra-1-" }
ListElement { number: "2"; extraData: "extra{2}" }
ListElement { number: "3"; extraData: "extra_3_" }
ListElement { number: "4"; extraData: "extra*4*" }
ListElement { number: "5"; extraData: "extra$" }
}
model: myModel
delegate: Item {
id: item_delegate
width: control.width
height: 50
property bool checked: false
Rectangle {
id: rect
width: control.width
height: 50
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
border.color: "gray"
color: item_delegate.checked? "green" : "red"
Connections{
target: control
function onCheckOne(idx) { item_delegate.checked=(idx===index); }
function onCheckMul(idx) {
if(idx>control.mulBegin){
item_delegate.checked=(index>=control.mulBegin&&index<=idx);
}else{
item_delegate.checked=(index<=control.mulBegin&&index>=idx);
}
}
}
Text {
anchors.centerIn: parent
text: number + " / " + extraData
}
}
MouseArea {
id: item_mousearea
anchors.fill: parent
onClicked: {
switch(mouse.modifiers){
case Qt.ControlModifier:
item_delegate.checked=!item_delegate.checked;
break;
case Qt.ShiftModifier:
control.checkMul(index);
break;
default:
control.checkOne(index);
control.mulBegin=index;
break;
}
}
onPressAndHold: {
// It is possible to do the same using the onPress handler
// but then it collides with the current ControlModifier functionality.
// In fact, due to the default case in the onClicked handler, it is not
// strictly necessary to implement this slot.
console.log("onPressAndHold: " + index)
control.checkMul(index)
}
onPositionChanged: {
console.log("onPositionChanged: " + index)
// map the coordinate
var point = mapToItem(control, mouse.x, mouse.y)
console.log("mouse position (x, y): " + mouse.x, mouse.y
+ " mapToItem (x, y): "
+ point.x,
+ point.y)
var item = control.childAt(point.x, point.y)
if(item)
{
var indexAtPoint = control.indexAt(point.x, point.y)
var itemAtIndex = control.itemAtIndex(indexAtPoint)
console.log("item found at index: " + indexAtPoint
+ " data from item model: " + itemAtIndex.ListView.view.model.get(indexAtPoint).extraData)
control.checkMul(indexAtPoint)
}
}
onReleased: {
// another option is to put here the code from onPositionChanged
// but it is actually a different approach with a different behaviour
}
}
}
}
}
}