Qt and Windows CE

To demonstrate how you can use Qt to build a Windows Mobile application, Espen presents an image viewer and internationalizes it for three different languages.


May 23, 2008
URL:http://www.drdobbs.com/mobile/qt-and-windows-ce/208200263

Espen is a senior software engineer for Trolltech. He can be contacted at [email protected].


Qt is a C++ application framework from Trolltech that lets you write native applications that can be compiled cross-platform. This means that the source code only needs to be written once, yet support Linux, Windows CE/98/XP/Vista, Mac OS X, UNIX, and Embedded Linux. To deploy, you simply compile it for your target platform. One well-known application taking advantage of this kind of capability is Google Earth, which is available for Linux, Windows, and Mac OS X. Qt makes it easy for Google to maintain its code base and simultaneously support several platforms.

When it comes to embedded operating systems, Qt is supported by embedded Linux and, with the beta release of Qt 4.4, it supports Windows CE 5.0/6.0, and Windows Mobile 5.0/6.0. In this article, I create native applications for Windows CE using Qt.

Windows CE targets different segments of the embedded marketplace. Windows Mobile, for instance, targets Smartphones and Pocket PCs. Windows Mobile has a specialized UI, and provides lightweight office and communication applications. Nevertheless, it's still Windows CE. Generally speaking, when I refer to Windows CE, I include Windows Mobile and any other Windows CE flavor that supports the Windows CE Standard SDK 5.0 (or later).

An Image Viewer Example

To demonstrate how you can use Qt, I present an image viewer called "Qt Image Viewer" (Figure 1) and internationalize it for three different languages. It has its own custom look-and-feel—and users can change both the language and look-and-feel while the application is running. The complete source code for the application is available www.ddj.com/code/.

Qt comes with a UI builder tool for designing UIs. You can, of course, code the GUI by hand, but you can save time doing it in Qt Designer instead. Qt Designer stores the UI in an XML file, which generates C++ code that you can include in your project. Figure 2 shows the Qt Designer with the .ui file for Image Viewer.

For this application, I use the QLabel, QLineEdit, and QPushButton widgets (controls). I use QLabel for the actual images and for textual information (such as the name of the current image and its dimensions). I use QLineEdit to display the name of the current directory, and QPushButton for user interactions in the application. Giving the widgets sensible names like previousImage, nextButton, and currentDirectory, it is simpler later on when using these widgets in the application code.

Figure 1: Qt Image Viewer with custom style running on Windows Mobile 6.0.

[Click image to view at full size]

Figure 2: Qt Designer loaded with imageviewer.ui.

Once you define the UI, you combine it with the application code. The generated C++ code created from the .ui file in Figure 2 results in a header file called ui_imageviewer.h. To use it, just include it in the code. Here, I subclass a QWidget and initialize the GUI in the constructor:


class PreviewWindow : public QWidget
{
  Q_OBJECT
public:
  PreviewWindow() : QWidget(), current(1) {
    ui.setupUi(this);
   ...
}


The PreviewWindow class has the following members:


Ui::ImageViewer ui;
QStringList imageFileList;
QPixmap mainPixmap;
int current;

UI::ImageViewer ui is an instance of the class generated by Qt Designer. By calling ui.setupUi(this), I initialize my own class (the PreviewWindow class) with the GUI I created in Qt Designer. At this point, I can run the application. While it would look like what I designed in Qt Designer, I also need to connect the widgets with program logic to make the application functional.

When you change one widget in GUI programming, you often want another widget to be notified. Generally, you want objects of any kind to be able to communicate with one another. For example, if users click previousButton, you want PreviewWindow's previousImage() function to be called.

Qt's solution for this is "signals" and "slots" (similar to Delegates/Events in C#):

Qt's widgets have many predefined slots, but it is common practice to subclass widgets and add your own slots so that you can handle the signals you're interested in. For the PreviewWindow class, I've added these slots:


void nextImage() { ... }
void previousImage() { ... }
void changeDirectory() { ... }
void toggleStyleSheet() { ... }
void setTranslator(QObject *object) { ... }


To connect the signals from the different widgets to these slots, you only need to call the connect() function in the constructor of the widget. Here, I connect the clicked() signals from previousButton and nextButton:


// connect next and previous
connect(ui.previousButton,     SIGNAL(clicked()), 
      this, SLOT(previousImage()));
connect(ui.nextButton,     SIGNAL(clicked()), 
      this, SLOT(nextImage()));


The rest of the constructor code connects the other buttons, scans the current directory for any images, and loads them for preview if any exist.

Customized Look

Qt supports the native look-and-feel of all the platforms it runs on. Windows XP applications look exactly like an XP app should look; the same for Vista, Mac OS X, Linux, UNIX, and CE. For CE, Qt supports both the look of Windows Mobile applications, and the more traditional looking Windows CE apps. However, sometimes it is important to look different, especially for embedded devices where the look-and-feel is part of defining the platform you are creating. Qt has several ways of helping you create a custom look-and-feel for your applications.

For instance, Qt has the ability to style a widget or complete application by using style sheets. Qt Style Sheets let you customize the appearance of widgets. The concepts, terminology, and syntax of Qt Style Sheets are heavily inspired by HTML Cascading Style Sheets (CSS), but adapted to the world of widgets.

In Image Viewer, I use this code to turn on/off customization of the application:


void toggleStyleSheet() {
   QFile file(":/qss/stylesheet.qss");
   file.open(QFile::ReadOnly);
   qApp->setStyleSheet        (qApp->styleSheet().isEmpty() ?
     QLatin1String(file.readAll()) :         QString());
}


By filling the stylesheet.qss file with styling rules like this:


QWidget {
   backgroundcolor:beige;
}
QGroupBox {
   bordercolor: darkkhaki;
   font: bold;
}
QLabel {
   font: bold;
}


you get a different look than the normal one. Figures 3(a) and 3(b) show a noticeable difference.

Internationalizing Applications

Notice that the languages in Figure 3 are also different. Figure 3(a) is Norwegian, while 3(b) is German (Swiss).

To internationalize applications in Qt:

