在Qt Quick中从ListView制作自定义TableView的规范方法 [英] Canonical way to make custom TableView from ListView in Qt Quick
问题描述
用ListView
制作表格的最佳方法是什么?
What is the best way to make table from ListView
?
说,给定二维数组字符串,所有列的delegate
为Label
.仅使用QML时,如何以及何时计算每列的最大项目宽度?每个Label
的内容不是恒定的(即implicitWidth
在生命周期内是可变的).
Say, given a 2d array of strings and delegate
for all the columns are Label
s. How and when to calculate maximum item width for each column while using only QML? Content of each Label
is not constant (i.e. implicitWidth
is mutable during lifetime).
发明TableView
的实际原因是事实,到TreeView
的步骤仍将保留.
Practical reason to invent the TableView
is the fact, that 1 step to TreeView
will remain.
推荐答案
关于在QML中创建表的问题似乎经常发布,但是我还没有看到一个汇总所有不同选项的答案.有很多方法可以实现您的要求.我希望在此答案中提供多种选择.
Questions about creating tables in QML seem to get posted fairly frequently, but I am yet to see an answer compiling all the different options. There are lots of ways to achieve what you are asking. I hope to provide in this answer a number of alternatives.
(2019年1月14日更新)
(Updated 14 Jan 2019)
Qt 5.12包含一个新的名为TableView
的Qt Quick项目,该项目从头开始进行了重新设计,以使其对于具有任意行或列数的数据模型都具有良好的性能.它解决了Quick Controls 1中以前TableView
中存在的性能问题.
Qt 5.12 includes a new Qt Quick item called TableView
, which has been redesigned from the ground up to have good performance for a data model with any number of rows or columns. It resolves the performance problems which were present in the previous TableView
from`Quick Controls 1.
我无法提供此方法的使用示例,因为我还没有使用它(我的项目仍在使用Qt 5.9),但是Qt文档中有适用于5.12和更高版本的示例.
I cannot provide a usage example for this approach, because I haven't used it yet (I am still using Qt 5.9 for my projects), but there are examples in the Qt documentation for 5.12 and later.
- 性能比较: http://blog.qt.io /blog/2018/12/20/tableview-performance/
- 文档: https://doc.qt.io/qt -5/qml-qtquick-tableview.html
- Performance Comparison: http://blog.qt.io/blog/2018/12/20/tableview-performance/
- Documentation: https://doc.qt.io/qt-5/qml-qtquick-tableview.html
如果您使用的是Qt 5.12,并且您知道表将同时需要水平滚动和垂直滚动(行和列的数量超出视图的容纳范围),那么这似乎是首选解决方案.
If you are using Qt 5.12, and you know that you will need both horizontal scrolling and vertical scrolling for your table (there are more rows AND columns than can fit in the view), then this would seem to be the first choice solution.
以下是Qt 5.11及更早版本的替代方法的摘要,或者如果您出于某种原因不想使用Qt 5.12 TableView
(也许这些替代方法之一更适合您的数据模型?).
Below are a summary of alternative approaches for Qt 5.11 and earlier, or if for some reason you do not want to use the Qt 5.12 TableView
(perhaps one of these alternative approaches better suits your data model?).
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
使用Vertical ListView
创建表有其优点和缺点.
优点:
Vertical ListView
Creating a table with the Vertical ListView
has its advantages and disadvantages.
Pros:
- 可滚动
- 动态创建可见区域之外的代表,这意味着加载速度更快
- 易于创建固定宽度的列,在该列中文本被消除或包裹
缺点:
- 对于垂直滚动
ListView
(通常这是人们想要的),动态列宽很难实现...即列宽设置为完全适合列中的所有值
- For a vertical scrolling
ListView
(which is usually what people want), dynamic column width is difficult to achieve... i.e. column width is set to completely fit all values in the column
必须使用循环遍历该列内的所有模型数据来计算列宽,这可能很慢,并且您不希望经常执行此操作(例如,如果用户可以修改单元格内容并且您希望调整列的大小) ).
Column widths must be calculated using a loop over all the model data inside that column, which could be slow and is not something you would want to perform often (for example if user can modify cell contents and you want the column to resize).
在将模型分配给ListView
时,仅计算一次列宽,并混合使用固定宽度和计算宽度的列即可实现合理的折衷.
A reasonable compromise can be achieved by only calculating the column widths once, when the model is assigned to the ListView
, and having a mixture of fixed-width and calculated-width columns.
警告:以下是示例,该示例计算列宽以适合最长的文本.如果模型较大,则应考虑废弃Javascript循环,并采用固定宽度的列(或相对于视图大小的固定比例).
Warning: Below is an example of calculating column widths to fit longest text. If you have a large model, you should consider scrapping the Javascript loop and resort to fixed width columns (or fixed proportions relative to the view size).
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和更早版本)
(来自Quick Controls 1)
TableView (5.11 and earlier)
(from Quick Controls 1)
QC1具有TableView
组件. QC2没有(在Qt 5.9中).有一个正在开发中,但是没有保证的时间范围.
QC1 has a TableView
component. QC2 does not (in Qt 5.9). There is one in development, but with no guaranteed timescale.
TableView
一直不受欢迎,但是它确实在Quick Controls 1.0到1.4之间得到了改进,并且它仍然是可用的组件. QC1和QC2可以在同一应用程序中混合使用.
TableView
has been unpopular due to performance issues, but it did receive improvements between Quick Controls 1.0 to 1.4, and it remains a useable component. QC1 and QC2 can be mixed in the same application.
优点
- 易于实现电子表格样式的用户可调整大小的列
- 基于
ListView
,因此可以很好地处理大量行. - 仅类似于Widget中
QTableView
的内置组件
- easy to achieve spreadsheet-style user-resizable columns
- based on a
ListView
, so handles large numbers of rows well. - only built-in component resembling the
QTableView
from Widgets
缺点
- 默认样式是一种桌面灰色.与使用
ListView
从头开始相比,您可能要花更多的时间来尝试覆盖样式. - 自动调整列的大小以适合最长的内容不是很实际,也不是真的不可行.
- default styling is a sort of desktop-grey. You might spend more time trying to override the styling than if you started from scratch using a
ListView
. - auto resizing columns to fit longest contents not really practical / doesn't really work.
示例:
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
}
}
}
这篇关于在Qt Quick中从ListView制作自定义TableView的规范方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!