4. 使用ListView展示数据列表

任务目标

使用 Qt Quick 的 ListView 配合内置 ListModel 展示一组设备信息,实现列表滚动浏览、点击高亮选中项,并在右侧区域显示当前选中设备的详细信息。

环境依赖

Qt 5.15+(或 Qt 6.x),模块:QtQuick、QtQuick.Controls。使用 qmlscene 或 qml 运行器直接加载 QML 文件即可,无需 C++ 工程。

关键完整代码

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

Rectangle {
    width: 640
    height: 480
    color: "#f5f6fa"

    // 设备数据模型
    ListModel {
        id: deviceModel
        ListElement { name: "温度传感器"; type: "温湿度"; location: "A区-1号机房"; status: "在线"; value: "23.5°C" }
        ListElement { name: "压力变送器"; type: "压力"; location: "B区-2号产线"; status: "告警"; value: "1.2MPa" }
        ListElement { name: "流量计"; type: "流量"; location: "C区-3号管道"; status: "在线"; value: "3.8m³/h" }
        ListElement { name: "振动分析仪"; type: "振动"; location: "D区-4号机组"; status: "离线"; value: "--" }
        ListElement { name: "液位开关"; type: "液位"; location: "E区-5号储罐"; status: "在线"; value: "78%" }
        ListElement { name: "电流互感器"; type: "电量"; location: "F区-6号配电柜"; status: "在线"; value: "12.5A" }
        ListElement { name: "气动调节阀"; type: "执行器"; location: "G区-7号反应釜"; status: "告警"; value: "开度45%" }
    }

    RowLayout {
        anchors.fill: parent
        anchors.margins: 12
        spacing: 12

        // 左侧:设备列表
        Rectangle {
            Layout.preferredWidth: 280
            Layout.fillHeight: true
            color: "white"
            radius: 6
            border.color: "#dcdde1"

            ListView {
                id: deviceList
                anchors.fill: parent
                anchors.margins: 4
                model: deviceModel
                clip: true
                focus: true
                spacing: 2

                // 当前选中项索引(初始选中第一项)
                property int currentIndex: 0

                delegate: Rectangle {
                    id: itemRect
                    width: ListView.view.width
                    height: 56
                    radius: 4
                    color: ListView.isCurrentItem ? "#3498db" : "transparent"

                    required property string name
                    required property string type
                    required property string status

                    Column {
                        anchors.left: parent.left
                        anchors.leftMargin: 12
                        anchors.verticalCenter: parent.verticalCenter
                        spacing: 4

                        Text {
                            text: name
                            font.pixelSize: 15
                            font.bold: true
                            color: ListView.isCurrentItem ? "white" : "#2c3e50"
                        }
                        Text {
                            text: type + " · " + status
                            font.pixelSize: 12
                            color: ListView.isCurrentItem ? "#ecf0f1" : "#7f8c8d"
                        }
                    }

                    MouseArea {
                        anchors.fill: parent
                        onClicked: {
                            deviceList.currentIndex = index
                            deviceList.forceActiveFocus()
                        }
                    }
                }

                // 键盘上下键切换选中
                Keys.onUpPressed: if (currentIndex > 0) currentIndex--
                Keys.onDownPressed: if (currentIndex < count - 1) currentIndex++

                highlightFollowsCurrentItem: true
            }
        }

        // 右侧:选中设备详情
        Rectangle {
            Layout.fillWidth: true
            Layout.fillHeight: true
            color: "white"
            radius: 6
            border.color: "#dcdde1"

            Column {
                anchors.centerIn: parent
                spacing: 10
                width: parent.width - 40

                Text {
                    text: "设备详情"
                    font.pixelSize: 18
                    font.bold: true
                    color: "#2c3e50"
                }

                Rectangle {
                    width: parent.width
                    height: 1
                    color: "#ecf0f1"
                }

                Text {
                    text: "名称:" + deviceModel.get(deviceList.currentIndex).name
                    font.pixelSize: 14
                    color: "#34495e"
                }
                Text {
                    text: "类型:" + deviceModel.get(deviceList.currentIndex).type
                    font.pixelSize: 14
                    color: "#34495e"
                }
                Text {
                    text: "位置:" + deviceModel.get(deviceList.currentIndex).location
                    font.pixelSize: 14
                    color: "#34495e"
                }
                Text {
                    text: "状态:" + deviceModel.get(deviceList.currentIndex).status
                    font.pixelSize: 14
                    color: deviceModel.get(deviceList.currentIndex).status === "在线" ? "#27ae60" :
                           (deviceModel.get(deviceList.currentIndex).status === "告警" ? "#e67e22" : "#95a5a6")
                }
                Text {
                    text: "当前值:" + deviceModel.get(deviceList.currentIndex).value
                    font.pixelSize: 14
                    color: "#34495e"
                }
            }
        }
    }
}

运行方式

  1. 将上述代码保存为 DeviceList.qml。
  2. 在终端执行:qmlscene DeviceList.qml(Qt 5)或 qml DeviceList.qml(Qt 6)。

验证方法

  • 列表展示:窗口左侧应显示 7 行设备条目,每行包含设备名称、类型与状态。
  • 滚动:当窗口高度不足以显示全部条目时,可用鼠标滚轮在列表区域滚动浏览。
  • 点击高亮:点击任意条目,该行背景变为蓝色,文字变为白色,表示选中。
  • 键盘操作:点击列表后按键盘 ↑/↓ 键,选中项随之移动并保持高亮。
  • 详情联动:右侧“设备详情”区域实时显示当前选中设备的名称、类型、位置、状态和当前值。初始状态默认选中第一项(温度传感器),右侧应显示对应信息。

关键实现说明

  • ListView 的 currentIndex 属性控制当前选中项,highlightFollowsCurrentItem 确保高亮跟随选中项移动。
  • 委托(delegate)中通过 ListView.isCurrentItem 判断当前项是否为选中项,从而切换背景色与文字颜色。
  • 右侧详情通过 deviceModel.get(deviceList.currentIndex) 动态读取当前选中项数据,实现双向联动。
  • 点击条目时手动设置 currentIndex 并调用 forceActiveFocus(),保证键盘事件能正确作用于列表。