aboutsummaryrefslogtreecommitdiffstats
path: root/tests/manual
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2022-09-27 14:03:18 +0200
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2022-11-09 12:15:07 +0100
commit8733b01ce3e8eadbbe62b9e9a264d4ce699a6be8 (patch)
tree442158b24d6a683646239a197a0259028df10a0f /tests/manual
parentcb59815631a216b077a27e44b6886f7474b6496b (diff)
QQuickTableView: implement support for letting the user resize rows and columns
This patch will add support to TableView for resizing rows and columns by dragging between the cells. To achieve this, a custom pointer handler (QQuickTableViewResizeHandler) is implemented. This handler can detect if the pointer is hovering between the cells, and if the user starts a drag. This information is used to call out to the new setColumnWidth()/setRowHeight() API for adjusting the row and column sizes while the user is dragging. The pointer handler is careful to make sure that you can only start to resize by dragging _between_ the cells. If the drag starts elsewhere, the solution will fall back to normal contentItem dragging/flicking instead. Resizing is off by default. The user can enable it by setting the resizableRows/resizableColumns properties. In addition, an API that lets you query the state of the resizing has been added. [ChangeLog][Quick][TableView] Added resizableColumns and resizableRows properties to enable resizing by dragging between cells. Change-Id: I05d4170f30b8c6461a5877c2b831a1ab044d2b5b Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'tests/manual')
-rw-r--r--tests/manual/tableview/abstracttablemodel/main.cpp34
-rw-r--r--tests/manual/tableview/abstracttablemodel/main.qml567
-rw-r--r--tests/manual/tableview/storagemodel/main.qml9
3 files changed, 450 insertions, 160 deletions
diff --git a/tests/manual/tableview/abstracttablemodel/main.cpp b/tests/manual/tableview/abstracttablemodel/main.cpp
index d3cf2bed78..dadd992ef7 100644
--- a/tests/manual/tableview/abstracttablemodel/main.cpp
+++ b/tests/manual/tableview/abstracttablemodel/main.cpp
@@ -47,7 +47,7 @@ public:
for (int x = 0; x < m_cols; ++x) {
m_modelData[x] = QVector<CellData>(m_rows);
for (int y = 0; y < m_rows; ++y)
- m_modelData[x][y] = qMakePair(QStringLiteral("white"), false);
+ m_modelData[x][y] = qMakePair(QString("%1, %2").arg(x).arg(y), false);
}
}
@@ -71,15 +71,25 @@ public:
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) override
{
- if (role != Qt::CheckStateRole)
- return false;
-
- bool checked = value.toBool();
- auto &cellData = m_modelData[index.column()][index.row()];
- if (checked == cellData.second)
- return false;
-
- cellData.second = checked;
+ switch (role) {
+ case Qt::DisplayRole: {
+ QString text = value.toString();
+ auto &cellData = m_modelData[index.column()][index.row()];
+ if (text == cellData.first)
+ return false;
+ cellData.first = text;
+ break; }
+ case Qt::CheckStateRole: {
+ bool checked = value.toBool();
+ auto &cellData = m_modelData[index.column()][index.row()];
+ if (checked == cellData.second)
+ return false;
+
+ cellData.second = checked;
+ break; }
+ default:
+ return QAbstractTableModel::setData(index, value, role);
+ }
emit dataChanged(index, index, {role});
return true;
@@ -124,7 +134,7 @@ public:
for (int y = 0; y < count; ++y) {
for (int x = 0; x < m_cols; ++x)
- m_modelData[x].insert(row, qMakePair(QStringLiteral("lightgreen"), false));
+ m_modelData[x].insert(row, qMakePair(QStringLiteral("added"), false));
}
endInsertRows();
@@ -166,7 +176,7 @@ public:
const int c = column + x;
m_modelData.insert(c, QVector<CellData>(m_rows));
for (int y = 0; y < m_rows; ++y)
- m_modelData[c][y] = qMakePair(QStringLiteral("lightblue"), false);
+ m_modelData[c][y] = qMakePair(QStringLiteral("added"), false);
}
endInsertColumns();
diff --git a/tests/manual/tableview/abstracttablemodel/main.qml b/tests/manual/tableview/abstracttablemodel/main.qml
index 14dd590025..36f27afda3 100644
--- a/tests/manual/tableview/abstracttablemodel/main.qml
+++ b/tests/manual/tableview/abstracttablemodel/main.qml
@@ -6,207 +6,486 @@ import QtQuick.Window
import QtQml.Models
import TestTableModel
import QtQuick.Controls
+import QtQuick.Layouts
import Qt.labs.qmlmodels
ApplicationWindow {
id: window
- width: 640
- height: 480
+ width: 1000
+ height: 800
visible: true
- property int selectedX: -1
- property int selectedY: -1
+ readonly property var currentIndex: tableView.selectionModel.currentIndex
+ readonly property point positionOffset: useOffset.checked ? Qt.point(10, 10) : Qt.point(0, 0)
+ readonly property rect positionSubRect: useSubRect.checked ? Qt.rect(10, 10, 10, 10) : Qt.rect(0, 0, 0, 0)
+ property int hiddenColumn: -1
- Item {
- anchors.fill: parent
-
- Column {
- id: menu
- x: 2
- y: 2
-
- Row {
- spacing: 1
- Button {
- text: "Add row"
- onClicked: tableView.model.insertRows(selectedY, 1)
- }
- Button {
- text: "Remove row"
- onClicked: tableView.model.removeRows(selectedY, 1)
- }
- Button {
- text: "Add column"
- onClicked: tableView.model.insertColumns(selectedX, 1)
- }
- Button {
- text: "Remove column"
- onClicked: tableView.model.removeColumns(selectedX, 1)
+ ScrollView {
+ id: menu
+ height: window.height
+ width: 230
+
+ readonly property real menuMargin: 10
+
+ ColumnLayout {
+ GroupBox {
+ Layout.minimumWidth: menu.availableWidth - (menu.menuMargin * 2)
+ Layout.rightMargin: menu.menuMargin
+ Layout.leftMargin: menu.menuMargin
+ Layout.topMargin: menu.menuMargin
+ ColumnLayout {
+ CheckBox {
+ text: "Use Syncview"
+ checkable: true
+ checked: true
+ onCheckedChanged: {
+ if (checked) {
+ leftHeader.syncView = tableView
+ topHeader.syncView = tableView
+ } else {
+ leftHeader.syncView = null
+ topHeader.syncView = null
+ }
+ }
+ }
+
+ CheckBox {
+ id: flickingMode
+ checkable: true
+ checked: true
+ text: "Enable flicking"
+ }
+
+ CheckBox {
+ id: indexNavigation
+ checkable: true
+ checked: true
+ text: "Enable navigation"
+ }
+
+ CheckBox {
+ id: resizableRowsEnabled
+ checkable: true
+ checked: false
+ text: "Resizable rows"
+ }
+
+ CheckBox {
+ id: resizableColumnsEnabled
+ checkable: true
+ checked: false
+ text: "Resizable columns"
+ }
+
+ CheckBox {
+ id: enableAnimation
+ checkable: true
+ checked: true
+ text: "Enable animation"
+ }
+
+ CheckBox {
+ id: drawText
+ checkable: true
+ checked: true
+ text: "Draw text"
+ }
+
+ CheckBox {
+ id: useRandomColor
+ checkable: true
+ checked: false
+ text: "Use colors"
+ }
+
+ CheckBox {
+ id: useLargeCells
+ checkable: true
+ checked: false
+ text: "Use large cells"
+ onCheckedChanged: Qt.callLater(tableView.forceLayout)
+ }
+
+ CheckBox {
+ id: useSubRect
+ checkable: true
+ checked: false
+ text: "Use subRect"
+ }
+
+ CheckBox {
+ id: useOffset
+ checkable: true
+ checked: false
+ text: "Use offset"
+ }
+
+ CheckBox {
+ id: highlightCurrentRow
+ checkable: true
+ checked: false
+ text: "Highlight row/col"
+ }
}
- SpinBox {
- id: spaceSpinBox
- from: -100
- to: 100
- value: 0
+ }
+
+ GroupBox {
+ Layout.minimumWidth: menu.availableWidth - (menu.menuMargin * 2)
+ Layout.rightMargin: menu.menuMargin
+ Layout.leftMargin: menu.menuMargin
+ GridLayout {
+ columns: 2
+ Label { text: "Model size:" }
+ SpinBox {
+ id: modelSize
+ from: 0
+ to: 1000
+ value: 200
+ editable: true
+ }
+ Label { text: "Spacing:" }
+ SpinBox {
+ id: spaceSpinBox
+ from: -100
+ to: 100
+ value: 1
+ editable: true
+ }
+ Label { text: "Margins:" }
+ SpinBox {
+ id: marginsSpinBox
+ from: 0
+ to: 100
+ value: 1
+ editable: true
+ }
}
}
- Row {
- spacing: 1
- Button {
- text: "fast-flick<br>center table"
- onClicked: {
- tableView.contentX += tableView.width * 1.2
+ GroupBox {
+ Layout.minimumWidth: menu.availableWidth - (menu.menuMargin * 2)
+ Layout.rightMargin: menu.menuMargin
+ Layout.leftMargin: menu.menuMargin
+ RowLayout {
+ id: positionRow
+ Button {
+ text: "<<"
+ onClicked: {
+ tableView.positionViewAtRow(0, Qt.AlignTop, -tableView.topMargin)
+ tableView.positionViewAtColumn(0, Qt.AlignLeft, -tableView.leftMargin)
+ }
+ }
+
+ Button {
+ text: ">>"
+ onClicked: {
+ tableView.positionViewAtRow(tableView.rows - 1, Qt.AlignBottom, tableView.bottomMargin)
+ tableView.positionViewAtColumn(tableView.columns - 1, Qt.AlignRight, tableView.rightMargin)
+ }
}
}
- Button {
- text: "flick to end<br>center table"
- onClicked: {
- tableView.contentX = tableView.contentWidth - tableView.width
+ }
+
+ GroupBox {
+ Layout.minimumWidth: menu.availableWidth - (menu.menuMargin * 2)
+ Layout.rightMargin: menu.menuMargin
+ Layout.leftMargin: menu.menuMargin
+ ColumnLayout {
+ Button {
+ text: "Add row"
+ enabled: currentIndex.valid
+ onClicked: tableView.model.insertRows(currentIndex.row, 1)
+ }
+
+ Button {
+ text: "Remove row"
+ enabled: currentIndex.valid
+ onClicked: tableView.model.removeRows(currentIndex.row, 1)
+ }
+
+ Button {
+ text: "Add column"
+ enabled: currentIndex.valid
+ onClicked: tableView.model.insertColumns(currentIndex.column, 1)
+ }
+
+ Button {
+ text: "Remove column"
+ enabled: currentIndex.valid
+ onClicked: tableView.model.removeColumns(currentIndex.column, 1)
+ }
+
+ Button {
+ text: "Hide column"
+ enabled: currentIndex.valid
+ onClicked: {
+ hiddenColumn = currentIndex.column
+ tableView.forceLayout()
+ }
}
}
- Button {
- text: "fast-flick<br>headers"
- onClicked: {
- leftHeader.contentY += 1000
- topHeader.contentX += 1000
+ }
+
+ GroupBox {
+ Layout.minimumWidth: menu.availableWidth - (menu.menuMargin * 2)
+ Layout.rightMargin: menu.menuMargin
+ Layout.leftMargin: menu.menuMargin
+ ColumnLayout {
+ RadioButton {
+ id: selectionDisabled
+ text: "SelectionDisabled"
+ }
+ RadioButton {
+ id: selectCells
+ text: "SelectCells"
+ checked: true
+ }
+ RadioButton {
+ id: selectRows
+ text: "SelectRows"
+ }
+ RadioButton {
+ id: selectColumns
+ text: "SelectColumns"
+ }
+ Label {
+ width: parent.width
+ font.pixelSize: 10
+ text: "(SelectionMode: " + (tableView.interactive ? "PressAndHold)" : "Drag)")
}
}
- Button {
- text: "set/unset<br>master bindings"
- onClicked: {
- leftHeader.syncView = leftHeader.syncView ? null : tableView
- topHeader.syncView = topHeader.syncView ? null : tableView
+ }
+
+ GroupBox {
+ Layout.minimumWidth: menu.availableWidth - (menu.menuMargin * 2)
+ Layout.rightMargin: menu.menuMargin
+ Layout.leftMargin: menu.menuMargin
+ ColumnLayout {
+ Button {
+ text: "Current to top-left"
+ enabled: currentIndex.valid
+ onClicked: {
+ let cell = Qt.point(currentIndex.column, currentIndex.row)
+ tableView.positionViewAtCell(cell, Qt.AlignTop | Qt.AlignLeft, positionOffset, positionSubRect)
+ }
+ }
+
+ Button {
+ text: "Current to center"
+ enabled: currentIndex.valid
+ onClicked: {
+ let cell = Qt.point(currentIndex.column, currentIndex.row)
+ tableView.positionViewAtCell(cell, Qt.AlignCenter, positionOffset, positionSubRect)
+ }
+ }
+
+ Button {
+ text: "Current to bottom-right"
+ enabled: currentIndex.valid
+ onClicked: {
+ let cell = Qt.point(currentIndex.column, currentIndex.row)
+ tableView.positionViewAtCell(cell, Qt.AlignBottom | Qt.AlignRight, positionOffset, positionSubRect)
+ }
+ }
+
+ Button {
+ text: "Current to Visible"
+ enabled: currentIndex.valid
+ onClicked: {
+ let cell = Qt.point(currentIndex.column, currentIndex.row)
+ tableView.positionViewAtCell(cell, TableView.Visible, positionOffset, positionSubRect)
+ }
+ }
+
+ Button {
+ text: "Current to Contain"
+ enabled: currentIndex.valid
+ onClicked: {
+ let cell = Qt.point(currentIndex.column, currentIndex.row)
+ tableView.positionViewAtCell(cell, TableView.Contain, positionOffset, positionSubRect)
+ }
}
}
- Button {
- id: flickingMode
- checkable: true
- text: checked ? "Flickable" : "Scrollable"
+ }
+
+ GroupBox {
+ Layout.minimumWidth: menu.availableWidth - (menu.menuMargin * 2)
+ Layout.rightMargin: menu.menuMargin
+ Layout.leftMargin: menu.menuMargin
+ Layout.bottomMargin: menu.menuMargin
+ ColumnLayout {
+ Button {
+ text: "Fast-flick table"
+ onClicked: {
+ tableView.contentX += tableView.width * 1.2
+ }
+ }
+
+ Button {
+ text: "Fast-flick headers"
+ onClicked: {
+ topHeader.contentX += tableView.width * 1.2
+ leftHeader.contentY += tableView.height * 1.2
+ }
+ }
}
}
- Text {
- text: "Selected: x:" + selectedX + ", y:" + selectedY
+
+ Item {
+ Layout.fillHeight: true
}
}
+ }
- TableView {
- id: topHeader
- objectName: "topHeader"
- anchors.left: tableView.left
- width: tableView.width
- anchors.top: menu.bottom
- height: 30
- clip: true
- ScrollBar.horizontal: ScrollBar {}
+ TableView {
+ id: topHeader
+ objectName: "topHeader"
+ anchors.left: centerScrollView.left
+ anchors.right: centerScrollView.right
+ anchors.top: menu.top
+ height: 30
+ clip: true
- model: TestTableModel {
- rowCount: 1
- columnCount: 200
- }
+ model: TestTableModel {
+ rowCount: 1
+ columnCount: modelSize.value
+ }
- delegate: Rectangle {
- implicitHeight: topHeader.height
- implicitWidth: 20
- color: "lightgray"
- Text { text: column }
+ delegate: Rectangle {
+ implicitHeight: topHeader.height
+ implicitWidth: 20
+ color: "lightgray"
+ Text {
+ anchors.centerIn: parent
+ visible: drawText.checked
+ text: column
+ font.pointSize: 8
}
+ }
- columnSpacing: 1
- rowSpacing: 1
+ columnSpacing: 1
+ rowSpacing: 1
- syncView: tableView
- syncDirection: Qt.Horizontal
- }
+ syncView: tableView
+ syncDirection: Qt.Horizontal
+ resizableColumns: resizableColumnsEnabled.checked
+ }
- TableView {
- id: leftHeader
- objectName: "leftHeader"
- anchors.left: parent.left
- anchors.top: tableView.top
- height: tableView.height
- width: 30
- clip: true
- ScrollBar.vertical: ScrollBar {}
+ TableView {
+ id: leftHeader
+ objectName: "leftHeader"
+ anchors.left: menu.right
+ anchors.top: centerScrollView.top
+ anchors.bottom: centerScrollView.bottom
+ width: 30
+ clip: true
- model: TestTableModel {
- rowCount: 200
- columnCount: 1
- }
+ model: TestTableModel {
+ rowCount: modelSize.value
+ columnCount: 1
+ }
- delegate: Rectangle {
- implicitHeight: 50
- implicitWidth: leftHeader.width
- color: "lightgray"
- Text { text: row }
+ delegate: Rectangle {
+ implicitHeight: 50
+ implicitWidth: leftHeader.width
+ color: "lightgray"
+ Text {
+ anchors.centerIn: parent
+ visible: drawText.checked
+ text: row
+ font.pointSize: 8
}
+ }
- columnSpacing: 1
- rowSpacing: 1
+ columnSpacing: 1
+ rowSpacing: 1
- syncView: tableView
- syncDirection: Qt.Vertical
- }
+ syncView: tableView
+ syncDirection: Qt.Vertical
+ resizableRows: resizableRowsEnabled.checked
+ }
+
+ Item {
+ id: centerScrollView
+ anchors.left: leftHeader.right
+ anchors.right: parent.right
+ anchors.top: topHeader.bottom
+ anchors.bottom: parent.bottom
+ anchors.rightMargin: 10
+ anchors.bottomMargin: 10
TableView {
id: tableView
+ anchors.fill: parent
objectName: "tableview"
- anchors.left: leftHeader.right
- anchors.right: parent.right
- anchors.top: topHeader.bottom
- anchors.bottom: parent.bottom
- width: 200
clip: true
delegate: tableViewDelegate
columnSpacing: spaceSpinBox.value
rowSpacing: spaceSpinBox.value
interactive: flickingMode.checked
+ keyNavigationEnabled: indexNavigation.checked
+ pointerNavigationEnabled: indexNavigation.checked
+ resizableRows: resizableRowsEnabled.checked
+ resizableColumns: resizableColumnsEnabled.checked
+ animate: enableAnimation.checked
+ selectionBehavior: selectCells.checked ? TableView.SelectCells
+ : selectColumns.checked ? TableView.SelectColumns
+ : selectRows.checked ? TableView.SelectRows
+ : TableView.SelectionDisabled
+ leftMargin: marginsSpinBox.value
+ topMargin: marginsSpinBox.value
+ rightMargin: marginsSpinBox.value
+ bottomMargin: marginsSpinBox.value
- columnWidthProvider: function(c) {
- if (c > 30)
- return 100
- }
-
- ScrollBar.horizontal: ScrollBar {}
- ScrollBar.vertical: ScrollBar {}
+ ScrollBar.horizontal: ScrollBar { visible: !flickingMode.checked }
+ ScrollBar.vertical: ScrollBar { visible: !flickingMode.checked }
model: TestTableModel {
- rowCount: 200
- columnCount: 60
+ rowCount: modelSize.value
+ columnCount: modelSize.value
}
selectionModel: ItemSelectionModel {}
}
+ }
- SelectionRectangle {
- target: tableView
- }
+ SelectionRectangle {
+ target: tableView
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ id: delegate
+ implicitWidth: useLargeCells.checked ? 1000 : 50
+ implicitHeight: useLargeCells.checked ? 1000 : 30
+ border.width: current ? 2 : 0
+ border.color: "darkgreen"
+ property var randomColor: Qt.rgba(0.6 + (0.4 * Math.random()), 0.6 + (0.4 * Math.random()), 0.6 + (0.4 * Math.random()), 1)
+ color: selected ? "lightgreen"
+ : (highlightCurrentRow.checked && (row === tableView.currentRow || column === tableView.currentColumn)) ? "lightgray"
+ : useRandomColor.checked ? randomColor
+ : model.display === "added" ? "lightblue"
+ : "white"
+
+ required property bool selected
+ required property bool current
- Component {
- id: tableViewDelegate
Rectangle {
- id: delegate
- implicitWidth: 50
- implicitHeight: 30
- border.width: row === selectedY && column == selectedX ? 2 : 0
- border.color: "darkgreen"
- color: selected ? "lightgreen" : "white"
- required property bool selected
-
- TapHandler {
- onTapped: {
- selectedX = column
- selectedY = row
- }
- }
+ x: positionSubRect.x
+ y: positionSubRect.y
+ width: positionSubRect.width
+ height: positionSubRect.height
+ border.color: "red"
+ visible: useSubRect.checked
+ }
- Text {
- anchors.centerIn: parent
- text: column + ", " + row
- }
+ Text {
+ anchors.centerIn: parent
+ visible: drawText.checked
+ text: model.display
}
}
-
}
}
diff --git a/tests/manual/tableview/storagemodel/main.qml b/tests/manual/tableview/storagemodel/main.qml
index 71c97b78f1..f188c66fb9 100644
--- a/tests/manual/tableview/storagemodel/main.qml
+++ b/tests/manual/tableview/storagemodel/main.qml
@@ -1,10 +1,10 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-import QtQuick 2.12
-import QtQuick.Window 2.12
-import Qt.labs.qmlmodels 1.0
-import StorageModel 0.1
+import QtQuick
+import QtQuick.Window
+import Qt.labs.qmlmodels
+import StorageModel
Window {
id: window
@@ -22,6 +22,7 @@ Window {
model: StorageModel { }
columnSpacing: 1
rowSpacing: 1
+ resizableColumns: true
delegate: DelegateChooser {
role: "type"
DelegateChoice {