关于在 QML 中创建表的问题似乎经常发布,但我还没有看到编译所有不同选项的答案。有很多方法可以实现您的要求。我希望在这个答案中提供一些替代方案。
TableView(5.12 及更高版本)
(更新于 16/07/2021)
Qt 5.12 包含一个新的 Qt Quick 项目,称为TableView
,它经过了彻底的重新设计,对于具有任意数量的行或列的数据模型具有良好的性能。它解决了之前存在的性能问题TableView
来自“快速控制 1”。
在创建此答案时 TableView 不存在,但我在此处的最新答案中提供了新 TableView 的使用示例:https://stackoverflow.com/a/68347396/5414907 https://stackoverflow.com/a/68347396/5414907
它为根据委托调整列宽提供了良好的内置支持implicitWidth
,但它仅对视口中的行执行此操作,这意味着滚动可能会显示不适合列的数据,除非您强制forceLayout()
.
如果您使用的是 Qt 5.12,并且您知道表格需要水平滚动和垂直滚动(行和列的数量超出了视图的容纳范围),那么这似乎是首选解决方案。
Qt 在这里提供了新 TableView 与旧 TableView 的性能比较:http://blog.qt.io/blog/2018/12/20/tableview-performance/ http://blog.qt.io/blog/2018/12/20/tableview-performance/
以下是 Qt 5.11 及更早版本的替代方法的摘要,或者如果由于某种原因您不想使用 Qt 5.12TableView
(也许这些替代方法之一更适合您的数据模型?)。
网格布局
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
}
}
}
}
垂直列表视图
创建具有垂直方向的表格ListView
有其优点和缺点。
优点:
- 可滚动
- 动态创建可视区域之外的委托,这意味着加载速度更快
- 易于创建固定宽度的列,其中文本被省略或换行
Cons:
- 对于垂直滚动
ListView
(这通常是人们想要的),动态列宽很难实现......即列宽设置为完全适合列中的所有值
列宽必须使用该列内所有模型数据的循环来计算,这可能会很慢并且不是您想要经常执行的操作(例如,如果用户可以修改单元格内容并且您希望调整列大小)。
当模型分配给列宽时,可以通过仅计算一次列宽来实现合理的折衷ListView
,并且混合了固定宽度和计算宽度的列。
警告:下面是一个example计算列宽以适合最长的文本。如果您有一个大型模型,您应该考虑废弃 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 可以在同一应用中混合使用。
Pros
- 轻松实现电子表格样式的用户可调整大小的列
- 基于一个
ListView
,因此可以很好地处理大量行。
- 唯一的内置组件类似于
QTableView
来自小部件
Cons
- 默认样式是一种桌面灰色。与使用从头开始相比,您可能会花费更多时间尝试覆盖样式
ListView
.
- 自动调整列大小以适应最长的内容不太实用/不起作用。
Example:
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
}
}
}