QML function from child Tab c++ call

Well, that’s a mouth full of a title.  It means, that I am going to share how I called a JavaScript function in my main QML page from a Tab that called a c++ function.  Okay…still need to break it down even further.

I am creating an application that uses OAuth 2.0 to get and send data.  If the application hasn’t already stored the access tokens, I need for the user to give the application access.  When the authentication is complete, I need to remove the Login Tab and make the other Tabs enabled.  Since the authentication function has to wait for a return and then it handles that return in a separate function, I can’t simply point a button on the QML to the c++ function and wait for a response.  What needs to happen is that a function on the main QML page is given “signal” to start when the return function is complete.

Simple Flow: press authentication button -> get form -> submit form -> get access token -> send access token -> get authentication token -> signal main function -> close login tab

The key here is using a “signal” to kick of the QML function.  But, the trick is that QML’s don’t have signals.  What you have to do is create a signal on the c++ page and map that to the QML function, so when the c++ signal is activated, it activates the QML function.

Here is an example of a QML function, which is basically a JavaScript function.

onActionDone() {   // do some action}

Simple enough.  And here is what you need for creating a signal on the .cpp page.

signal:   void actionDoneSignal();

Again, pretty simple.  And here is how you connect the two on the QML page.

mycpp.actionDoneSignal(onActionDone);

Very simple.  Now, the “mycpp” part is handled by registering the cpp class on the main.cpp;

qmlRegisterType<MyCPP>("MyCPP", 1, 0, "MyCPP");

And then importing the class and attaching it on the QML page.  I found this much easier than creating an abstract object and then calling it.  There might be a few more lines of code, but the IDE seems to like it better.

import MyCPP 1.0
attachedObjects: [
	MyCPP{
		id: mycpp
	}
]

That would be it, if I was doing this from the main QML page, but I’m not.  On my main QML page I have a TabbedPane  and I need for that main page to run the function that I call from one of it’s tabs.  Therefor, you need to make sure you can call the TabbedPane from the Tabs.  You do this by setting what I consider to be a global QML variable.  The best time to set it is when the main page has completed loading.

onCreationCompleted: {
	Qt.mainTab = mainTab;
}

Now, I can call the JavaScript function from the Tab after the signal is triggered by setting the connection on the Tab to connect to the function on the main QML.

mycpp.actionDoneSignal(Qt.mainTab.onActionDone);

I am setting the connection on the child Tab, because in this case, I want to make sure the connection happens after the other steps have completed.

This took me a while to figure out, but now I can use this method for other data sends and requests.

main.qml

import AuthServices 1.0
TabbedPane {
	id: mainTab
	objectName: "mainTab"
	showTabsOnActionBar: true
		Tab {
			id: loginTab
			objectName: "loginTab"
			title: qsTr("Login") + Retranslate.onLocaleOrLanguageChanged
			description: "Application Authentication"
			LoginPage { }
		}

		//Tab 1...2...3..

	onCreationCompleted: {
		Qt.mainTab = mainTab;
	}
	onActionDone() {
		// do some action
	}
}

LoginPage.qml

import MyCPP 1.0

Page {
	Container {
			Button {
				id: btnGeAuthenticate
				text: "Get OAuth Access"
				onClicked: {
				startOAuth();
			}
		}
		function startOAuth() {
		// actually last part of step
		mycpp.getAccess(accessURL, consumerKey, consumerSecret, returnCode, redirectURI, "authorization_code")
		mycpp.actionDoneSignal(Qt.mainTab.onActionDone);
	}
	attachedObjects: [
		MyCPP{
			id: mycpp
		}
	]
}

main.cpp

qmlRegisterType<MyCPP>("MyCPP", 1, 0, "MyCPP");

MyCpp.hpp

class MyCpp: public QObject
{
	Q_OBJECT
	public:
		AuthServices();
		virtual ~AuthServices() { }
	Q_SIGNALS:

	public Q_SLOTS:
		void getAccess(const QString &urlString, const QString &consumerKey, const QString &consumerSecret, const QString &code, const QString &redirectURI, const QString &grantType);

	private slots:
		void onGetReply();
	private:

	signals:
		void authenicationDone();
};

MyCpp.cpp


void MyCpp::getAccess(const QString &urlString, const QString &consumerKey, const QString &consumerSecret, const QString &code, const QString &redirectURI, const QString &grantType)
{
 // send request
}

void MyCpp::onGetReply()
{
 // handle request reply
 // emit
 emit actionDone();
}

About DeanLogic
Dean has been playing around with programming ever since his family got an IBM PC back in the early 80's. Things have changed since BASICA and Dean has dabbled in HTML, JavaScript, Action Script, Flex, Flash, PHP, C#, C++, J2ME and SQL. On this site Dean likes to share his adventures in coding. And since programming isn't enough of a time killer, Dean has also picked up the hobby of short film creation.

About DeanLogic

Dean has been playing around with programming ever since his family got an IBM PC back in the early 80's. Things have changed since BASICA and Dean has dabbled in HTML, JavaScript, Action Script, Flex, Flash, PHP, C#, C++, J2ME and SQL. On this site Dean likes to share his adventures in coding. And since programming isn't enough of a time killer, Dean has also picked up the hobby of short film creation.