QT and QML

[C++,QT/Qml]21.Qml프로그래밍 동적 리스트 만들기7(체크박스 리스트 삭제)

뼈민 2019. 9. 8. 15:46
반응형

 

[C++,QT/Qml]21.Qml프로그래밍 동적 리스트 만들기7(체크박스 리스트 삭제)

 

 

 

안녕하세요 고급 개발자가 꿈인 코린이 입니다.

 

지난시간에 이어서 체크박스 리스트에서 삭제하는 내용을 더해서 설명하겠습니다.

 

qml에서 리스트를 만드는 포스팅이 엄청 길어졌네요 막상 준비해서 글을 올리다보니 설명드려야 할것도 많고 

 

아직도 내용이 많이 남았는데 ㅎㅎ 리스트구현하는게 작은게 아닌것 같아요 ㅎㅎ

 

암튼 오늘은 지난시간에 말씀 드렸던 리스트 삭제 후 stackview.pop을 하면 메인화면은 리스트가 업데이트 되지않아서

 

리스트가 그대로인데 이 메인화면의 리스트를 업데이트 하도록 시그널을 주는 내용을 다루어 보겠습니다.

 

일단 동영상을 먼저 보겠습니다. 

 

지난 포스팅에서 구현한 내용에 back버튼을 추가해서 리스트 삭제후 back을 해보겠습니다.

 

 

 

이전에 포스팅한 코드로 돌려보시면 위처럼 첫번째 화면의 리스트가 삭제가 되지 않습니다.

 

그 이유는 2번째 화면의 리스트를 업데이트 했지만 첫번째 화면의 리스트가 갱신이 안되었기 때문이죠 

 

그래서 삭제를 한 후에 1번째 화면에 리스트가 갱신이 되었다는것을 알려주어야 합니다.

 

그래서 아래와 같이 코드를 작성하시면 됩니다.

 

아래 코드를 보겠습니다.

 

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
108
109
110
111
112
113
114
115
116
117
118
import QtQuick 2.9
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
import ConnectEvent 1.0//등록한 클래스 타입을 import해준다.
import "."
 
Window {
    id:mainWindow
    property bool mbImageClicked : true
    property int mCount : 0
    property int mListClickIndex : 0//클릭한 리스트의 index를 담는 전역 변수
 
    signal qmlSignalListUpdate();//리스트가 업데이트되었다는 것을 알려주기 위한 시그널 등록
 
    visibletrue
    width800
    height600
    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에 선언한 임의의 모델 안에 데이터를 넣어준다.
        }
 
    }
    onQmlSignalListUpdate:{//시그널이 호출되면 실행하는 함수
        console.log("onQmlSignalListUpdate called")
        listView.model.clear();//리스트 초기화
        for(var i = 0; i < connectEvent.getListSize(); i++){//리스트 초기화 후 다시 넣어줌
            listView.model.append({"list_text": connectEvent.getListTitle(i),
                                      "list_button_text": connectEvent.getListButtonText(i)})
        }
    }
 
    Component {//리스트 뷰의 틀을 만든다.
        id: contactDelegate
        Item {
            width800
            height100
            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
 

deleteList.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
119
120
121
122
123
124
125
126
127
128
129
130
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
import ConnectEvent 1.0//등록한 클래스 타입을 import해준다.
Item {
    width800
    height600    
 
    Component.onCompleted://view가 처음 실행될때 제일 처음으로 불려지는곳
    {
        console.log("connectEvent.getListSize():" + connectEvent.getListSize())
        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 {
            width800
            height100
            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);
                }
            }
            mainWindow.qmlSignalListUpdate();//삭제 완료후 리스트가 업데이트 되었다는 것을 알려주기 위해 시그널을 호출 해준
        }
    }
    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
                }
 
            }
        }
    }
    Button
    {
        id:backbutton
        width:200
        height:50;
        anchors.top: listView.bottom
        anchors.topMargin: 30
        anchors.right: deleteButton.left
        anchors.rightMargin: 20
        text:"back"
        onClicked: {
            stackView.pop();
        }
    }
}
 
 
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
 

 

 

먼저 메인 윈도우에 시그널 하나를 추가합니다. 이 시그널을 리스트가 삭제되었을때 삭제 되었다는것을 알려주기 위한

 

시그널 입니다.

 

1
2
signal qmlSignalListUpdate();//리스트가 업데이트되었다는 것을 알려주기 위한 시그널 등록
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
 

그리고 시그널이 발생되었을때 실행할 함수를 작성 합니다.

 

이 시그널이 발생되면 메인화면의 리스트가 초기화 되고 다시 리스트를 그리게 수정 해줍니다.

 

1
2
3
4
5
6
7
8
onQmlSignalListUpdate:{//시그널이 호출되면 실행하는 함수
        console.log("onQmlSignalListUpdate called")
        listView.model.clear();//리스트 초기화
        for(var i = 0; i < connectEvent.getListSize(); i++){//리스트 초기화 후 다시 넣어줌
            listView.model.append({"list_text": connectEvent.getListTitle(i),
                                      "list_button_text": connectEvent.getListButtonText(i)})
        }
    }
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
 

여기서 onQmlSignalListUpdate 함수란 qml에서는 시그널을 등록하면 그 이름에 on을 붙혀서 시그널이 발생 되었을때의

 

함수를 만들어 줄수 있습니다. 그래서 onQmlSignalListUpdate 함수를 작성한 것 입니다.

 

여기에 리스트를 초기화 하고 리스트를 다시 넣어주는 코드를 넣어서 삭제된 리스트가 업데이트되도록 코드를 작성해

 

줍니다.

 

그리고 이 시그널을 발생시키고 싶은 위치에 시그널을 발생시키도록 코드를 작성해 줍니다.

 

저는 리스트 삭제요청했을때 앞의 리스트가 삭제되도록 하겠습니다.

(삭제를 시킬때마다 리스트가 업데이트 되면 쓸데없이 함수를 계속 호출할수 있으니 안좋은 방법이나 화면이 이전화면으로 갔을때 호출시키는 함수를 아직 언급하지 않아서 삭제버튼에 작성을 하였습니다. 양해해 주시면 감사하겠습니다.)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);
                }
            }
            mainWindow.qmlSignalListUpdate();//삭제 완료후 리스트가 업데이트 되었다는 것을 알려주기 위해 시그널을 호출 해준
        }
    }
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

위의 코드처럼 리스트를 삭제 요청해서 삭제할때 메인화면의 리스트가 업데이트 되도록 시그널을 호출해 줍니다.

 

이렇게 되면 리스트가 삭제되었을때 메인화면의 리스트가 업데이트 되는 것을 구현 할수 있습니다.

 

네 여기까지 체크박스 리스트에 대한 내용을 다루어 봤는데요 

 

다음 시간에는 리스트의 스크롤 바를 만드는 것을 다루어 보겠습니다.

 

리스트의 스크롤바는 qt에서 지원하는 스크롤 바가 있고 프로그래머가 임의로 만드는 custom스크롤 바가 있는데

 

qt에서 지원하는 스크롤 바를 먼저 구현한 후 custom스크롤 바를 구현해서 포스팅 하겠습니다.

 

여기 까지 읽어주셔서 감사합니다!!

 

 

반응형