[C++,QT/Qml]25.Qml프로그래밍 cpp qml 연동4(C++ 에서 qml 함수 호출하기 두번째 방법)
signal slot을 항상 등록해야하기 때문에 코드량도 늘어들고 하기때문에 선언하는 것이 귀찮을때도 많고 번거로울때가
많습니다.
그래서 c++에서 더욱 편하게 qml함수를 호출하는 방법을 없을까 라고 생각하고 찾아본 결과 c++에서도
invoke method를 사용해서 qml함수를 호출할수 있다는 것을 찾을수 있었습니다.
그래서 그 내용을 공유드리기 위해서 이렇게 포스팅을 하게 되었습니다.
아래의 코드를 보겠습니다.
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
42
43
44
45
46
47
48
49
50
51
52
|
#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
Q_ENUMS(WEEK)
public:
ConnectEvent();
~ConnectEvent();
static ConnectEvent &getInstance(); //singleton instance를 만들기 위한 함수
void setWindow(QQuickWindow* Window);
QQuickWindow *getWindow();
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);
Q_INVOKABLE void cppCalledQmlFunction();
private:
int value = 0;
QQuickWindow* mMainView;
vector<TestStruct> mTestList;
QObject *mRootObject = nullptr;
public:// enum 클래스를 사용하기 위해 등록
#include <AllEnum.hpp>//enum값 들을 등록하기 위한 헤더파일
};
Q_DECLARE_METATYPE(ConnectEvent::WEEK)
#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
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
131
132
133
134
135
136
137
138
139
140
|
#include "ConnectEvent.h"
ConnectEvent::ConnectEvent()
{
cout << "ConnectEvent" << endl;
setTestList();//생성자에서 호출해서 객체가 만들어 지자마자 데이터를 vector에 담는다.
qmlRegisterType<ConnectEvent>("ConnectEvent", 1, 0, "ConnectEvent");//class를 qml에서 사용하기 위해서 등록해주는 부분
}
ConnectEvent::~ConnectEvent()
{
}
ConnectEvent &ConnectEvent::getInstance()
{
static ConnectEvent *mpInstance;
if(mpInstance == nullptr){
mpInstance = new ConnectEvent();
}
return *mpInstance;
}
void ConnectEvent::setWindow(QQuickWindow* Window)
{
std::cout << "setWindow called "<<std::endl;
mMainView = Window;//connection을 해주기 위해 윈도우를 등록
}
QQuickWindow *ConnectEvent::getWindow()
{
std::cout << "getWindow called "<<std::endl;
return mMainView;
}
void ConnectEvent::setTestList()
{
std::cout << "setTestList called "<<std::endl;
TestStruct testStruct;
testStruct.title = "Sunday is enum = 0";
testStruct.ButtonText = "Sunday" ;
testStruct.Infomation = "Sunday is hollyday";
mTestList.push_back(testStruct);
testStruct.title = "Monday is enum = 1";
testStruct.ButtonText = "Monday" ;
testStruct.Infomation = "Monday is Work day";
mTestList.push_back(testStruct);
testStruct.title = "Tuesday is enum = 2";
testStruct.ButtonText = "Tuesday" ;
testStruct.Infomation = "Tuesday is Work day";
mTestList.push_back(testStruct);
testStruct.title = "wednesday is enum = 3";
testStruct.ButtonText = "wednesday" ;
testStruct.Infomation = "wednesday is Work day";
mTestList.push_back(testStruct);
testStruct.title = "Thursday is enum = 4";
testStruct.ButtonText = "Thursday" ;
testStruct.Infomation = "Thursday is Work day";
mTestList.push_back(testStruct);
testStruct.title = "Friday is enum = 5";
testStruct.ButtonText = "Friday" ;
testStruct.Infomation = "Friday is Work day";
mTestList.push_back(testStruct);
testStruct.title = "Saturday is enum = 6";
testStruct.ButtonText = "Saturday" ;
testStruct.Infomation = "Saturday is hollyday";
mTestList.push_back(testStruct);
testStruct.title = "test data 7";
testStruct.ButtonText = "test data 7" ;
testStruct.Infomation = "test data 7";
mTestList.push_back(testStruct);
testStruct.title = "test data 8";
testStruct.ButtonText = "test data 8" ;
testStruct.Infomation = "test data 8";
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){
std::cout << "delete count:" << count<<std::endl;
it = mTestList.erase(it);
break;
}else{
count++;
}
}
std::cout << "mTestList.size:" << mTestList.size()<<std::endl;
}
void ConnectEvent::cppCalledQmlFunction(){
std::cout << "cppCalledQmlFunction called :"<<std::endl;
if(mRootObject == nullptr)
mRootObject = qobject_cast<QObject *>(getInstance().getWindow());
QMetaObject::invokeMethod(mRootObject, "qmlSlotFromCpp");
}
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
108
109
110
111
112
113
114
|
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를 담는 전역 변수
property int mCurrentListCount : 0
signal qmlSignalListUpdate();//리스트가 업데이트되었다는 것을 알려주기 위한 시그널 등록
visible: true
width: 800
height: 600
title: qsTr("Hello World")
ConnectEvent//클래스를 qml 타입으로 지정
{
id:connectEvent
}
function qmlSlotFromCpp(){
console.log("qmlSlotFromCpp called");
if(mCurrentListCount !== connectEvent.getListSize()){
listView.model.append({"list_text": connectEvent.getListTitle(mCurrentListCount),//모델에 리스트의 데이터값을 넣어준다.
"list_button_text": connectEvent.getListButtonText(mCurrentListCount)})
mCurrentListCount++;
}
}
Component.onCompleted://view가 처음 실행될때 제일 처음으로 불려지는곳
{
console.log("enum value log:" + ConnectEvent.MONDAY)//qml에서 enum값 로그 찍는 방법
listView.model.append({"list_text": connectEvent.getListTitle(0),//모델에 리스트의 데이터값을 넣어준다.
"list_button_text": connectEvent.getListButtonText(0)})//listview에 선언한 임의의 모델 안에 데이터를 넣어준다.
mCurrentListCount = 1;
}
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를 리턴해준다
connectEvent.cppCalledQmlFunction();
}
}
//버튼 객체를 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
|
위의 코드를 실행 시키면 리스트의 버튼을 클릭할때마다 c++의 invoke method를 호출하고 이 함수에서는
qml의 invoke method를 호출해서 리스트의 총 개수만큼 리스트를 추가하도록 구현한 내용 입니다.
그래서 등록한 리스트가 총 9개 임으로 총 9개의 리스트가 출력외 되도록 구현하였습니다.
위의 코드를 보면 각리스트를 클릭 했을때 ConnectEvent 클래시의 cppCalledQmlFunction이라는 함수를
호출하도록 했습니다.
1
2
3
4
5
6
7
8
9
10
|
MouseArea
{
id:listMouseArea
anchors.fill: parent
onClicked:
{
mListClickIndex = index;//여기에서 사용하는 index는 클릭했을때의 index를 리턴해준다
connectEvent.cppCalledQmlFunction();
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
그리고 이 함수는 아래과 같이 window를 qobject로 타입을 형변환 해줍니다.
그리고 이 object를 이용해서 이 object의 qml함수를 호출하도록 아래와 같이 invokeMethod라는 함수를 호출해서
호출을 하였습니다.
1
2
3
4
5
6
7
8
9
|
void ConnectEvent::cppCalledQmlFunction(){
std::cout << "cppCalledQmlFunction called :"<<std::endl;
if(mRootObject == nullptr)
mRootObject = qobject_cast<QObject *>(getInstance().getWindow());
QMetaObject::invokeMethod(mRootObject, "qmlSlotFromCpp");
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
그리고 qmlSLotFromCpp라는 함수에서 리스트를 한개씩 추가하는 로직을 넣어주면 위의 실행 동영상과 같이
실행이 됩니다.
1
2
3
4
5
6
7
8
9
10
|
function qmlSlotFromCpp(){
console.log("qmlSlotFromCpp called");
if(mCurrentListCount !== connectEvent.getListSize()){
listView.model.append({"list_text": connectEvent.getListTitle(mCurrentListCount),//모델에 리스트의 데이터값을 넣어준다.
"list_button_text": connectEvent.getListButtonText(mCurrentListCount)})
mCurrentListCount++;
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
위와 같이 코딩을 하면 C++에서 qml의 함수를 아주 쉽게 호출을 할수가 있습니다.
구지 signal slot등을 선언을 안해도 함수를 호출 할수 있기때문에 코드 량도 줄어들고
구현하는 시간도 단축이 되게 됩니다.
그렇다면 위와같은 함수를 호출할때 현재는 매개변수가 없는 함수를 호출하였지만 매개변수가 있는 함수를
호출하려면 어떻게 해야할까라는 의문이 들텐데요
이내용은 아래의 코드를 보면서 설명 드리겠습니다.
아래의 코드는 위의 원본 코드에서 함수내용만 살짝 바꾼 코드입니다.
main.qml 의 qmlSlotFromCpp 함수안의 내용을 아래와 같이 바꾸었고
ConnectEvent.cpp 의 qmlSlotFromCpp 함수에서 맨아래 처럼 코드를 바꿔주었습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function qmlSlotFromCpp(stringValue,intValue){
console.log("qmlSlotFromCpp called stringValue:" + stringValue + "intValue:" + intValue);
if(mCurrentListCount !== connectEvent.getListSize()){
listView.model.append({"list_text": connectEvent.getListTitle(mCurrentListCount),//모델에 리스트의 데이터값을 넣어준다.
"list_button_text": connectEvent.getListButtonText(mCurrentListCount)})
mCurrentListCount++;
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
1
2
3
|
QMetaObject::invokeMethod(mRootObject, "qmlSlotFromCpp", Q_ARG(QVariant, "String 매개변수 테스트"),Q_ARG(QVariant, 100));//qml 함수를 호출하는데 string 형 매개변수와 int형 매개변수를 넣어서 호출해주는 부분
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
매개변수를 넣어서 호출하고 싶은때는 위 코드와 같이 Q_ARG 라는 것을 이용해서 string 값이나 int형의 변수나 값들을
qml에서 읽을수 있는 변수인 QVariant로 변환 해주어서 함수를 호출해 주면 됩니다.
원본 코드인 qmlSlotFromCpp에서 위와같이 호출을 하면 qmlSlotFromCpp 힘수가 호출되고 이 함수에서 로그를
찍어 보면 위의 이미지 처럼 로그가 찍히는 것을 볼수 있습니다.
여기까지 cpp에서 qml함수를 호출하는 2번째 방법을 설명 드렸는데요 여태까지 설명드린 qml ->cpp함수 호출
cpp -> qml 함수 호출등을 보시고 구현하실때 가장 편한 방법을 사용해주시면 될것 같습니다.
여기 까지 읽어주셔서 감사합니다.!!
cpp qml 연동
[C++,QT/Qml]12.Qml프로그래밍 cpp qml 연동1(c++에서 qml 함수 호출하기)
[C++,QT/Qml]13.Qml프로그래밍 cpp qml 연동2(qml 에서 C++ 함수 호출하기)
'QT and QML' 카테고리의 다른 글
[C++,QT/Qml]27.Qml프로그래밍 버튼이 있는 팝업 출력하기 2(팝업 영역이 아닌 부분 gray 처리하기) (0) | 2019.10.20 |
---|---|
[C++,QT/Qml]26.Qml프로그래밍 버튼이 있는 팝업 출력하기 1(팝업 영역이 아닌 부분을 클릭시 팝업 닫기) (0) | 2019.10.13 |
[C++,QT/Qml]24.Qml프로그래밍 qml 에서 Enum값 사용하기 (0) | 2019.09.29 |
[C++,QT/Qml]23.Qml프로그래밍 리스트 스크롤바 만들기2(custom scrollbar 만들기) (0) | 2019.09.22 |
[C++,QT/Qml]22.Qml프로그래밍 리스트 스크롤바 만들기1(qml scrollbar 사용하기) (0) | 2019.09.08 |