ListView

Последнее обновление: 23.12.2023

Элемент ListView представляет один из наиболее часто используемых компонентов приложения и типов представлений, который позволяет создать список. Элементы в ListView могут располагаться горизонтально или вертикально. ListView наследуется от типа Flickable, который определяет базовый функционал для работы с элементами списков.

Рассмотрим простейший список ListView:

import QtQuick

Window {
    width: 250
    height: 200
    visible: true
    title: "METANIT.COM"
    ListView {
        width: parent.width
        height: 150

        model: ListModel {
            ListElement {
                name: "Tom"
                age: 39
            }
            ListElement {
                name: "Bob"
                age: 43
            }
            ListElement {
                name: "Sam"
                age: 28
            }
        }
        delegate: Text {
            text: name + " (" + age + ")"
        }
    }
}
Простейший список ListView в QML и Qt

Рассмотрим список по частям. Прежде всего, так как ListView наследуется от Flickable, а последний - от типа Item, то мы можем установить для ListView ширину и высоту.

Для определения используемых данных тип ListView определяет свойство model:

model: ListModel {
    ListElement {
        name: "Tom"
        age: 39
    }
    ListElement {
        name: "Bob"
        age: 43
    }
    ListElement {
        name: "Sam"
        age: 28
    }
}

Модель определяется типом ListModel из пакета "QtQml.Models". Это не единственный тип модели, который мы можем использовать. При необходимости мы можем создавать свои типы моделей. ListModel — это простой контейнер элементов ListElement, каждое из которых содержит роли данных. Содержимое ListModel может быть определено динамически или явно в QML.

Тип ListElement представляет отдельный элемент списка в ListModel. ListItem определяется, как и другие элементы в QML, только вместо свойств содержит роли (согласно терминологии официальной документации). Например, в примере выше для каждого ListElement определяются две роли - "name" и "age". Имена ролей должны начинаться со строчной буквы и быть общими для всех элементов в данной модели. Значения должны быть простыми константами: строки, логические значения (true, false), числа или значения перечисления (например, AlignText.AlignHCenter). Таким образом, в примере выше определяются три элемента, каждый из которых представляет данные человека. Каждый элемент имеет две роли: name и age для хранения имени и возраста человека соответственно.

Другой компонент ListView - делегат определяет, как эти данные будут отображаться в списке, и устанавливается с помощью свойства delegate:

delegate: Text {
    text: name + " (" + age + ")"
}

В примере выше делегат представляет элемент Text, у которого устанавливается свойство text. Внутри делегата мы можем обратиться к ролям текущего элемента модели по их имени - name и age.

Таким образом, для каждого объекта модели будет создан элемент Text, который отобразит данные модели.

Вместо простого элемента Text можно было бы использовать более сложные композиции элементов. Например:

import QtQuick

Window {
    width: 250
    height: 200
    visible: true
    title: "METANIT.COM"
    ListView {
        anchors.fill: parent

        model: ListModel {
            ListElement {
                name: "Tom"
                age: 39
            }
            ListElement {
                name: "Bob"
                age: 43
            }
            ListElement {
                name: "Sam"
                age: 28
            }
        }
        delegate: Column {
            Text { text: "<b>Name:</b> " + name }
            Text { text: "<b>Age:</b> " + age }
        }
    }
}
Модель и делегат ListView в QML и Qt

Ориентация списка

ListView может располагать свои элементы вертикально и горизонтально. Для этого управления ориентацией применяется свойство orientation, которое может принимать следующие значения:

  • Qt.Horizontal: расположение по горизонтали

  • Qt.Vertical: расположение по вертикали (значение по умолчанию)

По умолчанию список располагается по вертикали, поэтому теперь расположим по горизонтали:

import QtQuick

Window {
    width: 250
    height: 200
    visible: true
    title: "METANIT.COM"
    ListView {
        anchors.fill: parent
        orientation: Qt.Horizontal
        spacing: 8
        model: ListModel {
            ListElement {
                name: "Tom"
                age: 39
            }
            ListElement {
                name: "Bob"
                age: 43
            }
            ListElement {
                name: "Sam"
                age: 28
            }
        }
        delegate: Column {
            Text { text: "<b>Name:</b> " + name }
            Text { text: "<b>Age:</b> " + age }
        }
    }
}
горизонтальное расположение элементов списка ListView в QML и Qt

