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: 407
Registered: ‎04-04-2012
My Device: BlackBerry Z30/Z10/Z10LE/Q10/PlayBook

Re: Progress Indicator updated from Class

Well nothing is displayed to the screen until the progress of reading the contacts is finished.

Retired
Posts: 749
Registered: ‎12-16-2008
My Device: BlackBerry Z30
My Carrier: Bell

Re: Progress Indicator updated from Class

Does the UI still respond though? Can you bring in the application menu and such?

 

Either way, the contacts stuff should be accessed on it's own thread, since it takes time to do.

Paul Bernhardt
Application Development Consultant
BlackBerry
@PBernhardt

Did this answer your question? Please accept this post as the solution.
Found a bug? Report it to the Developer Issue Tracker
Highlighted
Developer
Posts: 407
Registered: ‎04-04-2012
My Device: BlackBerry Z30/Z10/Z10LE/Q10/PlayBook

Re: Progress Indicator updated from Class

The process is inside the application menu so I can't tell for my main app Smiley Wink

 

I would love to do the contact stuff in it's own thread, but that is what I am having problems getting my head wrapped around it.

 

I suspect that this isn't a simple progress otherwise someone could have helped me out by now. Just wish there was an example from Blackberry.

Retired
Posts: 749
Registered: ‎12-16-2008
My Device: BlackBerry Z30
My Carrier: Bell

Re: Progress Indicator updated from Class

Well, you shouldn't really put a progress indicator in the application menu, that's more for buttons Smiley Tongue

 

I'm not sure if we have an actual sample app lying around that shows you how to do this, but let me see if I can walk you through it at a high level.

 

You have some sort of loop that goes through the contacts, pulling contacts out of the contact service and doing something with them, yes? Take that code and put it into it's own class, in a slot. The example in the KB article I linked to creates a "progress" slot. In there, you do your work, and then fire off your signals like finished, error, or whatever you signal you come up with to notify the UI to change something to "Now on contact X of Y", or where you are on your progress indicator, or what have you.

 

Then, when it's time to start going through the contacts, you basically use this block of code:

 

// Create a thread
QThread* thread = new QThread;
Worker* worker = new Worker();

// Give QThread ownership of Worker Object
worker->moveToThread(thread);

// Connect worker error signal to this errorHandler SLOT.
connect(worker, SIGNAL(error(QString)), this, SLOT(errorHandler(QString)));

// Connects the thread’s started() signal to the process() slot in the worker, causing it to start.
connect(thread, SIGNAL(started()), worker, SLOT(process()));

// Connect worker finished signal to trigger thread quit, then delete.
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));

// Make sure the thread object is deleted after execution has finished.
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

thread->start();

 All you need to add is some more connections before thread->start() that hook things like the finished signal or your update signal to your UI. If you've exposed the object that is kicking off the thread to QML, you can do something like this:

 

	connect(thread, SIGNAL(finished()), this, SIGNAL(updateComplete()));
	connect(thread, SIGNAL(updated(QString)), this, SIGNAL(updated(QString)));

 

Then you have a slot handling those singnals in QML that do whever you wanted to.

 

Does that help?

 

 

 

Paul Bernhardt
Application Development Consultant
BlackBerry
@PBernhardt

Did this answer your question? Please accept this post as the solution.
Found a bug? Report it to the Developer Issue Tracker
Developer
Posts: 407
Registered: ‎04-04-2012
My Device: BlackBerry Z30/Z10/Z10LE/Q10/PlayBook

Re: Progress Indicator updated from Class

[ Edited ]

Paul,

 

  Thanks for helping. Hopefully someone else can benefit from my inability to figure this out on my own.

 

  Here is what I have.

 

ContactWorker.hpp

 

#ifndef CONTACTWORKER_HPP_
#define CONTACTWORKER_HPP_

#include <QtCore/QObject>

#include <bb/pim/contacts/ContactService>
#include <bb/pim/contacts/Contact>
#include <bb/pim/contacts/ContactListFilters>

class ContactWorker : public QObject
{
  Q_OBJECT

public:

  ContactWorker();
  virtual ~ContactWorker();

public slots:
	// Read through the contacts using the Contact Service
	void process();

signals:
	void initialized(float toValue);
	void updated(float value);
	void finished();

private:

	// The central object to access the contacts service
    bb::pim::contacts::ContactService* m_contactService;

};

#endif // CONTACTWORKER_HPP_

 ContactWorker.cpp

 

#include "ContactWorker.hpp"

using namespace bb::pim::contacts;

ContactWorker::ContactWorker()
	:  m_contactService(new ContactService(this))
{

}

ContactWorker::~ContactWorker()
{

}

