Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Developer
Posts: 139
Registered: ‎05-24-2011
My Device: Z30 running 10.2 and Playbook 4GLTE running OS2.1
My Carrier: rogers
Accepted Solution

updating a QML DropDown from C++ fails the first time

hey gang,

 

I have a function in my C++ class that looks for a couple of drop downs by objectName and adds Options to them.

 

the function works fine -- with the exception that when the app first starts, the function can't find the DropDown, so the DropDown is empty.  At various points in the execution of the app, it refreshes the DropDown and those all work great.  Its only on the first attempt when the app first starts that it fails.

 

here's the function: 

 

void WorkManager::updateDropDown() {
//	qWarning() << "WorkManager::updateDropDown(), running..";
/*
 * this function updates the two drop down lists in the UI
 * it updates them dynamically with the taskName() ('label') of the job.
 * NOTE: for some reason, this doesn't find the dropdown's by name on first start.  however subsequent runs work fine.
 */
	int i = 0;
	QList<QObject *>  myObjects = m_model->toListOfObjects();
	DropDown * dpList = bb::cascades::Application::instance()->scene()->findChild<DropDown*>("scriptListDropDown");
	DropDown * logDpList = bb::cascades::Application::instance()->scene()->findChild<DropDown*>("logDropDown");
	if (dpList != 0 && logDpList !=0 ) {
		dpList->removeAll();
		logDpList->removeAll();
		for (i = 0; i < myObjects.size(); i++) {
			Task * myTask = static_cast<Task *> (myObjects[i]);
			myTask->setParent(this);
			dpList->add(Option::create().text(myTask->taskLabel()).value(myTask->command()));
			logDpList->add(Option::create().text(myTask->taskLabel()).value(myTask->taskName() + ".log"));
		}
	} else  {
//		qWarning() << "WorkManager::updateDropDown(), ---> dpList was 0, try again";
	}
}

 so when the app starts, i get that qWarning() message, and dpList (and logDpList) are both 0.

 

I've tried scattering calls to this function in various places in both the C++ class, as well as in various onCreationCompleted() signals in the QML UI - like for the main Page, the TabbedPane, the DropDowns.

 

No matter where or when I call it, i can't get the DropDown list to populate on the first try.

 

is there a way to figure out how to get this to work?  it's (quite) a bit annoying.  I would have expected that the onCreationCompleted() for the DropDown would work, but alas, no joy.

 

help?

 

thanks!

 

J

bron: a cron-like scheduler for BlackBerry 10
http://apps.oddelement.com
Developer
Posts: 541
Registered: ‎05-17-2009
My Device: Not Specified

Re: updating a QML DropDown from C++ fails the first time

Quite simply, if the object isn't in the scene's tree, then you won't get a result from findChild. It hasn't been created and/or added to the scene yet.

You say you've done the above in onCreationCompleted of a dropdown, but this would only guarantee that one of your drop down menus has been created and your conditional statement requires both drop down to simultaneously be not null. You need to run the above after both objects are created.

It appears that you can split up the above function to handle dpList and logDpList separately, following the onCreationCompleted signals for each dropdown.

Side note: if you need to run findChild on your entire app's UI, then your app has a serious design flaw.
Developer
Posts: 541
Registered: ‎05-17-2009
My Device: Not Specified

Re: updating a QML DropDown from C++ fails the first time

[ Edited ]

One more note, the drop downs need to have a parent in the app's ui for findChild to locate them. OnCreationCompleted wouldn't guarantee findChild to work unless you knew the dropdown had a parent in the app's UI tree at that point. This is more reason to avoid using massive findChild operations.

Developer
Posts: 139
Registered: ‎05-24-2011
My Device: Z30 running 10.2 and Playbook 4GLTE running OS2.1
My Carrier: rogers

Re: updating a QML DropDown from C++ fails the first time

Hi, thanks for the info.

Is there any best practices I could follow to make this more efficient? I'm still a bit newb around here.

I can easily split out the conditional, but your points about parenting and design flaws have me concerned and curious.

bron: a cron-like scheduler for BlackBerry 10
http://apps.oddelement.com
Developer
Posts: 139
Registered: ‎05-24-2011
My Device: Z30 running 10.2 and Playbook 4GLTE running OS2.1
My Carrier: rogers

Re: updating a QML DropDown from C++ fails the first time

ok, so fix was easy enough.  i was creating the instance of my WorkManager class before creating the AbstractPane and setScene().

 

i moved these two lines so they come before the instantiating of my WorkManager and the setContextProperty().

 

// Create root object for the UI
    AbstractPane *root = qml->createRootObject<AbstractPane>();

    // Set created root object as the application scene
    app->setScene(root);

    // Create a WorkManager
    WorkManager * workManager = new WorkManager(this);
    qml->setContextProperty("workManager", workManager);

 when coded like that (above), the drop down is populated as soon as the app loads.  

 

the way i had it before - which doesn't work - was like this:

 

    // Create a WorkManager
    WorkManager * workManager = new WorkManager(this);
    qml->setContextProperty("workManager", workManager);

// Create root object for the UI
    AbstractPane *root = qml->createRootObject<AbstractPane>();

    // Set created root object as the application scene
    app->setScene(root);

 I'm guessing (and it seems obvious now) that when my custom class is created first, the DropDowns don't exist.  By creating an instance of the custom class *after* the scene is set, they do exist, and everything is groovy.

 

I'm still a bit concerned and curious about why this is a design flaw.  It seems to work well enough, and this is the only place that I "reach across" the QML/C++ divide.  Everyting else is done with slots and invokable methods.  I just couldn't figure out how to create these DropDown Options dynamically any other way.

 

 

bron: a cron-like scheduler for BlackBerry 10
http://apps.oddelement.com
Developer
Posts: 541
Registered: ‎05-17-2009
My Device: Not Specified

Re: updating a QML DropDown from C++ fails the first time

FindChild is slow, tricky to time, and it should always be used as a last resort unless your app is small and you don't care about scaling it.

 

Needing to run findChild on your entire app UI probably means you don't have a tight enough coupling between your QML layer and your C++ layer. For large applications, using a MVC pattern is useful. For every screen I create, there is one view controller written in C++ which has one view (usually) written in QML. Using this relationship handy because a view controller will demand the power of C++ and views are really fast to build in QML. 

 

In the case of your app, at the very least I would instantiate the entire dropdown in C++, populate it with data, and then add it to your UI which I am guessing you made in QML. On your QML side I would make a function that accepts a dropdown as an argument, then add that dropdown to the container. From the C++ side call QMetaObject::invokeMethod on the function. Maintain a reference to the dropdown in your view controller and when you want to update it's data, you don't need to run findChild, it's already in referenced in your controller.