  1. Use QString for all user-visible text. Since QString uses Unicode 4.0 encoding internally, every language in the world can be processed transparently using familiar text-processing operations.
  2. Wherever your program uses "quoted text" for user-visible text, ensure that it is processed by the tr() function.
  3. Run the application lupdate to extract translatable text from the C++ source code of the Qt application.
  4. Use Qt Linguist and translate your extracted text to the languages you want to support.
  5. Run the application lrelease to obtain a lightweight message file suitable for end use.

Step 4 is usually done by a translator (like QT Linguist), while the other steps are done by you.

[Click image to view at full size]

Figure 3: (a) Image Viewer running in Windows Mobile 6.0 with default native style; (b) Image Viewer running in Windows Mobile 6.0 with custom style sheet enabled.

To switch the language you simply call the QCoreApplication::installTranslator() function. When called during the construction of an application, nothing else is needed for the app to run in the selected language. However, to change the language at runtime, you need to reimplement changeEvent() of the PreviewWindow class to handle LanguageChange:


void changeEvent(QEvent *event) {
  if (event->type() ==      QEvent::LanguageChange) {
    ui.retranslateUi(this);
    ui.imageName->setTitle       (imageCount() ?          currentImageName() :            tr("no images found"));
    ui.imageDimension->setText       (QString(tr("Dimensions: %1X%2"))
        .arg(ui.currentImage->pixmap() ?            ui.currentImage->             pixmap()->width() : 0)
      .arg(ui.currentImage->pixmap() ?          ui.currentImage->pixmap()->           height() : 0));
  }
}


You call ui.retranslateUi(this) to translate all the user-visible strings that entered when creating the GUI in Qt Designer. However, you also need to update the widgets that have user-visible strings updated by code. That is why I call setTitle() and setText() for the imageName and imageDimension. Notice how the strings are wrapped inside a tr() function. With this reimplementation of changeEvent(), the application supports changing the language at runtime.

It's Small, Powerful, and Cross Platform

The Image Viewer application is around 150 lines of code (not counting comments), which can be compiled to any of the platforms that Qt supports, and will run natively with the platform's look-and-feel or custom look-and-feel created using style sheets. The application supports three languages and can be run on both desktop computers as well as embedded devices.

Qt provides a powerful layout system that takes care of the repositioning of widgets as an application resizes. That means that problems like dealing with users switching the view orientation from Portrait to Landscape mode, or dealing with different screen resolutions, goes away. This application has no special code for dealing with screens of different sizes or with the switching of view orientations—this is all handled automatically by Qt. Figure 4 shows the same application running in QVGA and VGA with different view orientations.

[Click image to view at full size]

Figure 4: (a) Qt Image Viewer running in QVGA Portrait; (b) Qt Image Viewer running in VGA Landscape.

Qt, Windows CE, and Visual Studio 2005

To create a native Windows CE application in Visual Studio 2005, you need four things:

The Windows CE SDK and emulator are part of the Windows Mobile 5.0 SDK available from Microsoft (www.microsoft.com/downloads/ details.aspx?familyid=83A52AF2-F524-4EC5-9155-717CBE5D25ED). If you already have a Windows CE device, you still need the SDK.

Once you have gotten the four ingredients installed, you can build a native application. The easiest way to build a Qt application is with qmake, a makefile generator that reads a project file and outputs a makefile or project file for the specified platform and compiler. To start your first project, navigate into the demos or examples directory in Qt and have qmake generate a Visual Studio project file for you. For example, navigate to demos\textedit and run:


qmake -tp vc

and open the textedit.vcproj file generated. The Visual Studio project file (.vcproj) has everything set up from include paths to library paths, as well as deployment rules that describe the libraries and resources that should be uploaded to your emulator or device. It simply takes the press of F5 to automatically build, link, and sign the application; deploy to your device; and start the native application you have created.

The really cool thing is that you don't necessarily have to use Windows CE or even Visual Studio when you develop Windows CE apps. Because Qt is cross-platform, you can develop on any supported platform, then just compile for Windows CE using Visual Studio 2005 in the end. Even though Visual Studio 2005 makes embedded development pleasant, it is still faster to debug an application when it's not running in an emulator or on a device. Indeed, I developed most of the Qt Image Viewer under Linux.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.