Модель TableView предназначена для определения данных в виде таблицы. Она определена в пакете Qt.labs.qmlmodels. Она имеет относительно небольшой функционал. Она имеет три свойства:
columnCount: возвращает количество столбцов
rowCount: возвращает количество строк
rows: хранит все строки таблицы
Для манипуляции с данными TableModel предоставляет ряд методов:
appendRow(object row): добавляет строку
clear(): удаляет все строки
variant data(QModelIndex index, string role): возвращает данные по определенному индексу с учетом роли
object getRow(int rowIndex): возвращает строку по индексу
QModelIndex index(int row, int column): возвращает индекс для определенной ячейки таблицы
insertRow(int rowIndex, object row): вставляет строку по определенному индексу
moveRow(int fromRowIndex, int toRowIndex, int rows): передвигает строку на новую позицию
removeRow(int rowIndex, int rows): удаляет строку/строки
bool setData(QModelIndex index, string role, variant value): устанавливает данные
setRow(int rowIndex, object row): устанавливает строку
Определение простейшей модели TableModel
TableModel{
TableModelColumn { display: "name" }
TableModelColumn { display: "age" }
rows:[
{name: "Tom", age: 39},
{name: "Bob", age: 43},
{name: "Sam", age: 28}
]
}
Все строки таблицы помещаются в массив rows. В данном случае в этом массиве три строки-объекта, каждый из которых имеет два свойства - name и age. В
модели также надо установить определения столбцов с помощью типа TableModelColumn. Для каждого столбца устанавливается свойство display, которое указывает,
какое именно свойство объектов-строк будет отображаться.
Стоит отметить, что количество столбцов - объектов TableModelColumn необязательно должно соответствовать количеству свойств в объектах-строках. Мы можем определить меньшее количество стобцов, если мы не хотим выводить в таблицу все свойства.
Для отображения табличных данных в Qt Quick есть представление TableView. Например, определим простейшую таблицу:
import QtQuick
import Qt.labs.qmlmodels
Window {
width: 250
height: 150
visible: true
title: "METANIT.COM"
TableModel{
id: userTable
TableModelColumn { display: "name" }
TableModelColumn { display: "age" }
rows:[
{name: "Tom", age: 39},
{name: "Bob", age: 43},
{name: "Sam", age: 28}
]
}
TableView {
model: userTable
anchors.fill: parent
delegate: Text { text: model.display}
}
}
Здесь свойству model у TableView передается выше определенная модель TableModel. Для получения содержимого столбца внутри делегата можно использовать свойство
model.display:
delegate: Text { text: model.display}
То есть поскольку у нас три строки с двумя свойствами, то делегат будет создавать 6 элементов Text.
Тип TableView предоставляет ряд свойств для управления внешним видом таблицы. Отмечу основные:
columnSpacing: устанавливает расстояние между столбцами. По умолчанию равно 0
rowSpacing: устанавливает расстояние между строками. По умолчанию равно 0
resizableColumns: при значении true позволяет пользователю растягивать ширину столбцов. По умолчанию равно false. Добавлено с версии Qt 6.5
resizableRows: при значении true позволяет пользователю растягивать высоту строк. По умолчанию равно false. Добавлено с версии Qt 6.5
По умолчанию TableView не включает заголовки. Тем не мнее можно вручную добавить элементы HorizontalHeaderView и VerticalHeaderView для создания заголовков для стобцов и строк соответственно. Например, определим заголовки:
import QtQuick
import QtQuick.Controls
import Qt.labs.qmlmodels
Window {
width: 250
height: 150
visible: true
title: "METANIT.COM"
TableModel{
id: userTable
TableModelColumn {
display: "name"
}
TableModelColumn { display: "age" }
rows:[
{name: "Tom", age: 39},
{name: "Bob", age: 43},
{name: "Sam", age: 28}
]
}
HorizontalHeaderView {
id: horizontalHeader
anchors.left: tableView.left
anchors.top: parent.top
syncView: tableView
}
VerticalHeaderView {
id: verticalHeader
anchors.top: tableView.top
anchors.left: parent.left
syncView: tableView
}
TableView {
id: tableView
anchors.left: verticalHeader.right
anchors.top: horizontalHeader.bottom
anchors.right: parent.right
anchors.bottom: parent.bottom
model: userTable
rowSpacing: 9
columnSpacing: 9
delegate: Text { text: model.display}
}
}
Для обоих заголовков здесь определена синхронизация с TableView:
syncView: tableView
Больше для связи заголовков с TableView ничего не требуется. В итоге мы получим следующий интерфейс:
Но, как видно из скриншота, в качестве текста по умолчанию заголовки получают индекс столбцов/строк. Настроим заголовки - уберем заголовки строк, а и исправим текст заголовков столбцов:
import QtQuick
import QtQuick.Controls
import Qt.labs.qmlmodels
Window {
width: 250
height: 150
visible: true
title: "METANIT.COM"
TableModel{
id: userTable
TableModelColumn {
display: "name"
}
TableModelColumn { display: "age" }
rows:[
{name: "Tom", age: 39},
{name: "Bob", age: 43},
{name: "Sam", age: 28}
]
}
HorizontalHeaderView {
id: horizontalHeader
anchors.left: tableView.left
anchors.top: parent.top
syncView: tableView
model: ["Имя", "Возраст"]
delegate: Text {
text: modelData
font.bold: true
}
}
TableView {
id: tableView
anchors.left: parent.left
anchors.leftMargin: 5
anchors.top: horizontalHeader.bottom
anchors.right: parent.right
anchors.bottom: parent.bottom
model: userTable
rowSpacing: 9
columnSpacing: 9
delegate: Text { text: model.display}
}
}
HorizontalHeaderView/VerticalHeaderView представляют типы представлений, у которых можно задать данные с помощью свойства model и настроить отображение данных с помощью делегата. В данном случае HorizontalHeaderView в качестве модели получает массив текстов заголовков для обоих столбцов:
Когда новый столбец отображается в TableView, с помощью вызвова метода columnsWidthProvider у него определяется ширина. Если эта функция установлена, то она устанавливает ширину столбца. Если эта функция не установлена, то проверяется установка ширины с помощью метода setColumnWidth(). Если этот метод не был вызван, то для установки ширины применяется метод implicitColumnWidth(). Этот метод устанавливает в качестве ширины столбца неявную ширину, которая равна наибольшей неявной ширине элементов для данного столбце.
Та же логика применяется для установки высоты строк с помощью методов rowsHeightProvider, setRowHeight() и implicitRowHeight().
Пример установки ширины столбца:
TableView {
id: tableView
model: userTable
delegate: Text { text: model.display}
property var columnWidths: [80, 50] // два столбца шириной по 80 и 50
columnWidthProvider: function(column) {
// получаем неявную длину
const implicitWidth = implicitColumnWidth(column)
// если неявная ширина больше, чем та, которую мы хотим установить
if (implicitWidth > columnWidths[column]) return implicitWidth;
return columnWidths[column]
}
}
Возьмем ситуацию, когда мы хотим, чтобы столбцы имели как минимм некоторую ширину. Однако содержимое столбца превышает эту ширину, то столбец должен принимать
ширину этого содержимого. И здесь на уровне элемента TableView определяется свойство columnWidths, которое в виде массива хранит два значения - ширину двух столбцов. Это минимальная
ширина.
Свойству columnWidthProvider передается функция, которая в качестве параметра принимает индекс столбца, для которого устанавливается ширина. И данная функция должна возвратить
ширину столбца. Сначала с помощью функции implicitColumnWidth(column) получаем неявную ширину столбца, которая вычисляет на основе содержимого (implicitColumnWidth() - встроенная функция). Если
эта неявная ширина больше минимальной ширины для текущего столбца, то возвращаем неявную ширину. Иначе возвращаем минимальную ширину.
Можно таким образом также установить константные значения:
columnWidthProvider: function(column) { return 80;} // с помощью обычной функции
rowHeightProvider: () => 25 // с помощью стрелочной функции
TableView позволяет добавить поддержку выделения строки. Для настройки выделения в таблице применяются три свойства:
selectionModel: модель выделения, принимает объект ItemSelectionModel
selectBehavior: что именно выделяет пользователь. Может принимать следующие значения:
TableView.SelectionDisabled: выделение отключено
TableView.SelectCells: можно выделять отдельные ячейки (значение по умолчанию)
TableView.SelectRows: можно выделять отдельные строки
TableView.SelectColumns: можно выделять отдельные столбцы
selectionMode: режим выделения, который указывает как и сколько объектов может выделять пользователь. Может принимать следующие значения:
TableView.SingleSelection: пользователь может выбрать одну ячейку, строку или столбец.
TableView.ContigiousSelection: пользователь может выбрать один непрерывный блок ячеек. Существующее выделение можно увеличить или уменьшить,
удерживая клавишу Shift во время выделения.
TableView.ExtendedSelection: пользователь может выбрать несколько отдельных блоков ячеек (значение по умолчанию). Существующее выделение можно увеличить
или уменьшить, удерживая клавишу Shift во время выделения. Новый блок выбора можно запустить, не очищая текущий выбор, удерживая клавишу Control во время выбора.
Чтобы узнать, делегат применяется к текущей или выделенной ячейке, в делегат добавляются два свойства - selected (выделена ли ячейка) и current (является ли ячейка текущей):
delegate: Item {
required property bool selected
required property bool current
// ...
}
Оба свойства должны быть определены как required
Для рендеринга элемента также можно использовать свойства currentRow и currentColumn, который представляют соответственно текущую строку и текущий столбец.
Например, выделим текущую строку при нажатии на нее:
import QtQuick
import QtQuick.Controls
import Qt.labs.qmlmodels
Window {
width: 250
height: 150
visible: true
title: "METANIT.COM"
TableModel{
id: userTable
TableModelColumn { display: "name"}
TableModelColumn { display: "age" }
rows:[
{name: "Tom", age: 39},
{name: "Bob", age: 43},
{name: "Sam", age: 28}
]
}
TableView {
id: tableView
anchors.fill: parent
model: userTable
selectionModel: ItemSelectionModel {}
delegate: Rectangle {
implicitHeight: 25
implicitWidth: 80
color: row==tableView.currentRow ? "lightgray": "white"
Text { text: display }
}
}
}
Здесь при установке свойства color проверяем на соответствие строки ячейки и текущей строки TableView. Строку, для которой создается ячейка, в делегате можно получить через
свойство row
color: row==tableView.currentRow ? "lightgray": "white"
Если надо выделить только одну ячейку, можно проверять свойство "current", которое устанавливается автоматически:
TableView {
id: tableView
anchors.fill: parent
model: userTable
selectionModel: ItemSelectionModel {}
delegate: Rectangle {
implicitHeight: 25
implicitWidth: 80
required property bool current
color: current ? "lightgray": "white"
Text { text: display }
}
}
Другой пример - выделим нескольких строк:
import QtQuick
import QtQuick.Controls
import Qt.labs.qmlmodels
Window {
width: 250
height: 150
visible: true
title: "METANIT.COM"
TableModel{
id: userTable
TableModelColumn { display: "name"}
TableModelColumn { display: "age" }
rows:[
{name: "Tom", age: 39},
{name: "Bob", age: 43},
{name: "Sam", age: 28}
]
}
TableView {
id: tableView
anchors.fill: parent
model: userTable
selectionBehavior: TableView.SelectRows
selectionModel: ItemSelectionModel {}
delegate: Rectangle {
implicitHeight: 25
implicitWidth: 80
required property bool selected
color: selected ? "lightgray": "white"
Text { text: display }
}
}
SelectionRectangle {
target: tableView
}
}
В данном случае аналогичным способом проверяем свойство "selected" и в зависимости от его значения устанавливаем свойство "color". Здесь надо отметить, что для отрисовки выделения применяется элемент SelectionRectangle, у которого свойство target указывает на TableView. Выделим несколько строк: