qt 5.12.x 기반으로 만들어진 것 입니다.
qml tableview에 전체선택할 수 있게 checkbox를 column에 추가 하고 각 row마다 checkbox를 넣어 사용 할 수 있게 만들었습니다.
CustomTableView.qml
import QtQuick 2.0
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Controls 1.5
TableView {
id: custom_tableview
clip: true
focus: true
frameVisible: true
sortIndicatorOrder: Qt.DescendingOrder
sortIndicatorColumn: 1
selectionMode: SelectionMode.ExtendedSelection//shiftKey_event ? SelectionMode.ExtendedSelection : SelectionMode.SingleSelection
alternatingRowColors: false
property bool all_check: !model ? false : (custom_tableview.model.count > 0 ?
custom_tableview.selection.count === custom_tableview.model.count : false)
property bool shiftKey_event: false
Component { //동적으로 tableview에 넣을 checkbox component
id: checkBoxColumnComponent
TableViewColumn {
id: checkBoxTableViewColumn
resizable: false
movable: false
delegate: Item {
CheckBox {
implicitWidth: 14
implicitHeight: 14
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
checked: model ? model.checked : false
}
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
enabled: shiftKey_event ? false : true
onClicked: {
if(model) {
if(!model.checked) {
custom_tableview.selection.select(styleData.row)
} else {
custom_tableview.selection.deselect(styleData.row)
}
}
}
}
}
}
}
Component { //동적으로 tableview에 넣을 일반 text component
id: columnComponent
TableViewColumn {
id: componentTableViewColumn
width: 100
delegate: Text {
id: columnDelegateTxt
text : {
if(styleData.value !== undefined) return styleData.value
else return ""
}
horizontalAlignment: Text.AlignLeft
leftPadding: 10
verticalAlignment: Text.AlignVCenter
clip: true
elide: Text.ElideRight
onImplicitWidthChanged: {
if(implicitWidth > componentTableViewColumn.width) {
componentTableViewColumn.width = implicitWidth + 20
}
}
ToolTip.visible: truncated && mouseArea.containsMouse ? true : false
ToolTip.text: styleData.value
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
}
}
}
}
Component.onCompleted: {
//tableview column을 동적으로 만들게 하였고 제일 처음 column에는 checkbox를 이용한 column
custom_tableview.addColumn(checkBoxColumnComponent.createObject(custom_tableview,
{"role": "checked",
"width": 50}))
custom_tableview.addColumn(columnComponent.createObject(custom_tableview,
{"role": "text",
"title": "TEXT",
"width": 150}))
}
onSortIndicatorColumnChanged: {
if(custom_tableview.rowCount === 0) return ;
if(custom_tableview.getColumn(sortIndicatorColumn).role === "checked") { //전채선택을 눌렀을때
sortIndicatorColumn = ++sortIndicatorColumn
if(all_check) { //전체선택되었던거라면
custom_tableview.selection.clear() // 선택 초기화
} else {
custom_tableview.selection.selectAll() // 모두 선택
}
}
}
headerDelegate: Rectangle {
border.width: 0.5
border.color: "#d2d2d2"
height: 25
color: "#efefef"
clip: true
CheckBox {
id: headerCheckBox
implicitWidth: 14
implicitHeight: 14
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
visible: styleData.column === 0 ? true : false //column이 0번째라면 checkbox활성화
checked: visible && all_check
}
Text {
anchors.left: parent.left
anchors.leftMargin: 8
anchors.verticalCenter: parent.verticalCenter
color: "#2d3150"
text: styleData.value
width: parent.width
elide: Text.ElideRight
visible: !headerCheckBox.visible
}
}
rowDelegate: Rectangle {
height: 35
property var rowSelect: styleData.selected // row가 선택여부
property int rowIdx: -1
readonly property color selectColor: "#D2E4Ed"
color: {
var baseColor = styleData.row % 2 ? "#f6f6f6" : "#ffffff"
return styleData.selected? selectColor : baseColor
}
onRowSelectChanged: {
console.log(styleData.row)
if(styleData.row === undefined) return ;
var no
if(styleData.row === -1) {
no = custom_tableview.model.get(rowIdx).no
} else {
rowIdx = styleData.row
no = custom_tableview.model.get(rowIdx).no
}
custom_tableview.model.setProperty(no, "checked", rowSelect)
}
Text {
anchors.left: parent.left
anchors.leftMargin: 8
anchors.verticalCenter: parent.verticalCenter
color: "#2d3150"
elide: Text.ElideRight
text: styleData.value === undefined ? "" : styleData.value
width: parent.width
}
}
}
아래 코드를 보면
if(all_check) { //전체선택되었던거라면
custom_tableview.selection.clear() // 선택 초기화
} else {
custom_tableview.selection.selectAll() // 모두 선택
}
tableview row를 전체선택 및 전체선택 초기화가있는데 clear(), selectAll() 함수가 호출되게되면 아래 코드에 styleData.selected가 해당 row에 호출된다.
rowDelegate Rectangle {
height: 35
property var rowSelect: styleData.selected // row가 선택여부
}
하지만 데이터가 많으면 많을 수록 selectAll(), clear()를 하게 되면 양이많아서 많이 버벅이지 않을까 싶었는데
tableview 자체에서 내부적으로 caching처리를 하여서 일부의 row에만 signal이 발생하게되어 전혀 버벅이지않게된다.
솔직히 처음에는 for문을 model 갯수만큼 돌려 checkbox를 일일이 true,false를해서 많이 버벅였었다.ㅠ
for(var i =0 ; i < custom_tableview.model.count; ++i) {
custom_tableview.model.setProperty(no, "checked", true)
}
이렇게되면 모든 tableview modal의 데이터가 바뀌어버리니 데이터가 많으면 많을수록 UI에 반영하는 시간등 더오래걸리게 되버린다. 그래서 for을 이용한 데이터 변경은 사용하지않는걸 추천한다.
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Layouts 1.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Component.onCompleted: {
for(var i = 0 ; i < 800000; ++i) {
listModel.append({"checked": false, "no": i, "text": i})
}
}
ListModel {
id: listModel
}
CustomTableView {
id: customTableView
anchors.fill: parent
model: listModel
}
}
listmodel에 800000개의 데이터를 만들고
만들어진 데이터를 customtableview model을 넣어주어 데이터를 UI에 보여주게끔한다.
하지만 ui스레드에서 model에 append하고 tableview에 그리는데 시간이 다소 소요된다. 그 때 동안은 UI스레드가 멈춰있어 행걸린 것 처럼 보일 수 있다.
다음 편에는 listmodel에 데이터를 비동기로 넣어 UI스레드가 행걸리지 않게 만드는 예제를 올리겠습니다.