在 QML ListView 中将交替行颜色与平滑突出显示矩形相结合

问题描述 投票:0回答:1

我目前正在努力将两个看似简单的概念结合起来:交替行颜色和QML ListViews中的平滑移动突出显示项目

考虑这个简单的例子:


import sys

from PySide6.QtCore import QUrl
from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtWidgets import QApplication

if __name__ == '__main__':
    app = QApplication([])
    engine = QQmlApplicationEngine()

    engine.load(QUrl.fromLocalFile('main.qml'))

    if not engine.rootObjects():
        sys.exit(-1)

    app.exec()
import QtQuick
import QtQuick.Controls.Material
import QtQuick.Layouts


ApplicationWindow {
    id: root

    width: 400
    height: 500
    visible: true
    font.family: 'Noto Sans'

    ListView {
        id: listView

        width: root.width
        height: root.height

        clip: true
        focus: true
        reuseItems: true
        boundsBehavior: Flickable.StopAtBounds

        model: [
            "Wikipedia is a free online encyclopedia",
            "Wikipedia is a free online encyclopedia",
            "Wikipedia is a free online encyclopedia",
            "Wikipedia is a free online encyclopedia",
            "Wikipedia is a free online encyclopedia",
            "Wikipedia is a free online encyclopedia",
            "Wikipedia is a free online encyclopedia",
            "Wikipedia is a free online encyclopedia",
            "Wikipedia is a free online encyclopedia"
        ]

        delegate: Rectangle {
            height: 40
            width: parent.width
            color: ListView.isCurrentItem ? Material.accent : index % 2 === 0 ? palette.base : palette.alternateBase

            MouseArea {
                anchors.fill: parent

                onClicked: {
                    listView.currentIndex = index
                }
            }

            RowLayout {
                height: parent.height

                Label {
                    text: index
                    horizontalAlignment: Qt.AlignHCenter
                    verticalAlignment: Qt.AlignVCenter
                    Layout.preferredWidth: 100
                }

                Label {
                    text: modelData
                    Layout.preferredWidth: 300
                }
            }
        }

    }


}

这里,我们有一个 ListView 和一个具有交替行颜色的委托。我们可以通过单击或使用箭头键来突出显示该项目:

通过换出几行代码来实现平滑突出显示(无需交替行颜色)也非常简单:

// ...

highlight: Rectangle {
    height: 40
    width: parent.width
    color: Material.accent
}

delegate: Rectangle {
    height: 40
    width: parent.width
    color: 'transparent'

    // ...
}

// ...

单独来看,这两个概念都很容易应用,但当它们结合起来时,困难就变得真实了😅

尝试#1

// ...

highlight: Rectangle {
    height: 40
    width: parent.width
    color: Material.accent
}

delegate: Rectangle {
    height: 40
    width: parent.width
    color: ListView.isCurrentItem ? 'transparent' : index % 2 === 0 ? palette.base : palette.alternateBase

    // ...
}

// ...

结果

尝试#2

// ...

highlight: Rectangle {
    height: 40
    width: parent.width
    color: Material.accent
    z: 1
}

delegate: Rectangle {
    height: 40
    width: parent.width
    color: index % 2 === 0 ? palette.base : palette.alternateBase

    // ...
}

// ...

结果

我经常发现自己相信这项任务应该不会太难完成,但我无法摆脱我可能忽略某些事情的感觉。有其他人遇到类似问题并找到解决方案吗?

qt listview qml qtquick2 pyside6
1个回答
0
投票

有趣的问题!

困难是由于物品的z堆叠顺序造成的。 Z 顺序由子树解析,这意味着项目不能将自身堆叠在同级及其子级之间。它要么高于兄弟姐妹及其所有后代,要么低于所有后代。

为了实现您想要的效果,我们需要将背景与委托的内容分开,以便它们不再属于同一子树。 为此,您可以显式设置委托背景(及其几何形状)的父级。我还重构了委托以使用

ItemDelegate
使代码更清晰一点:

        highlight: Rectangle {
            height: 40
            width: parent.width
            color: Material.accent
        }

        delegate: ItemDelegate {
            id: delegate
            height: 40
            width: parent.width
            background: Rectangle {
                parent: delegate.parent
                y: delegate.y
                height: delegate.height
                color: index % 2 === 0 ? palette.base : palette.alternateBase
            }

            onClicked: listView.currentIndex = index

            contentItem: RowLayout {
                Label {
                    text: index
                    horizontalAlignment: Qt.AlignHCenter
                    verticalAlignment: Qt.AlignVCenter
                    Layout.preferredWidth: 100
                }
                Label {
                    text: "Wikipedia is a free online encyclopedia"
                    Layout.preferredWidth: 300
                }
            }
        }

可以通过将

z
设置为 0 表示背景、1 表示突出显示、2 表示代表代表来更明确,但这里似乎可以使用默认顺序。

这会导致:

使用 GammaRay 我们甚至可以看到项目层:

  • 当背景重新设置父级时(注意夹在背景和文本之间的突出显示):
  • 如果不是(请注意所有内容下方的突出显示):
© www.soinside.com 2019 - 2024. All rights reserved.