从ListView中选择多个项目

时间:2016-07-18 13:39:06

标签: qt qml

我想从ListView中选择多个项目。在C++我会做这样的事情

if (clicked_card->is_selected) {
    clicked_card->is_selected = false;
    int i = 0;
    while(selected_cards[i] != clicked_card) i++;
    selected_cards.erase(selected_cards.begin() + i);
} else {
    clicked_card->is_selected = true;
    selected_cards.push_back(clicked_card);
}

上面的代码使用指针进行比较。那么如何在QML中进行这样的选择。我提出的解决方案是这样的

Card.qml

Image {
    id: delegate
    property bool isSelected: false
    ...
    MouseArea {
        onClicked: {
            if(isSelected === true) {
                isSelected = false;
                gameScene.deselectCard(selectSeq);
            }
            else {
                isSelected = true;
                gameScene.selectCard({'opParam': opParam, 'selectSeq': selectSeq});
            }
        }
    }
}

GameScene.qml

Item {
    id: gameScene
    property var selectedCards: []

    signal selectCard(variant userData)
    onSelectCard: {
        gameScene.selectedCards.push(userData)
    }

    signal deselectCard(variant userData)
    onDeselectCard: {
        for (var i = 0; i < gameScene.selectedCards.length; i += 1) {
            if (gameScene.selectedCards[i].selectSeq == userData) {
                gameScene.selectedCards.splice(i, 1);
                break;
            }
        }
    }
}

上面代码的问题在于我将属性isSelected存储在由系统创建和销毁的委托中。所以这给了我错误的解决方案。有没有更好的多重选择方法或解决方案的任何改进?我通过继承model来使用C ++中的QAbstractListModel

2 个答案:

答案 0 :(得分:3)

我在Qt文档中找到了答案。我只需要使用[DelegateModel][1]。它具有group属性,对于DelegateModel中定义的每个组,将向每个委托项添加两个附加属性。表单DelegateModel.in*GroupName*中的第一个表示项目是否属于该组,第二个DelegateModel.*groupName*Index包含该组中项目的索引。

  import QtQuick 2.0
  import QtQml.Models 2.2

  Rectangle {
      width: 200; height: 100

      DelegateModel {
          id: visualModel
          model: ListModel {
              ListElement { name: "Apple" }
              ListElement { name: "Orange" }
          }

          groups: [
              DelegateModelGroup { name: "selected" }
          ]

          delegate: Rectangle {
              id: item
              height: 25
              width: 200
              Text {
                  text: {
                      var text = "Name: " + name
                      if (item.DelegateModel.inSelected)
                          text += " (" + item.DelegateModel.selectedIndex + ")"
                      return text;
                  }
              }
              MouseArea {
                  anchors.fill: parent
                  onClicked: item.DelegateModel.inSelected = !item.DelegateModel.inSelected
              }
          }
      }

      ListView {
          anchors.fill: parent
          model: visualModel
      }
  }

其他解决方案是将属性isSelected移动到C ++数据模型,并使用getter和setter函数更新更改。

答案 1 :(得分:0)

一个简单的解决方案。使用QPair或QPair存储所有项目的状态。

typedef QPair<int, bool> ItemState;

在列表中启用多项选择:

ui->tableView->setSelectionMode(QAbstractItemView::MultiSelection);

当你想选择一个集合时,试试这样的事情:

QList<ItemState> collection;
foreach (ItemState& el , collection) {
    const int row = el.first;
    const bool state = el.second;
    const QModelIndex& index = ui->tableView->model()->index(row, 0);
    ui->tableView->selectionModel()->select(index, state ? QItemSelectionModel::Select : QItemSelectionModel::Deselect );
} 

每次修改模型中的数据时,都应该更新收集数据(添加,移除移动元素)。当用户点击卡片时,只需处理单击的事件并修改收集项目状态,然后调用循环。