Для управления направлением элементов ListView предоставляет еще пару свойств:

  • layoutDirection: управляет направлением по горизонтальни и может принимать значения Qt.LeftToRight (расположение слева направо), либо Qt.RightToLeft (расположение справа налево).

  • verticalLayoutDirection: управляет направлением по горизонтальни и может принимать значения ListView.TopToBottom (элементы располагаются сверху вниз), либо ListView.BottomToTop (элементы располагаются снизу вверх).

Выделение элемента в списке

За выделение элемента в списке ListView отвечает свойство highlight. Этому свойству можно назначить элемент, применяемый для выделения элемента списка. Например:

import QtQuick

Window {
    width: 250
    height: 200
    visible: true
    title: "METANIT.COM"
    ListView {
        id: list
        anchors.fill: parent
        highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
        focus: true     // добавляем поддержку перемещения клавиатуров

        model: ListModel {
            ListElement {
                name: "Tom"
                age: 39
            }
            ListElement {
                name: "Bob"
                age: 43
            }
            ListElement {
                name: "Sam"
                age: 28
            }
        }
        delegate: Column {
            padding: 5
            width: list.width   // растягиваем элемент по всей ширине контейнера
            Text { text: "<b>Name:</b> " + name }
            Text { text: "<b>Age:</b> " + age }
        }
    }
}

Здесь в качестве элемента выделения применяется тип Rectangle, у которого устанавливается цвет - цвет выделения и радиус.

highlight: Rectangle { color: "lightsteelblue"; radius: 5 }

Для поддержки перемещения по списку клавиатурой свойству focus присваивается значение true:

focus: true

При запуске приложения уже будет выделяться первый элемент:

Выделение элемента в списке ListView в QML и Qt

Но тут мы можем столкнуться с проблемой - по умолчанию выделение мышью не доступно, и нам надо определить данный функционал самостоятельно. Для этого изменим код следующим образом:

import QtQuick

Window {
    width: 250
    height: 200
    visible: true
    title: "METANIT.COM"
    ListView {
        id: list
        anchors.fill: parent
        highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
        focus: true

        model: ListModel {
            ListElement {
                name: "Tom"
                age: 39
            }
            ListElement {
                name: "Bob"
                age: 43
            }
            ListElement {
                name: "Sam"
                age: 28
            }
        }
        delegate: Item{
            width: list.width
            height:45
            Column {
                padding: 5
                Text { text: "<b>Name:</b> " + name }
                Text { text: "<b>Age:</b> " + age }
            }
            MouseArea {
                anchors.fill: parent
                onClicked: list.currentIndex = index
            }
        }
    }
}

В данном случае определение отдельного объекта списка вынесено в элемент Item, у которого установлены ширина и высота. И в этом элементе определен элемент MouseArea, который занимает всю область контейнера.

MouseArea {
    anchors.fill: parent
    onClicked: list.currentIndex = index
}

MouseArea - это область нажатия мышью, при нажатии которой срабатывает обработчик onClicked. В этом обработчике мы устанавливаем индекс текущего элемента списка ListVie, передавая ему индекс нажатого элемента.

Заголовок и футер

С помощью свойств header и footer можно задать соответственно заголовок и низ элемента ListView:

import QtQuick

Window {
    width: 250
    height: 200
    visible: true
    title: "METANIT.COM"
    ListView {
        anchors.fill: parent
        id: list
        spacing: 8
        header: Text {
            text: "Список пользователей"
            font.pixelSize: 15
        }
        footer: Text {
            text: "Количество пользователей на 2023 год: " + list.count
            font.pixelSize: 11
            font.italic: true
        }
        model: ListModel {
            ListElement {
                name: "Tom"
                age: 39
            }
            ListElement {
                name: "Bob"
                age: 43
            }
            ListElement {
                name: "Sam"
                age: 28
            }
        }
        delegate: Column {
            Text { text: "<b>Name:</b> " + name }
            Text { text: "<b>Age:</b> " + age }
        }
    }
}

В данном случае заголовок и футер представляют элементы Text. В футере выводится количество элементов, для этого идет обращение к свойство count текущего списка.

Заголовок и футер в списке ListView в QML и Qt

Повторное использование элементов

В общем случае в ListView делегат вызывается для каждого элемента ListItem и создает свой элемент, который отображается в ListView. Однако если элементов много, это может несколько ухужшить производительность приложения при работе со списком. Но ListViw (начиная с версии Qt 5.15) позволяет повторное использовать ранее использованные элементы, когда они исчезают из поля зрения при прокрутке. Этот подход повышает производительность в зависимости от сложности делегата. По умолчанию повторное использование элементов отключено (по соображениям обратной совместимости), но его можно включить, установив для свойства reuseItems значение true.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850