[C++,QT/Qml]40.Qml프로그래밍 cpp qml 연동4(c++ 에서 qml 함수 호출하기)
안녕하세요 고급 개발자가 꿈인 코린이 입니다. 오늘은 qml과 cpp 연동하는 방법중 4번째 방법에 대해서
다루어 보겠습니다.
이전에 다루었던 cpp qml에서의 연동내용은 cpp에서 시그널을 등록한후에 이 등혹한 시그널에 slot을 불러주는
방식이었습니다.(아래의 urI)
https://youonlyliveonce1.tistory.com/23
하지만 오늘은 시그널과 슬롯을 연결하지 않는 qml 에서 c++ 함수 호출과 같은 invokemethod를 호출하는 방식으로
cpp함수에서 qml 함수를 호출해 보겠습니다.
invokemethod에 관한 내용은 아래 uri의 qt 사이트에 잘 설명이 되어있으니 참고해 주시면 될것 같습니다.
https://doc.qt.io/qt-5/qmetaobject.html
cpp 에서 qml 함수를 호출하는 방법은 아래의 코드를 이용해서 설명 드리겠습니다.
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <RegisterCommonapi.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
ConnectEvent::getInstance(); //뷰가 그려지기 전에 객체를 생성해서 필요한 것들을 미리 만들어 준다.
RegisterCommonapi *registerCommonapi = new RegisterCommonapi();
registerCommonapi->start();
//RegisterCommonapi::getInstance().start();
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QObject *root = engine.rootObjects()[0];//qrc:/main.qml를 등록한 엔진의 object값을 가져옴
ConnectEvent::getInstance().setObject(root);
ConnectEvent::getInstance().setWindow(qobject_cast<QQuickWindow *>(root));//qrc:/main.qml를 등록한 엔진의 object값을 window타입으로 변경해준다.
ConnectEvent::getInstance().init();
//event->cppCalledQmlFunction();
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
|
cs |
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
|
#ifndef CONNECTEVENT_H
#define CONNECTEVENT_
#include <QQuickView>
#include <QObject>
#include <iostream>
#include <QMetaObject>
using namespace std;
class ConnectEvent : public QObject//connection을 사용하기 위해 상속 받아야 하는 클래스
{
public:
Q_OBJECT
public:// enum 클래스를 사용하기 위해 등록
#include <AllEnum.hpp>//enum값 들을 등록하기 위한 헤더파일
public:
ConnectEvent();
~ConnectEvent();
void init();
static ConnectEvent &getInstance(); //singleton instance를 만들기 위한 함수
void setWindow(QQuickWindow* Window);
QQuickWindow *getWindow();
void setObject(QObject* object);
QObject* getObject();
void cppCallQmlFunctionArgString(QString stringValue);
void cppCallQmlFunctionArgInt(int intValue);
private:
int value = 0;
QQuickWindow* mMainView;
//vector<TestStruct1> mTestList;
QObject *mRootObject = nullptr;
};
#endif // CONNECTEVENT_H
|
cs |
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"
#include "qdebug.h"
ConnectEvent::ConnectEvent()
{
cout << "ConnectEvent" << endl;
qmlRegisterType<ConnectEvent>("ConnectEvent", 1, 0, "ConnectEvent");//class를 qml에서 사용하기 위해서 등록해주는 부분
}
ConnectEvent::~ConnectEvent()
{
}
void ConnectEvent::init()
{
std::cout <<__FUNCTION__<<std::endl;
cppCallQmlFunctionArgString("call qml function");
cppCallQmlFunctionArgInt(1);
cppCallQmlFunctionArgInt(12);
}
ConnectEvent &ConnectEvent::getInstance()
{
static ConnectEvent *mpInstance;
if(mpInstance == nullptr){
mpInstance = new ConnectEvent();
}
return *mpInstance;
}
void ConnectEvent::setWindow(QQuickWindow* Window)
{
qDebug()<<"aaaa";
cout << "setWindow called "<<std::endl;
mMainView = Window;//connection을 해주기 위해 윈도우를 등록
}
QQuickWindow *ConnectEvent::getWindow()
{
std::cout << "getWindow called "<<std::endl;
return mMainView;
}
void ConnectEvent::setObject(QObject *object)
{
mRootObject = object;//invokemethod의 매개변수에는 rootobject값이 필요하기 때문에 set으로 설정 해준다.
}
QObject *ConnectEvent::getObject()
{
return mRootObject;//rootobject를 리턴해준다.
}
void ConnectEvent::cppCallQmlFunctionArgString(QString stringValue)
{
std::cout << "cppCallQmlFunctionArgString called "<< stringValue.toStdString()<<std::endl;
QMetaObject::invokeMethod(getObject(), "qmlFunctionArgString",Q_ARG(QVariant, stringValue));//string 값을 QVariant 값으로 변환후 qml함수를 호출한다.
}
void ConnectEvent::cppCallQmlFunctionArgInt(int intValue)
{
std::cout << "cppCallQmlFunctionArgInt called "<< intValue<<std::endl;
QMetaObject::invokeMethod(getObject(), "qmlFunctionArgInt",Q_ARG(QVariant, intValue));//int 값을 QVariant 값으로 변환후 qml함수를 호출한다.
}
|
cs |
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 "./"
import "./style" 1.0
Window {
property bool mbImageClicked : true
property int mCount : 0
visible: true
width: 640
height: 480
title: qsTr("Hello World")
function qmlFunctionArgString(stringValue){//cpp 에서 호출할 qml 함수를 정의해 줍니다. 매개변수로 string값을 전달할 함수입니다.
console.log("qmlFunctionArgString stringValue: " + stringValue);
}
function qmlFunctionArgInt(intValue){//cpp 에서 호출할 qml 함수를 정의해 줍니다. 매개변수로 int값을 전달할 함수입니다.
console.log("qmlFunctionArgInt intValue: " + intValue);
}
function qmlSlotCommonapiBroadCastEvent(value){//서버에서 브로드캐스트 함수가 호출되면 cpp시그널이 발생되면서 이 함수가 호출이 된다.
console.log("value: " + value);
if(customPopup.visible){
customPopup.closeCustomTwoButtonPopup()
}
else
customPopup.openCustomTwoButtonPopup("screen2 popup","go screen2","go previous")
}
CustomTwoButtonPopup
{
id:customPopup
onButton1Onclicked: //custom type에서 설정한 signal이 발생되었을때 동작하는 함수(button1Onclicked)
{
stackView.push(Qt.resolvedUrl("qrc:/screen2.qml"))
}
onButton2Onclicked: //custom type에서 설정한 signal이 발생되었을때 동작하는 함수(button2Onclicked)
{
stackView.pop();
}
}
StackView
{
id:stackView
width:parent.width//윈도우의 넓이 만큼
height:350//stackview 높이를 윈도우보다 작게 설정 윈도우의 높이는 480
initialItem: Item //제일 첫화면을 설정하는 것으로 설정을 안하면 되돌아오기가 안된다.
{
Rectangle//배경 색을 지정하는 부분
{
id:background
anchors.fill: parent
color:"red"
}
Text
{
id:testData
anchors.horizontalCenter: parent.horizontalCenter
text:"main screen testData"
font.pixelSize: 30
font.bold: true
}
Text
{
id:testText
anchors.centerIn: parent
text:"main screen"
font.pixelSize: 50
font.bold: true
}
Button
{
anchors.top:testText.bottom
anchors.horizontalCenter: parent.horizontalCenter
text:"open popup"
onClicked:
{
stackView.push(Qt.resolvedUrl("qrc:/screen1.qml"))
}
}
}
}
Button
{
width:200
height:100
anchors.top: stackView.bottom//버튼을 stackview영역 밑에 위치하도록 설정
onClicked: {
if(stackView.index === 0){//stackview가 첫번째 화면일때 아무동작안함
}else {//stackview가 첫번째 화면이 아닐때 stackview pop
stackView.pop();
}
}
}
}
|
cs |
먼저 main.cpp파일을 보겠습니다.
main.cpp 파일의 아래의 코드에서 ConnectEvent 클래스에 object를 설정해 줍니다
1
2
|
QObject *root = engine.rootObjects()[0];//qrc:/main.qml를 등록한 엔진의 object값을 가져옴
ConnectEvent::getInstance().setObject(root);
|
cs |
그리고 main.qml에 cpp파일에서 qml함수를 호출할수 있도록 함수를 선언해 줍니다.
아래와 같이 string 값을 전달할 함수와 int형 값을 전달할 함수를 따로 지정해서 구현 하였습니다.
1
2
3
4
5
6
7
|
function qmlFunctionArgString(stringValue){//cpp 에서 호출할 qml 함수를 정의해 줍니다. 매개변수로 string값을 전달할 함수입니다.
console.log("qmlFunctionArgString stringValue: " + stringValue);
}
function qmlFunctionArgInt(intValue){//cpp 에서 호출할 qml 함수를 정의해 줍니다. 매개변수로 int값을 전달할 함수입니다.
console.log("qmlFunctionArgInt intValue: " + intValue);
}
|
cs |
그리고 호출하고 싶은 위치에서 호출할 qml 함수를 호출해 줍니다.
호출하는 방법은 아래와 같이 호출하시면 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
void ConnectEvent::cppCallQmlFunctionArgString(QString stringValue)
{
std::cout << "cppCallQmlFunctionArgString called "<< stringValue.toStdString()<<std::endl;
QMetaObject::invokeMethod(getObject(), "qmlFunctionArgString",Q_ARG(QVariant, stringValue));//string 값을 QVariant 값으로 변환후 qml함수를 호출한다.
}
void ConnectEvent::cppCallQmlFunctionArgInt(int intValue)
{
std::cout << "cppCallQmlFunctionArgInt called "<< intValue<<std::endl;
QMetaObject::invokeMethod(getObject(), "qmlFunctionArgInt",Q_ARG(QVariant, intValue));//int 값을 QVariant 값으로 변환후 qml함수를 호출한다.
}
|
cs |
위의 함수에 맞는 매개변수를 넣어서 호출을 해주면 Q_ARG라는 매크로를 통해서 QVariant값으로 변환해주고
이 값을 각 연결된 qml함수에 전달해주고 qml 함수에서 받은 값을 로그로 출력해주면 값이 잘들어 온것을
알수가 있습니다.
여기 까지 cpp 와 qml의 연동하는 4번째 방법에 대한 내용입니다.
여기 까지 읽어주셔서 감사합니다.!