void ContactWorker::process()
{
	QList<Contact> contacts;
	ContactListFilters filter;

	filter.setLimit(0);

	// Tell the UI the ProgressIndicator toValue
	emit initialized(m_contactService->count(filter));

    const int maxLimit = 5;
	filter.setLimit(maxLimit);
	do
	{
		contacts = m_contactService->contacts(filter);
		foreach (const Contact &contact, contacts) {

			// Tell the UI to increment the ProcessIndicator value by maxLimit
			emit updated(maxLimit);

			const Contact contactDetails = m_contactService->contactDetails(contact.id());
			const QList<ContactAttribute> emails = contactDetails.emails();
			if (!emails.isEmpty()) {
			  	foreach(const ContactAttribute &email, emails) {
} } } if (contacts.size() == maxLimit) { filter.setAnchorId(contacts[maxLimit-1].id()); } else { break; } } while (true); // Tell the UI that the processing is done. emit finished(); }

 Does this look right?

Developer
Posts: 407
Registered: ‎04-04-2012
My Device: BlackBerry Z30/Z10/Z10LE/Q10/PlayBook

Re: Progress Indicator updated from Class

I am almost there. It looks like everything is working behind the scene, but I am still not getting the information passed by the signals in the thread back the UI.

 

QML

 

import bb.cascades 1.0
import com.example.addressbook 1.0

Page {
    Container {
        Label {
            id: searchLabel
            text: "Search Contacts"
            horizontalAlignment: HorizontalAlignment.Center
        }
        ProgressIndicator {
            id: progressIndicator
            horizontalAlignment: HorizontalAlignment.Center
            fromValue: 0.0
        }
        ListView {
            dataModel: addressBook.model
            listItemComponents: ListItemComponent {
                type: "item"
                StandardListItem {
                    title: qsTr("%1, %2").arg(ListItemData.lastName).arg(ListItemData.firstName)
                }
            }
        }
    }

    onCreationCompleted: {
        timer.start();
    }

    attachedObjects: [
        QTimer {
            id: timer
            interval: 0
            onTimeout: {
                timer.stop();
                addressBook.search();
            }
        },
        AddressBook {
            id: addressBook
            onInitialized: {
                searchLabel.text = toValue;
                progressIndicator.toValue = toValue;
            }
            onUpdated: {
                progressIndicator.value += value;
            }        }
    ]
}

 

AddressBook.hpp

 

#include <QtCore/QObject>

#include <bb/cascades/GroupDataModel>
#include <bb/pim/contacts/ContactService>
#include <bb/pim/contacts/Contact>
#include <bb/pim/contacts/ContactListFilters>

class AddressBook : public QObject
{
    Q_OBJECT

    // The model that provides the filtered list of contacts
    Q_PROPERTY(bb::cascades::GroupDataModel *model READ model CONSTANT);

public:

    AddressBook(QObject *parent = 0);
    virtual ~AddressBook();

Q_INVOKABLE void search();

signals:
	void initialized(float toValue);
	void updated(float value);
	void finished();

private:

    // The accessor methods of the properties
    bb::cascades::GroupDataModel* model() const;

    // The property values
    bb::cascades::GroupDataModel* m_model;

    // Logging
	void log(const QString &msg);

};

#endif // AddressBook_HPP_

 AddressBook.cpp

 

#include "AddressBook.hpp"
#include "ContactWorker.hpp"

#include <iostream>

using namespace bb::cascades;
using namespace bb::pim::contacts;

AddressBook::AddressBook(QObject *parent)
    : QObject(parent)
    , m_model(new GroupDataModel(this))
{
    // Disable grouping in data model
    m_model->setGrouping(ItemGrouping::None);
}

AddressBook::~AddressBook()
{

}

bb::cascades::GroupDataModel* AddressBook::model() const
{
    return m_model;
}

void AddressBook::search()
{
	log("search contacts");

	// Create a thread
	QThread* thread = new QThread;
	ContactWorker* contactWorker = new ContactWorker();

	// Give QThread ownership of Worker Object
	contactWorker->moveToThread(thread);

	// Connects the thread’s started() signal to the process() slot in the worker, causing it to start.
	connect(thread, SIGNAL(started()), contactWorker, SLOT(process()));

	// Connect worker finished signal to trigger thread quit, then delete.
	connect(contactWorker, SIGNAL(finished()), thread, SLOT(quit()));
	connect(contactWorker, SIGNAL(finished()), contactWorker, SLOT(deleteLater()));

	// Make sure the thread object is deleted after execution has finished.
	connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

	// Connect the current class to the UI
	connect(thread, SIGNAL(initialized(float)), this, SIGNAL(initialized(float)));
	connect(thread, SIGNAL(updated(float)), this, SIGNAL(updated(float)));
	// Start the Thread
	thread->start();
}

void AddressBook::log(const QString &msg) {
	std::cout << msg.toStdString() << std::endl;
}

 

Retired
Posts: 749
Registered: ‎12-16-2008
My Device: BlackBerry Z30
My Carrier: Bell

Re: Progress Indicator updated from Class

Hmmm... Maybe try sprinkling some more logging statements around to see what's happening in the code. What's the QTimer for? Why not call AddressBook.start() directly?

Paul Bernhardt
Application Development Consultant
BlackBerry
@PBernhardt

Did this answer your question? Please accept this post as the solution.
Found a bug? Report it to the Developer Issue Tracker
Developer
Posts: 407
Registered: ‎04-04-2012
My Device: BlackBerry Z30/Z10/Z10LE/Q10/PlayBook

Re: Progress Indicator updated from Class

I put the QTimer in there because if you don't with the problems for the UI, the screen stays black for a while. At least this way, the screen is displayed while you wait for the task to finish.

Retired
Posts: 749
Registered: ‎12-16-2008
My Device: BlackBerry Z30
My Carrier: Bell

Re: Progress Indicator updated from Class

Is it still doing that even with the ContactWorker threading? That should be what keeps things moving.

Paul Bernhardt
Application Development Consultant
BlackBerry
@PBernhardt

Did this answer your question? Please accept this post as the solution.
Found a bug? Report it to the Developer Issue Tracker
Developer
Posts: 407
Registered: ‎04-04-2012
My Device: BlackBerry Z30/Z10/Z10LE/Q10/PlayBook

Re: Progress Indicator updated from Class

Yes. The code I posted on Friday with the worker, still doesn't display anything until the search is completed. No updates during the search are transferred to the UI.