带有多选功能的GridView

问题描述

我需要一个具有多选功能GridView。我找不到任何现有的解决方案,所以我决定扩展GridView功能

我写了一个处理多重选择的快速草案:

import QtQuick 2.15
import cpp_objects.qml 1.0


GridView {
    id: grid

    function isSelected(index) {
        return selectionManager.isIndexSelected(index)
    }

    SelectionManager {
        id: selectionManager
    }

    MouseArea {
        anchors.fill: parent

        acceptedButtons: Qt.LeftButton
        propagateComposedEvents: true

        onClicked: {
            var ctrl = mouse.modifiers & Qt.ControlModifier;

            if (ctrl == false)
                selectionManager.clearSelection()

            var index = grid.indexAt(mouse.x,mouse.y)
            selectionManager.toggleIndexSelection(index)

            mouse.accepted = false
        }
    }
}

SelectionManager在cpp端实现,并收集所选项目。

这是它的界面:

class SelectionManagerComponent: public QObject
{
        Q_OBJECT

    public:
        SelectionManagerComponent(QObject * = nullptr);

        Q_INVOKABLE void toggleIndexSelection(int);
        Q_INVOKABLE void clearSelection();
        Q_INVOKABLE bool isIndexSelected(int) const;

    private:
        std::unordered_set<int> m_selected;
};

现在我面临最棘手的问题:如何可视化我的额外选择? 我希望这个qml组件尽可能通用,所以我不想在这里不提供硬编码的委托。完美的解决方案是添加某种类型的'selectionDelegate'属性,该属性将使用Item,并且与delegatehighlight的工作方式相同,因此我可以从自定义{{ 1}},并定义如何标记所选项目。但这似乎不可行。

还有其他可能性或选择吗?

解决方法

我可以想到两种方法。

  1. 使用Loader作为您的代表。根据是否选择了项目,更改sourceComponent
GridView {

    // Define these to specify your selected/unselected delegates
    property Component selectedComponent
    property Component unselectedComponent

    delegate: Loader {
        sourceComponent: selectionManager.isIndexSelected(index)
                             ? selectedComponent 
                             : unselectedComponent
    }
}
  1. 或者您可以使用DelegateChooser。它允许您根据模型中字段之一的值使用不同的委托。我本来会选择它为第一选择,但是我不知道它是否可以与您的selectionManager一起使用,因为它与模型数据无关。但是也许仍然有一种方法可以使它工作。
GridView {

    // Define these to specify your selected/unselected delegates
    property Component selectedComponent
    property Component unselectedComponent

    delegate: DelegateChooser {
        role: "selected"  // <-- This needs to be a role in your model
        DelegateChoice { roleValue: true; selectedComponent }
        DelegateChoice { roleValue: false; unselectedComponent }
    }
}