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
New Developer
dban
Posts: 19
Registered: ‎02-24-2012
My Device: Developer
My Carrier: -

"How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac

[ Edited ]

Hi,

 

Some days ago I've started looking into the different platforms available for BlackBerry. I've played for some days with BlackBerry Java until I realized it will not be available on BBX (or Black Berry 10). I'm not a fan of Adobe AIR or HTML 5 and I don't like the idea of an app runing in a player (Java Android Runtime).

 

So, what is left? C\C++ Native SDK. Great!

 

I've started looking at the existing tutorials and samples for a simple way to create a UI application (buttons, textboxes etc.). My app should be a mix of UI layouts and OpenGL. Cascades UI is not ready yet and the best way to do this seems to be Qt.

 

First step was to integrate Qt in Momentics IDE. After trying different things I've come to this blog (look at the comments also) - http://bgmotey.blogspot.com/ - and after overcoming some small problems I've managed to run my Hello World app on the PlayBook simulator.

 

Next I went to the Qt website and started looking at the "How to learn Qt" ( http://developer.qt.nokia.com/doc/qt-4.8/how-to-learn-qt.html ). One of the first examples to look at is the Calculator ( http://developer.qt.nokia.com/doc/qt-4.8/widgets-calculator.html ). I've created a new project,  I did all the steps I've done for the Hello World application, I've added all the files except calculator.pro and I tried to build the project. But surprise! It failed:

 

qcc -o Calculator src/main.o src/calculator.o src/button.o -lbps -lQtCore -lQtGui -V4.4.2,gcc_ntox86_cpp -w1 -lang-c++ -g -Wl,-z,relro -Wl,-z,now -L/Developer/SDKs/bbndk-2.0.0-beta3/target/qnx6/../target-override/x86/lib -L/Developer/SDKs/bbndk-2.0.0-beta3/target/qnx6/../target-override/x86/usr/lib -L/Users/dban/Documents/Qt/stage/nto/x86/usr/lib/qt4/lib

src/main.o: In function `~Calculator':

/Users/dban/Documents/ndk-2.0.0-workspace/Calculator/Simulator-Debug/../src/calculator.h:50: undefined reference to `vtable for Calculator'

/Users/dban/Documents/ndk-2.0.0-workspace/Calculator/Simulator-Debug/../src/calculator.h:50: undefined reference to `vtable for Calculator'

...

 

Back to documentation...  The problem was Q_OBJECT and the Qt Signals/Slot. The Meta-Object Compiler (moc) was supposed to do some job but it didn't. The solution was to add some custom build steps for the header files. And I did so for button.h and calculator.h by right-clicking the file->Properties->C/C++ Build->Settings and Build Steps. The values used:

  • Custom Build Step Applicability: Apply Custom Build Step Overriding Other Tools
  • Output file name(s): moc_button.cpp
  • Command: moc -o src/moc_button.cpp ../src/button.h

Build again... Failed again:

 

...

src/moc_calculator.o: (.rodata._ZTV10Calculator[_ZTV10Calculator]+0xb0): undefined reference to `QWidget::x11Event(_XEvent*)'

src/moc_button.o: (.rodata._ZTV6Button[_ZTV6Button]+0xb0): undefined reference to `QWidget::x11Event(_XEvent*)'

...

 

I've started looking at the flags and their meaning. First thing that came to my mind was to remove the QT_BOOTSTRAPPED. And the build was successful! Tried to run it on the simulator but I got a message saying "Errors exist in a required project. Continue launch?". What errors? Looking in the console I saw the following:

 

**** Rebuild of configuration Simulator-Debug for project Calculator ****

 

**** Internal Builder is used for build               ****

Build error

null

 

What? I just built the whole shebang 10 seconds ago... So I just continued with the launch. And the calculator was running in the simulator! Hooray!

 

Still, I am not happy. When trying to rebuild the project I get:

 

Errors occurred during the build.

Errors running builder 'CDT Builder' on project 'Calculator'.

java.lang.NullPointerException

 

I have to open project properties and press ok and then the projects rebuilds just fine. Is there another way?

 

Also, removing QT_BOOTSTRAPPED doesn't sound like a good solution. Or does it? Another way to make it compile is to leave the QT_BOOTSTRAPPED and add also Q_WS_QPA. Does this sounds right? It doesn't work with Q_OS_MAC or Q_WS_MAC.

 

I will continue learning Qt until I can create an app with UI layouts and OpenGL scenes combined. I'm thinking that I'm going to make the effort one time and then I can create many application with Qt. But is it worth it? Or is there another way to do it? Will there be an easier way to integrate Qt into Momentics? When? Should I wait for Cascades UI?

 

Any feedback would be appreaciated!

 

Thanks & best regards,

Dumi.

Please use plain text.
Developer
BGmot
Posts: 1,068
Registered: ‎11-24-2011
My Device: PlayBook
My Carrier: x

Re: "How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac

Nice job!

you are correct about moc stuff. We need to find a way to integrate it in NDK but good think you don't have to run moc very ofthen, you need to run it only against new classes that have Q_OBJECT you introduce.

X11 errors - yes I ran into the same issue but only when I was trying to compile/deploy to Simulator. SInce then I gave up on Qt/Simulator as there are too many differences between SImulator and Readl PlayBook. If you want an advice then: don't waste your time trying to make Qt things work on Simulator, use real device.

And lastly as basically there is not documentation on Qt + NDK, learning/writing Qt apps for Playbook is close to reverse engineering. You have to go through Qt libs + Qt blackberry plugin sources to understand things (fortunately they are available!)

Cheers and good luck!

Please share your findings...

Please use plain text.
Contributor
azazello
Posts: 40
Registered: ‎01-15-2012
My Device: Playbook Tablet
My Carrier: MTS

Re: "How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac

may be some useful info can be found via search in this forum

http://supportforums.blackberry.com/t5/Native-SDK-for-BlackBerry-Tablet/Installing-QT-in-the-QNX-IDE...

/rgds
Andrey Yaromenok aka azazello
Please use plain text.
Developer
jheron
Posts: 188
Registered: ‎01-27-2012
My Device: playbook
My Carrier: ...

Re: "How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac

In my opinion, there is no need for the Momentics IDE. I have not bothered to even run it yet.

I would suggest just using the Qt SDK with the built in simulator to develop and test your app. Then you will not have to worry about the moc files etc. as they are all handled by Qt IDE. Then just build and deploy it via the command line to your playbook. (https://bdsc.webapps.blackberry.com/android/downloads/fetch/CommandLineTools.zip) You don't even need a cable, it will deploy to the pb via wifi, even while you kid is playing angry birds on it... :smileywink:

I have heard rumor that debugging on the playbook from the Qt IDE will be supported soon too...

Good luck!

Jon

Please use plain text.
New Developer
dban
Posts: 19
Registered: ‎02-24-2012
My Device: Developer
My Carrier: -

Re: "How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac

[ Edited ]

I was kind of happy with what I've accomplished yesterday. Until I've tried to open Momentics IDE this morning. At that point none of my test projects opened and I got a NPE exception:

 

Could not open the editor: Editor could not be initialized.

 

java.lang.NullPointerException
at org.eclipse.cdt.managedbuilder.internal.core.AdditionalInput.needsRebuild(AdditionalInput.java:336)
at org.eclipse.cdt.managedbuilder.internal.core.InputType.needsRebuild(InputType.java:1619)
at org.eclipse.cdt.managedbuilder.internal.core.Tool.needsRebuild(Tool.java:3307)
at org.eclipse.cdt.managedbuilder.internal.core.ResourceConfiguration.needsRebuild(ResourceConfiguration.java:854)
at org.eclipse.cdt.managedbuilder.internal.core.ResourceConfiguration.setRebuildState(ResourceConfiguration.java:869)
at org.eclipse.cdt.managedbuilder.internal.core.ResourceConfiguration.addTool(ResourceConfiguration.java:495)
at org.eclipse.cdt.managedbuilder.internal.core.ResourceConfiguration.<init>(ResourceConfiguration.java:119)
at org.eclipse.cdt.managedbuilder.internal.core.Configuration.<init>(Configuration.java:419)
at org.eclipse.cdt.managedbuilder.internal.dataprovider.ConfigurationDataProvider.load(ConfigurationDataProvider.java:366)
at org.eclipse.cdt.managedbuilder.internal.dataprovider.ConfigurationDataProvider.loadConfiguration(ConfigurationDataProvider.java:541)
at org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager.loadData(CProjectDescriptionManager.java:1115)
at org.eclipse.cdt.internal.core.settings.model.CConfigurationDescriptionCache.loadData(CConfigurationDescriptionCache.java:95)
at org.eclipse.cdt.internal.core.settings.model.CProjectDescription.loadDatas(CProjectDescription.java:196)
at org.eclipse.cdt.internal.core.settings.model.xml.XmlProjectDescriptionStorage.loadProjectDescription(XmlProjectDescriptionStorage.java:486)
at org.eclipse.cdt.internal.core.settings.model.xml.XmlProjectDescriptionStorage.getProjectDescription(XmlProjectDescriptionStorage.java:231)
at org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager.getProjectDescriptionInternal(CProjectDescriptionManager.java:416)
at org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager.getProjectDescription(CProjectDescriptionManager.java:398)
at org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager.getProjectDescription(CProjectDescriptionManager.java:393)
at org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager.getProjectDescription(CProjectDescriptionManager.java:386)
at org.eclipse.cdt.internal.core.model.CProject.computeSourceRoots(CProject.java:603)
at org.eclipse.cdt.internal.core.model.CProject.computeChildren(CProject.java:624)
at org.eclipse.cdt.internal.core.model.CProject.buildStructure(CProject.java:588)
at org.eclipse.cdt.internal.core.model.Openable.generateInfos(Openable.java:265)
at org.eclipse.cdt.internal.core.model.CElement.openWhenClosed(CElement.java:428)
at org.eclipse.cdt.internal.core.model.CElement.getElementInfo(CElement.java:307)
at org.eclipse.cdt.internal.core.model.CElement.getElementInfo(CElement.java:297)
at org.eclipse.cdt.internal.core.model.Parent.getChildren(Parent.java:55)
at org.eclipse.cdt.internal.core.model.CProject.getSourceRoots(CProject.java:480)
at org.eclipse.cdt.internal.core.model.CModelManager.create(CModelManager.java:327)
at org.eclipse.cdt.core.model.CoreModel.create(CoreModel.java:120)
at org.eclipse.cdt.internal.ui.editor.CDocumentProvider.createTranslationUnit(CDocumentProvider.java:795)
at org.eclipse.cdt.internal.ui.editor.CDocumentProvider.createFileInfo(CDocumentProvider.java:836)
at org.eclipse.ui.editors.text.TextFileDocumentProvider.connect(TextFileDocumentProvider.java:478)
at org.eclipse.cdt.internal.ui.editor.CDocumentProvider.connect(CDocumentProvider.java:779)
at org.eclipse.ui.texteditor.AbstractTextEditor.doSetInput(AbstractTextEditor.java:4213)
at org.eclipse.ui.texteditor.StatusTextEditor.doSetInput(StatusTextEditor.java:237)
at org.eclipse.ui.texteditor.AbstractDecoratedTextEditor.doSetInput(AbstractDecoratedTextEditor.java:1451)
at org.eclipse.ui.editors.text.TextEditor.doSetInput(TextEditor.java:169)
at org.eclipse.cdt.internal.ui.editor.CEditor.internalDoSetInput(CEditor.java:1495)
at org.eclipse.cdt.internal.ui.editor.CEditor.doSetInput(CEditor.java:1458)
at org.eclipse.ui.texteditor.AbstractTextEditor$19.run(AbstractTextEditor.java:3200)
at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalContext.java:464)
at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:372)
at org.eclipse.jface.window.ApplicationWindow$1.run(ApplicationWindow.java:759)
at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
at org.eclipse.jface.window.ApplicationWindow.run(ApplicationWindow.java:756)
at org.eclipse.ui.internal.WorkbenchWindow.run(WorkbenchWindow.java:2642)
at org.eclipse.ui.texteditor.AbstractTextEditor.internalInit(AbstractTextEditor.java:3218)
at org.eclipse.ui.texteditor.AbstractTextEditor.init(AbstractTextEditor.java:3245)
at org.eclipse.ui.internal.EditorManager.createSite(EditorManager.java:828)
at org.eclipse.ui.internal.EditorReference.createPartHelper(EditorReference.java:647)
at org.eclipse.ui.internal.EditorReference.createPart(EditorReference.java:465)
at org.eclipse.ui.internal.WorkbenchPartReference.getPart(WorkbenchPartReference.java:595)
at org.eclipse.ui.internal.EditorAreaHelper.setVisibleEditor(EditorAreaHelper.java:271)
at org.eclipse.ui.internal.EditorManager.setVisibleEditor(EditorManager.java:1459)
at org.eclipse.ui.internal.EditorManager$5.runWithException(EditorManager.java:972)
at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:135)
at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3938)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3615)
at org.eclipse.ui.application.WorkbenchAdvisor.openWindows(WorkbenchAdvisor.java:803)
at org.eclipse.ui.internal.Workbench$33.runWithException(Workbench.java:1595)
at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:135)
at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3938)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3615)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2604)
at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2494)
at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:674)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:667)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:123)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:344)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:622)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:577)
at org.eclipse.equinox.launcher.Main.run(Main.java:1410)

 

I've started looking for a solution but I didn't find one. I had to manually delete all my custom steps from .cproject and add them again after that. The workaround is to enable a custom build step only when you want to moc the corresponding header file and disable it after this.

 

Also, I had to change the values used for custom build steps with something like this:

 

  • Custom Build Step Applicability: Apply Custom Build Step Overriding Other Tools
  • Output file name(s): moc_xxx.cpp
  • Command: moc -o ../src/moc_xxx.cpp ../src/xxx.h

In this way the moc_xxx.cpp file is added to the src folder. You have to refresh the project and after that everything works fine...

 

Dumi.

Please use plain text.
New Developer
dban
Posts: 19
Registered: ‎02-24-2012
My Device: Developer
My Carrier: -

Re: "How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac

Hello again!

 

After finishing with the Calculator Example I decided it's time to try the Application Example ( https://qt-project.org/doc/qt-4.8/mainwindows-application.html ). It is a classic GUI app with menus, toolbars, image resources etc.

 

I've created a new project and did everything the same as for the Calculator. The different thing was a resource file, application.qrc. This one should be picked up by the following line of code:

 

Q_INIT_RESOURCE(application);

 

But for this to happen the qrc file needed to be compiled by the Qt Resource Compiler, rcc. Similar to the moc, right? So I've added a custom build step for the application.qrc:

  • Custom Build Step Applicability: Apply Custom Build Step Overriding Other Tools
  • Output file name(s): application.rcc
  • Command: rcc -o src/application.rcc ../src/application.qrc

Unfortunatelly this custom step did not execute. What changes are needed to force the compilation of .qrc files? My workaround was to rename the application.qrc to application.h and to have it compiled as aresource to application.cpp:

  • Custom Build Step Applicability: Apply Custom Build Step Overriding Other Tools
  • Output file name(s): application.cpp
  • Command: rcc -o src/application.cpp ../src/application.h

This works because the file generated by rcc is a C++ source file containing the data specified in the resource file.

 

And hooray! Here is the Application Example in the simulator:

 

 

 

Dumi.

Please use plain text.
New Developer
dban
Posts: 19
Registered: ‎02-24-2012
My Device: Developer
My Carrier: -

Re: "How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac

[ Edited ]

Back again! And with a serious problem I've been trying to overcome in the last hours. The Application Example saves the size of its window when receiving the close event. Unfortunatelly this happens only when selecting File->Exit. When closing the application in the BlackBerry way the close event is not raised. And that's because that event is the navigator exit event.

 

Still, there is a Qt event that may be used for this purpose - QEvent::ApplicationDeactivate. To have access to this event I have created a new class, MyApplication, that overrides some of the QApplication behaviour:

 

bool Application::event(QEvent *ev) {
	qDebug("%d", ev->type());
	if (ev->type() == QEvent::ApplicationDeactivate) {
		// do something
	}
	return QApplication::event(ev);
}

 

Is this the right way? It might be if you just need this navigator event.

 

But what if you need some other navigator events? Like navigator swipe down, navigator orientation, navigator window active/inactive? How should this be accomplished?

 

First thing that came into my mind was to create another class where to listen for bps navigator events. I've extended QThread and implemented the following:

 

NavigatorEventsThread::NavigatorEventsThread() {
	bps_initialize();
	navigator_request_events(0);

	stopped = false;
}

NavigatorEventsThread::~NavigatorEventsThread() {
	bps_shutdown();
}

void NavigatorEventsThread::run() {
	while (!stopped) {
		int rc, domain;

		bps_event_t *event = NULL;
		rc = bps_get_event(&event, -1);
		assert(rc == BPS_SUCCESS);
		if (event) {
			domain = bps_event_get_domain(event);
			if (domain == navigator_get_domain()) {
				switch (bps_event_get_code(event)) {
				case NAVIGATOR_EXIT:
					emit navigatorCloseEventRaised();
					stopped = true;
					break;
				default:
					break;
				}
			}
		}
	}
}

 

Unfortunatelly this blocks at the bps_get_event line. Why? Because there are no events coming if you don't create a bps screen also :smileysad: Right?

 

Next step was to replace the QApplication event filter with my own:

 

bool myEventFilter(void *message, long *result) {
	return false;
}

int main(int argc, char *argv[]) {
	QCoreApplication::addLibraryPath("app/native/lib");
	Application app(argc, argv);

	app.setEventFilter(myEventFilter);

	...
}

 

But myEventFilter is never called. Why? I'm guessing because the event filter function set here is called for all messages received by all threads meant for all Qt objects. It is not called for messages that are not meant for Qt objects. Or why else?

 

Another way was to replace the event filter function for the QAbstractEventDispatcher:

 

bool myEventFilter(void *message) {
	return false;
}

int main(int argc, char *argv[]) {
	QCoreApplication::addLibraryPath("app/native/lib");
	Application app(argc, argv);


	QAbstractEventDispatcher *aed = QAbstractEventDispatcher::instance(app.thread());
	aed->setEventFilter(myEventFilter);

	...
}

 

This was better. I got myEventFilter called on swipe down and on orientation changes. But not for application getting active/inactive. And also, to what should I cast the void *message in order to see what's actually in the message?

 

Is there another way, a better one, to somehow get the navigator events and add them to the Qt event loop? Or is there another solution for this problem?

 

Thanks & best regards,

Dumi.

 

Please use plain text.
Developer
jheron
Posts: 188
Registered: ‎01-27-2012
My Device: playbook
My Carrier: ...

Re: "How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac

[ Edited ]

[quote]Back again! And with a serious problem I've been trying to overcome in the last hours. The Application Example saves the size of its window when receiving the close event. Unfortunately this happens only when selecting File->Exit. When closing the application in the BlackBerry way the close event is not raised. And that's because that event is the navigator exit event.[/quote]

I have not had a problem with my settings gettign stored using the blackberry close method (dragging up and clicking X). For Qt c++ widget apps I call my settings function from the destructor. For qml apps I call the settings function from the main page in Component.onDestruction: {}.

This works fine, however I believe using the qcloseEvent is the proper method for widget apps.

https://qt-project.org/doc/qt-4.8/qwidget.html#closeEvent

I am just a rookie so perhaps that is not what your looking for! :smileywink:

Cheers,

Jon

Please use plain text.
New Developer
dban
Posts: 19
Registered: ‎02-24-2012
My Device: Developer
My Carrier: -

Re: "How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac


azazello wrote:

may be some useful info can be found via search in this forum

http://supportforums.blackberry.com/t5/Native-SDK-for-BlackBerry-Tablet/Installing-QT-in-the-QNX-IDE...


I've seen that, but this thread is more about problems encountered after managing to integrate Qt in QNX Momentics IDE; it's about creating different applications for PlayBook using Qt. The HelloWorld application represents only the beginning, it's just the tip of the iceberg. The problems are bigger and uglier from here on...

 

Dumi.

Please use plain text.
Developer
BGmot
Posts: 1,068
Registered: ‎11-24-2011
My Device: PlayBook
My Carrier: x

Re: "How to Learn Qt" with Qt integrated in QNX Momentics IDE on Mac

This is how I react to swipedown event. (Mainwindow is a descendant of QMainMindow)

void MainWindow::keyPressEvent(QKeyEvent *event)
{
	if (event->key() == Qt::Key_Menu){
	  ui->widgetMenu->show();
	}
	QMainWindow::keyPressEvent(event);
}

 

Please use plain text.