[C++,QT/Qml]20.Qml프로그래밍 동적 리스트 만들기6(체크박스 리스트 삭제)
삭제하도록 하겠습니다.
아래 코드로 설명 드리겠습니다.
ConnectEvent.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
#ifndef CONNECTEVENT_H
#define CONNECTEVENT_
#include <QQuickView>
#include <QObject>
#include <iostream>
using namespace std;
struct TestStruct{
QString title = "";
QString ButtonText = "";
QString Infomation = "";
};
class ConnectEvent : public QObject//connection을 사용하기 위해 상속 받아야 하는 클래스
{
public:
Q_OBJECT
public:
ConnectEvent();
~ConnectEvent();
void setWindow(QQuickWindow* Window);
void setTestList();
Q_INVOKABLE int getListSize();
Q_INVOKABLE QString getListTitle(int index);
Q_INVOKABLE QString getListButtonText(int index);
Q_INVOKABLE QString getListInfomation(int index);
Q_INVOKABLE void deleteListItem(int index);
private:
QQuickWindow* mMainView;
vector<TestStruct> mTestList;
};
#endif // CONNECTEVENT_H
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
ConnectEvent.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
#include "ConnectEvent.h"
ConnectEvent::ConnectEvent()
{
cout << "ConnectEvent" << endl;
setTestList();//생성자에서 호출해서 객체가 만들어 지자마자 데이터를 vector에 담는다.
qmlRegisterType<ConnectEvent>("ConnectEvent", 1, 0, "ConnectEvent");//class를 qml에서 사용하기 위해서 등록해주는 부분
}
ConnectEvent::~ConnectEvent()
{
}
void ConnectEvent::setWindow(QQuickWindow* Window)
{
mMainView = Window;//connection을 해주기 위해 윈도우를 등록
}
void ConnectEvent::setTestList()
{
TestStruct testStruct;
for(int i = 0; i < 10; i++){
testStruct.title = "TestTitle" + QString::number(i);//int형 변수를 QString 형으로 형변환
testStruct.ButtonText = "TestButton" + QString::number(i);
testStruct.Infomation = "TestInfomation" + QString::number(i);
mTestList.push_back(testStruct);
}
}
int ConnectEvent::getListSize()//리스트의 크기를 가져오기 위함 함수
{
return mTestList.size();
}
QString ConnectEvent::getListTitle(int index)//리스트 인덱스의 제목을 가져오기 위한 함수
{
return mTestList.at(index).title;
}
QString ConnectEvent::getListButtonText(int index)//리스트 인덱스의 버튼 텍스트를 가져오기 위한 함수
{
return mTestList.at(index).ButtonText;
}
QString ConnectEvent::getListInfomation(int index)//리스트 인덱스의 내부 정보를 가져오기 위한 함수
{
return mTestList.at(index).Infomation;
}
void ConnectEvent::deleteListItem(int index)//c++ 리스트의 데이터를 삭제
{
int count = 0;
std::cout << "deleteListItem index:" << index << std::endl;
std::cout << "deleteListItem ListInfomation:" << getListInfomation(index).toStdString() << std::endl;
for(std::vector<TestStruct>::iterator it = mTestList.begin(); it != mTestList.end(); it++){
if(count == index){
it = mTestList.erase(it);
break;
}else{
count++;
}
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
main.qml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
import QtQuick 2.9
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
import ConnectEvent 1.0//등록한 클래스 타입을 import해준다.
import "."
Window {
property bool mbImageClicked : true
property int mCount : 0
property int mListClickIndex : 0//클릭한 리스트의 index를 담는 전역 변수
visible: true
width: 800
height: 600
title: qsTr("Hello World")
ConnectEvent//클래스를 qml 타입으로 지정
{
id:connectEvent
}
Component.onCompleted://view가 처음 실행될때 제일 처음으로 불려지는곳
{
for(var i = 0; i < connectEvent.getListSize(); i++){//리스트의 개수만큼 for문을 돌린다.
listView.model.append({"list_text": connectEvent.getListTitle(i),//모델에 리스트의 데이터값을 넣어준다.
"list_button_text": connectEvent.getListButtonText(i)})//listview에 선언한 임의의 모델 안에 데이터를 넣어준다.
}
}
Component {//리스트 뷰의 틀을 만든다.
id: contactDelegate
Item {
width: 800
height: 100
Text//리스트에 텍스트를 넣어주기 위해 텍스트 객체를 만들어준다.
{
id:listView_Text
anchors.left: parent.left
anchors.leftMargin: 50
anchors.verticalCenter: parent.verticalCenter
text:list_text//모델에 매칭이될 변수 listview에 원하는 값을 넣기위해서 설정하는 값
}
Rectangle//리스트의 구분선
{
id:line
width:parent.width
anchors.bottom:parent.bottom//현재 객체의 아래 기준점을 부모객체의 아래로 잡아주어서 위치가 아래로가게 설정
height:1
color:"black"
}
MouseArea
{
id:listMouseArea
anchors.fill: parent
onClicked:
{
mListClickIndex = index;//여기에서 사용하는 index는 클릭했을때의 index를 리턴해준다
//그래서 현재 선택한 리스트를 전역변수에 담고 다음 화면에서 그에 해당하는 정보를 보여준다.
stackView.push(Qt.resolvedUrl("qrc:/deleteList.qml"))
}
}
//버튼 객체를 mouseArea아래로 옮겼다 이유는 mouseArea가 부모의 영역을 포함하고 있는데
//버튼 영역도 부모의 영역 안에 있기 때문에 버튼클릭시 버튼클릭이 아닌 리스트의 클릭이 되어 버린다.
Button//리스트에 버튼을 넣어주기 위해 버튼 객체를 만들어준다.
{
id:listView_Button
width:120
height:40
anchors.rightMargin: 30
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
text: list_button_text//모델에 매칭이될 변수 listview에 원하는 값을 넣기위해서 설정하는 값
onClicked:
{
connectEvent.deleteListItem(index);//c++ 리스트의 데이터를 삭제
listView.model.remove(index);//리스트의 모델에 삭제하는 함수(실시간 삭제)
}
}
}
}
StackView{
id:stackView
anchors.fill: parent
initialItem: Item //제일 첫화면을 설정하는 것으로 설정을 안하면 되돌아오기가 안된다.
{
ListView {
id:listView
anchors.fill: parent
model: ListModel{}//임으로 만들 모델을 넣어준다.
delegate: contactDelegate//delegate란 리스트 한개의 틀(틀을 하나 만들어서 그것들을 여러개 붙여놓은것이 리스트 뷰이다.)
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
focus: true
}
}
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
deletList.qml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
import ConnectEvent 1.0//등록한 클래스 타입을 import해준다.
Item {
width: 800
height: 600
Component.onCompleted://view가 처음 실행될때 제일 처음으로 불려지는곳
{
for(var i = 0; i < connectEvent.getListSize(); i++){//리스트의 개수만큼 for문을 돌린다.
listView.model.append({"list_text": connectEvent.getListTitle(i),//모델에 리스트의 데이터값을 넣어준다.
"list_button_text": connectEvent.getListButtonText(i),
"checkValue": false})//listview에 선언한 임의의 모델 안에 데이터를 넣어준다.
}
}
Component {//리스트 뷰의 틀을 만든다.
id: contactDelegate
Item {
width: 800
height: 100
CheckBox
{
id:checkbox
anchors.left: parent.left
anchors.leftMargin: 30
anchors.verticalCenter: parent.verticalCenter
checked: checkValue
}
Text//리스트에 텍스트를 넣어주기 위해 텍스트 객체를 만들어준다.
{
id:listView_Text
anchors.left: parent.left
anchors.leftMargin: 100
anchors.verticalCenter: parent.verticalCenter
text:list_text//모델에 매칭이될 변수 listview에 원하는 값을 넣기위해서 설정하는 값
}
Rectangle//리스트의 구분선
{
id:line
width:parent.width
anchors.bottom:parent.bottom//현재 객체의 아래 기준점을 부모객체의 아래로 잡아주어서 위치가 아래로가게 설정
height:1
color:"black"
}
MouseArea
{
id:listMouseArea
anchors.fill: parent
onClicked:
{
if(listView.model.get(index).checkValue){
listView.model.get(index).checkValue = false
}else
listView.model.get(index).checkValue = true
}
}
}
}
ListView {
id:listView
width:parent.width
height:parent.height - 100//리스트 뷰 밑에 버튼을 만들기위해 리스트뷰의 크기를 설정하는 것
clip:true//true 하면 리스트의 높이 보다 커도 리스트가 보여지는 것처럼 됨
//false 하면 리스트의 높이만 큼만 deletegate가 보여짐
model: ListModel{}//임으로 만들 모델을 넣어준다.
delegate: contactDelegate//delegate란 리스트 한개의 틀(틀을 하나 만들어서 그것들을 여러개 붙여놓은것이 리스트 뷰이다.)
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
focus: true
}
Button
{
id:deleteButton
width:200
height:50;
anchors.top: listView.bottom
anchors.topMargin: 30
anchors.horizontalCenter:parent.horizontalCenter
text:"delete"
onClicked: {
for(var i = listView.count - 1; i >= 0; i--){
if(listView.model.get(i).checkValue){
connectEvent.deleteListItem(i);
listView.model.remove(i);
}
}
}
}
Button
{
id:allSelectButton
width:200
height:50;
anchors.top: listView.bottom
anchors.topMargin: 30
anchors.left: deleteButton.right
anchors.leftMargin: 20
text:"all Select"
onClicked: {
for(var i = 0; i < listView.count; i++){
if(!listView.model.get(i).checkValue){
listView.model.get(i).checkValue = true
}
}
}
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
아래 동영상은 리스트를 삭제하는 동영상 입니다.
ㅠ
위의 코드를 보시면 삭제화면으로 넘어가기 위해서 stackview push를 이용해서 삭제 화면으로 넘어갔습니다.
1
|
stackView.push(Qt.resolvedUrl("qrc:/deleteList.qml"))
|
그리고 리스트에 checkbox를 그려주기 위해서 delegate에 checkbox를 추가해 줍니다.
여기서 중요한 점은 리스트의 check상태를 알기위해서 checkValue라는 변수를 만들어 주고 모든 리스트를
기본 false로 넣어주어서 체크가 안된 상태를 만들어 줍니다.
1
2
3
4
|
for(var i = 0; i < connectEvent.getListSize(); i++){//리스트의 개수만큼 for문을 돌린다.
listView.model.append({"list_text": connectEvent.getListTitle(i),//모델에 리스트의 데이터값을 넣어준다.
"list_button_text": connectEvent.getListButtonText(i),
"checkValue": false})//listview에 선언한 임의의 모델 안에 데이터를 넣어준다.
|
1
2
3
4
5
6
7
8
|
CheckBox
{
id:checkbox
anchors.left: parent.left
anchors.leftMargin: 30
anchors.verticalCenter: parent.verticalCenter
checked: checkValue
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
그리고 각 리스트를 클릭할때 check상태를 바꿔주기 위해서 mouseArea에 checkbox해제 및 설정 하는 코드를 넣어줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
|
MouseArea
{
id:listMouseArea
anchors.fill: parent
onClicked:
{
if(listView.model.get(index).checkValue){
listView.model.get(index).checkValue = false
}else
listView.model.get(index).checkValue = true
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
여기서 중요한 점은 각 리스트의 check상태를 알기위해서 모델의 특정 index를 가져와서 checkValue를 가져오도록 하였습니다.
그래서 true이면 checkbox를 해제하는 코드를 넣어주었고 false면 checkbox를 설정하는 코드를 넣었습니다.
1
2
3
4
|
if(listView.model.get(index).checkValue){
listView.model.get(index).checkValue = false
}else
listView.model.get(index).checkValue = true
|
그리고 리스트의 check상태에 따라 삭제하는 버튼과 전체 선택하는 버튼을 만들어 줍니다.
전체 선택하는 버튼은 각 리스트가 check가 안되어 있으면 check상태로 바꿔주는 형태로 만들어 주었습니다.
이를 응용하면 전체 해제하는 버튼도 만들어 볼수 있습니다. 이 부분은 글을 읽으시는 분들께서 충분히
만들수 있을것 같아서 따로 만들지는 않았습니다.
모든 리스트 체크하는 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
Button
{
id:allSelectButton
width:200
height:50;
anchors.top: listView.bottom
anchors.topMargin: 30
anchors.left: deleteButton.right
anchors.leftMargin: 20
text:"all Select"
onClicked: {
for(var i = 0; i < listView.count; i++){
if(!listView.model.get(i).checkValue){
listView.model.get(i).checkValue = true
}
}
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
check된 리스트를 삭제하는 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
Button
{
id:deleteButton
width:200
height:50;
anchors.top: listView.bottom
anchors.topMargin: 30
anchors.horizontalCenter:parent.horizontalCenter
text:"delete"
onClicked: {
for(var i = listView.count - 1; i >= 0; i--){
if(listView.model.get(i).checkValue){
connectEvent.deleteListItem(i);
listView.model.remove(i);
}
}
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
위의 check된 리스트를 삭제하는 코드를 보겠습니다.
여기서 가장 중요한 접은 리스트의 맨 아래서 부터 지운다는 것 입니다.
예를들어 1,2,3,4,5라는 리스트가 있다고 한다면 2,3,5 를 지우고 싶다하면
역순으로 5지우고 3지우고 2를 지운다는 것입니다.
이렇게하는 이유는 만약 순서대로 지운다고 치면 1,2,3,4,5 중에 2를 지우면
1,3,4,5 가되고 여기서 리스트의 index가 바뀌어 버립니다. 그래서 3번째 것을 지우면
4가 지워 지고 5번째 것을 지우면 out of index가 발생해서 프로세스가 죽거나 프로그램이 닫히게 됩니다.
그렇기 때문에 아래 보이는 코드처럼 index의 뒤에서 부터 지우게 합니다.
1
2
3
4
5
6
|
for(var i = listView.count - 1; i >= 0; i--){
if(listView.model.get(i).checkValue){
connectEvent.deleteListItem(i);
listView.model.remove(i);
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
그리고 qml 단에서 리스트를 지웠다고 해서 c++데이터에는 지워지는 것이 아니기 때문에 c++단에서 데이터를
삭제 하도록 삭제함수를 호출해 줍니다.
1
|
connectEvent.deleteListItem(i);
|
이렇게 해서 checkbox를 이용해서 삭제하는 코드를 만들어 보았습니다.
그런데 여기서 문제점이 하나 있습니다.
어떠한 문제점이냐 하면 이렇게 삭제를 하고 stackview.pop()을 하면 이전 리스트에서는 삭제된 데이터가 아니라
초기 데이터로 보여집니다.
즉 c++단에서는 데이터가 지워졌지만 qml단에서는 지워지지 않았습니다.
이렇게 된 이유는 main.qml의 총 리스트의 view도 있고 deleteList.qml 의 리스트 view도 있기 때문입니다.
그렇기 때문에 deleteList.qml에서 삭제를 한 후에 뒤로가기해서 sync가 맞으려면 삭제를 했다고 이전 화면에
알려주어야 합니다.
이렇게 해야 이전 화면에서 리스트가 업데이트가 되기 때문입니다.
그래서 다음 화면에서 이전화면에 신호를 주는 방법은 다음 포스팅에서 구현해 보도록 하겠습니다.
여기까지 읽어주셔서 감사합니다.!!
'QT and QML' 카테고리의 다른 글
[C++,QT/Qml]22.Qml프로그래밍 리스트 스크롤바 만들기1(qml scrollbar 사용하기) (0) | 2019.09.08 |
---|---|
[C++,QT/Qml]21.Qml프로그래밍 동적 리스트 만들기7(체크박스 리스트 삭제) (0) | 2019.09.08 |
[C++,QT/Qml]19.Qml프로그래밍 동적 리스트 만들기5(리스트 삭제기능,listview Delete) (2) | 2019.08.17 |
[C++,QT/Qml]18.Qml프로그래밍 동적 리스트 만들기4(dynamic ListView 클릭이벤트 주기) (4) | 2019.08.10 |
[C++,QT/Qml]17.Qml프로그래밍 동적 리스트 만들기3(dynamic ListView) (11) | 2019.08.01 |