具有多选功能的 GridView

GridView with multiselect

我需要 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 相同,所以我可以继承自我的自定义 GridView 并定义如何标记所选项目。但这似乎不可行。

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

我可以想到两种方法。

  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 }
    }
}