关于在 QML 中创建表的问题似乎相当频繁地发布,但我还没有看到编译所有不同选项的答案。有很多方法可以实现您的要求。我希望在这个答案中提供一些替代方案。
TableView(5.12 及更高版本)
(2021 年 7 月 16 日更新)
Qt 5.12 包含一个名为TableView 的新Qt Quick 项目,它经过重新设计,可以为具有任意数量的行或列的数据模型提供良好的性能。它解决了之前的TableView from`Quick Controls 1 中存在的性能问题。
在创建此答案时 TableView 不存在,但我在最近的答案中提供了新 TableView 的使用示例:https://stackoverflow.com/a/68347396/5414907
它为基于委托implicitWidth 调整列宽提供了良好的内置支持,但它仅对视口中的行这样做,这意味着滚动可能会显示不适合列的数据,除非你强制使用forceLayout()。
如果您使用的是 Qt 5.12,并且您知道您的表格需要水平滚动和垂直滚动(视图中的行和列数过多),那么这似乎是首选解决方案。
Qt 在此处提供了新 TableView 与旧 TableView 的性能比较:http://blog.qt.io/blog/2018/12/20/tableview-performance/
下面是 Qt 5.11 和更早版本的替代方法的摘要,或者如果由于某种原因您不想使用 Qt 5.12 TableView(也许这些替代方法之一更适合您的数据模型?)。
网格布局
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
ListModel {
id: listModel
ListElement { name: 'item1'; code: "alpha"; language: "english" }
ListElement { name: 'item2'; code: "beta"; language: "french" }
ListElement { name: 'item3'; code: "long-code"; language: "long-language" }
}
GridLayout {
flow: GridLayout.TopToBottom
rows: listModel.count
columnSpacing: 0
rowSpacing: 0
Repeater {
model: listModel
delegate: Label {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
Layout.preferredWidth: implicitWidth
background: Rectangle { border.color: "red" }
text: name
}
}
Repeater {
model: listModel
delegate: Label {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
Layout.preferredWidth: implicitWidth
background: Rectangle { border.color: "green" }
text: code
}
}
Repeater {
model: listModel
delegate: Label {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
Layout.preferredWidth: implicitWidth
background: Rectangle { border.color: "blue" }
text: language
}
}
}
}
垂直列表视图
使用 Vertical ListView 创建表格有其优点和缺点。
优点:
- 可滚动
- 在可视区域之外动态创建代理,这意味着加载速度更快
- 易于为固定宽度的列创建,其中文本被省略或换行
缺点:
- 对于垂直滚动
ListView(这通常是人们想要的),动态列宽很难实现...即列宽设置为完全适合列中的所有值
必须使用对该列内所有模型数据的循环来计算列宽,这可能会很慢并且您不希望经常执行此操作(例如,如果用户可以修改单元格内容并且您希望调整列的大小)。
当模型分配给ListView 时,只计算一次列宽,并且混合使用固定宽度和计算宽度的列,可以实现合理的折衷。
警告:以下是计算列宽以适应最长文本的示例。如果您有一个大型模型,您应该考虑放弃 Javascript 循环并使用固定宽度的列(或相对于视图大小的固定比例)。
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
ListModel {
id: listModel
ListElement { name: 'item1'; code: "alpha"; language: "english" }
ListElement { name: 'item2'; code: "beta"; language: "french" }
ListElement { name: 'item3'; code: "long-code"; language: "long-language" }
}
ListView {
property var columnWidths: ({"name": 100, "code": 50}) // fixed sizes or minimum sizes
property var calculatedColumns: ["code", "language"] // list auto sized columns in here
orientation: Qt.Vertical
anchors.fill: parent
model: listModel
TextMetrics {
id: textMetrics
}
onModelChanged: {
for (var i = 0; i < calculatedColumns.length; i++) {
var role = calculatedColumns[i]
if (!columnWidths[role]) columnWidths[role] = 0
var modelWidth = columnWidths[role]
for(var j = 0; j < model.count; j++){
textMetrics.text = model.get(j)[role]
modelWidth = Math.max(textMetrics.width, modelWidth)
}
columnWidths[role] = modelWidth
}
}
delegate: RowLayout {
property var columnWidths: ListView.view.columnWidths
spacing: 0
Label {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
Layout.preferredWidth: columnWidths.name
background: Rectangle { border.color: "red" }
text: name
}
Label {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
Layout.preferredWidth: columnWidths.code
background: Rectangle { border.color: "green" }
text: code
}
Label {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
Layout.preferredWidth: columnWidths.language
background: Rectangle { border.color: "blue" }
text: language
}
}
}
}
TableView(5.11 及更早版本)
(来自快速控制 1)
QC1 有一个TableView 组件。 QC2 没有(在 Qt 5.9 中)。有一个正在开发中,但没有保证的时间表。
TableView 由于性能问题一直不受欢迎,但它在 Quick Controls 1.0 到 1.4 之间确实得到了改进,并且它仍然是一个可用的组件。 QC1 和 QC2 可以在同一个应用程序中混合使用。
优点
- 轻松实现电子表格样式的用户可调整大小的列
- 基于
ListView,因此可以很好地处理大量行。
- 只有类似于 Widgets 中的
QTableView 的内置组件
缺点
- 默认样式是一种桌面灰色。与使用
ListView 从头开始相比,您可能会花费更多时间尝试覆盖样式。
- 自动调整列大小以适应最长的内容不太实用/实际上不起作用。
例子:
import QtQuick 2.7
import QtQuick.Controls 1.4 as QC1
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 400
height: 200
ListModel {
id: listModel
ListElement { name: 'item1'; code: "alpha"; language: "english" }
ListElement { name: 'item2'; code: "beta"; language: "french" }
ListElement { name: 'item3'; code: "long-code"; language: "long-language" }
}
QC1.TableView {
id: tableView
width: parent.width
model: listModel
QC1.TableViewColumn {
id: nameColumn
role: "name"
title: "name"
width: 100
}
QC1.TableViewColumn {
id: codeColumn
role: "code"
title: "code"
width: 100
}
QC1.TableViewColumn {
id: languageColumn
role: "language"
title: "language"
width: tableView.viewport.width - nameColumn.width - codeColumn.width
}
}
}