Sunday, November 13, 2011

Cross-Platform UI with Qt Components

Cross-platform UI development doesn't make much sense, if the platform UI paradigms are wildly different. It does however in my case: I develop Nokia Store applications targeting two very similar Nokia platforms: Meego and Symbian.

Both platforms are mobile phones with a touchscreen, and for both, Nokia provides UI toolkits (QML Components), that are similar, but full of maddening small differences. I'm sure these differences will disappear over time. In the meanwhile, I work around them using the Qt resource system.

So the idea is to wrap the platform-specific components into components providing uniform interfaces, and then put the wrappers into platform-specific resource files, with the content aliased to the same location. In my project, I have three resource files: meego.qrc, symbian.qrc, and for the common UI code, common.qrc.

This is how meego.qrc looks like:

<rcc>
 <qresource prefix="/qml">
  <file alias="MainPage.qml">qml/meego/MainWindow.qml</file>
 </qresource>
</rcc>

And this is how symbian.qrc looks like:

<rcc>
 <qresource prefix="/qml">
  <file alias="MainPage.qml">qml/symbian/MainWindow.qml</file>
 </qresource>
</rcc>


Lastly, this is in common.qml:

<rcc>
 <qresource prefix="/">
  <file>qml/main.qml</file>
 </qresource>
</rcc>

MainWindow,qml is implementing the wrapper for the platform-specific application main windows, that can be used from the platform-independent main.qml. To achieve this, both meego/MainWindow.qml and symbian/MainWindow.qml are aliased to the same resource file location (/qml/MainWindow.qml), while they physically reside in different source files (qml/meego/MainPage.qml and qml/symbian/MainPage.qml).

The project file of course only includes meego.qrc when building for Meego, and symbian.qrc when building for Symbian.

Final touches

When editing main.qml in Qt Creator, it won't find MainWindow.qml on the import path (because it doesn't exist in the current directory). To work around this, we should add the sub-directories "meego" and/or "symbian" to the import path. The final main.qml looks like this:

import symbian
import meego
import MainWindow.qml


MainWindow {
    ... (common UI code goes here)
}

Unfortunately, this is still not enough. Qt Creator is now happy, but when running main.qml from the resource file on the target platform, it will complain the directories "meego" and "symbian" do not exist.

This can be resolved by adding some dummy QML files (meego/dummy.qml and symbian/dummy.qml), and including them to the common resource file, which now looks like this:

<rcc>
 <qresource prefix="/">
  <file>qml/main.qml</file>
  <file>qml/meego/Dummy.qml</file>
  <file>qml/symbian/dummy.qml</file>
 </qresource>
</rcc>

Summary

What we have achieved with this somewhat complicated setup is simple: We can now wrap platform-specific QML components with a cross-platform API, and use them from a platform-agnostic UI code.



No comments:

Post a Comment