OpieProgrammingStepByStep

= Table Of Contents =

Chapter I

Next OpieProgrammingStepByStep2

= Preparing the Development Environment =

Compile Qt
See BuildingQtForOpie

Compile Opie
See BuildOpie

Set up Environment
Here is my script for initializing the Opie development environment:

export OPIEDIR=/oe/opie export PLATFORM=x68-linux export QMAKESPEC=$OPIEDIR/mkspecs/qws/linux-x86-g++ export QTDIR=/oe/qt-2.3.10
 * 1) !/bin/bash

export QWS_DISPLAY=QVFb:0

export LD_LIBRARY_PATH=$QTDIR/lib:$OPIEDIR/lib export PATH=$PATH:/oe/build/tmp/staging/i686-linux/bin

The important part here is the  environment variable, which specifies the directory where I have compiled Opie, and   where I have built Qt/Embedded for Opie. The  and   variables are used by the qmake tool and give all the information needed to create a Makefile for your project for a specific target device. is used to show a testing application window. We will see this later.

= Hello World =

Source files
First create the file main.cpp: int main( int argc, char **argv ){ QPEApplication a( argc, argv ); QPushButton hello( "Hello world!", 0 ); hello.resize( 100, 30 ); a.setMainWidget( &hello ); hello.show; return a.exec; }
 * 1) include 
 * 2) include 

Then create a project file called opie-rdt.pro: TEMPLATE = app INCLUDEPATH +=.

SOURCES += main.cpp
 * 1) Input

TARGET = opie-rdt INCLUDEPATH += $(OPIEDIR)/include DEPENDPATH += $(OPIEDIR)/include LIBS += -lqpe include ( $(OPIEDIR)/include.pro )

That is all the source code that is needed. Time to build and start your app.

Let's test it
We will build our project with the standard make command. To make it easier to create Makefiles for different platforms, TrollTech created the qmake tool. To create a Makefile from the opie-rdt.pro file we created earlier, run the following command: qmake -o Makefile opie-rdt.pro

Now you have a Makefile and you can start building: make

Next we will use the qvfb virtual framebuffer application to test our Opie application on a desktop PC: qvfb-qt2 & ./hello -qws

After the first command, you should see a small application window what will simulate the PDA screen for you. If everything goes fine after the second command you will see - "Hello World" on it. The  option tells the application to start in that small window you created. The environment variable  gives instruction where to find that framebuffer device emulation.

Tools
For now opie should be built against qt.2.3.10. Also for development we should use all tools from qt2. You can download thease tools from here:

Statically linked Qt2 tools

FIXME: Add qmake, qvfb, qt-designer e.t.c descriptions.

= Development =

Main window
Let's change a few things. First we will create two new files, mainwindow.h and mainwindow.cpp, what will separate our application main window from the application initialization code.

Here is mainwindow.h:
 * 1) ifndef MAINWINDOW_H
 * 2) define MAINWINDOW_H


 * 1) include 

class MainWindow : public QMainWindow {       Q_OBJECT public: static QString appName { return QString::fromLatin1("opie-rdt"); } MainWindow(QWidget *parent = 0, const char *name =0, WFlags fl); ~MainWindow;

private: QWidget *sourcewin; };


 * 1) endif

and mainwindow.cpp
 * 1) include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent, const char* name, WFlags fl = 0) : QMainWindow( parent, name, fl ) { sourcewin = new QWidget( this ); setCentralWidget( sourcewin ); }

MainWindow::~MainWindow { }

Let's go trought source. File mainwindow.h starts with #ifndef and #define (also see #endif at end). That is used to be sure that header files are not included more than one time.

Next lines is header file itself. Here we define new class MainWindow which will be based on QMainWindow so we include this with #include . As all QT classes we should include Q_OBJECT macro that puts all stuff needed for signal slots mechanism. We will speak about it later.

After public we define all class methods. Class constructor and destructor could be more less clear. But what is this first function? It's required for all opie main applicaion classes to give application name.

Private variable sourcewin contains main window widget and will be created in cpp file. Let's take look on it. First we include our made "mainwindow.h" file and then implement constructor and destructor functions. In constructor we create main widget and with setCentralWidget set it as window central object.

Also we should change the files we made before. In main.cpp we do two things - change the application's main class as it is now our brand new MainWindow, and use Opie's macro to create the application. So our main.cpp now looks like this:
 * 1) include 
 * 2) include "mainwindow.h"

class MainWindow;

using namespace Opie::Core; OPIE_EXPORT_APP( OApplicationFactory )

OPIE_EXPORT_APP is that macro and it is defined in oapplicationfactory.h file. MainWindow class we created earlear is used as main application class. That class should requires function appName that we created with MainWindow.

Also, we need to add mainwindow.h and mainwindow.cpp to the project file (from here onwards for short changes I will give only diffs) TEMPLATE = app INCLUDEPATH +=.

-SOURCES += main.cpp +HEADERS += mainwindow.h +SOURCES += main.cpp mainwindow.cpp
 * 1) Input

TARGET = opie-rdt INCLUDEPATH += $(OPIEDIR)/include DEPENDPATH += $(OPIEDIR)/include -LIBS += -lqpe include ( $(OPIEDIR)/include.pro )

Of course, after such a big rewrite we need re-run the whole make cycle including qmake. See previous chapters on how to do that.

We need menu
OK.. Here is a patch to apply to our mainwindow.h file to add a menu: diff -urNd step1/mainwindow.h step2/mainwindow.h --- step1/mainwindow.h 2005-04-28 20:58:38.000000000 +0300 +++ step2/mainwindow.h 2005-04-28 21:08:08.000000000 +0300 @@ -12,7 +12,11 @@ ~MainWindow; private: -  QWidget *sourcewin; + void createMenus; + + QWidget *sourcewin; + + QPopupMenu *fileMenu; };
 * 1) endif

Let's go trought changes line by line. There is two important lines added. Our class is main aplication object. So it should take care about main objects like menus. Sometimes developers use one function for all this stuff. I would recomend put construction functions as different for menu and others. So we will have function createMenus. Also menus is object wich is child of our form - QPopupMenu *fileMenu.

diff -urNd step1/mainwindow.cpp step2/mainwindow.cpp --- step1/mainwindow.cpp 2005-04-28 20:58:38.000000000 +0300 +++ step2/mainwindow.cpp 2005-04-28 21:08:08.000000000 +0300 @@ -1,10 +1,21 @@ +#include  +#include  + MainWindow::MainWindow(QWidget *parent, const char* name, WFlags fl = 0) : QMainWindow( parent, name, fl ) { sourcewin = new QWidget( this ); setCentralWidget( sourcewin ); +   +    createMenus; } MainWindow::~MainWindow { } + +void MainWindow::createMenus { + fileMenu = new QPopupMenu(this); + + menuBar->insertItem(tr("&File"), fileMenu); +}
 * 1) include "mainwindow.h"

In cpp file we have implementation of menu. Menu contains two parts: So first we include thease classes. Secondly we add our new function createMenus to main window constructor.
 * menu bar - is line on top of window which contains popup menus
 * popup menu - is application menu like File menu or like popup menu which apears after right mouse click on desktop computers.

Next goes implementation of that function. There we create menu like File menu and add it to MainWindow.menubar. Next we will continue with developing that menu.

Menus need actions
First we will change mainwindow header file:

diff -uNrd step2/mainwindow.h step3/mainwindow.h --- step2/mainwindow.h	2005-04-28 21:08:08.000000000 +0300 +++ step3/mainwindow.h	2005-04-30 13:03:13.000000000 +0300 @@ -3,6 +3,8 @@ +class QAction; + class MainWindow : public QMainWindow { 	Q_OBJECT @@ -12,10 +14,12 @@ 	~MainWindow; private: +	void createActions; void createMenus; QWidget *sourcewin; +	QAction *exitAct; QPopupMenu *fileMenu; };
 * 1) include 

What's done here? First for response to our menu clicks we use action class.

Action works like interface between any application elements (like menus items) and application slots. It's like Menu item (and also command buttons) calls > Action which emits signal for > application slot.

We should have this added in first line so compiler will not complain (to see how it is, you can left this line for now :). Also like for menus we create special function what will create all our application actions - createActions.

Next give place for or action itself - exitAct.

diff -uNrd step2/mainwindow.cpp step3/mainwindow.cpp --- step2/mainwindow.cpp	2005-04-28 21:08:08.000000000 +0300 +++ step3/mainwindow.cpp	2005-05-04 20:06:21.155427540 +0300 @@ -1,6 +1,10 @@ +#include  +#include  +#include 	// For loading icons + MainWindow::MainWindow(QWidget *parent, const char* name, WFlags fl = 0) @@ -8,14 +12,20 @@    sourcewin = new QWidget( this ); setCentralWidget( sourcewin ); +   createActions; createMenus; } MainWindow::~MainWindow { } +void MainWindow::createActions { +	exitAct = new QAction(tr("&Quit"), QString::null, 0, this, 0); +	exitAct->setIconSet(Opie::Core::OResource::loadPixmap( "quit_icon", Opie::Core::OResource::SmallIcon )); +} + void MainWindow::createMenus { fileMenu = new QPopupMenu(this); -	+	exitAct->addTo(fileMenu); menuBar->insertItem(tr("&File"), fileMenu); }
 * 1) include 
 * 2) include 
 * 1) include "mainwindow.h"

So for cpp file we first include qstring and qaction class headers. Also we include oresource header from opie2. This should be used for proper image scalling for many opie platforms it runs. We use image for menu. For now will not include image itself, we will get one from opie standart directories.

With main window creation we call function createActions so action classes is created. Next we write implementation of that function. There you see creation of action (reffer to trolltech docs for QAction arguments) and seting icon for that action.

In function createMenus we add our new created action to file menu.

Build changed application and see it working :)

Activate it
diff -uNrd step3/mainwindow.cpp step4/mainwindow.cpp --- step3/mainwindow.cpp	2005-05-04 20:06:21.155427540 +0300 +++ step4/mainwindow.cpp	2005-05-02 22:01:29.000000000 +0300 @@ -2,6 +2,7 @@ +#include  @@ -9,7 +10,7 @@ MainWindow::MainWindow(QWidget *parent, const char* name, WFlags fl = 0) : QMainWindow( parent, name, fl ) { -   sourcewin = new QWidget( this ); +   sourcewin = new QTextBrowser( this ); setCentralWidget( sourcewin ); createActions; @@ -22,6 +23,7 @@ void MainWindow::createActions { exitAct = new QAction(tr("&Quit"), QString::null, 0, this, 0); exitAct->setIconSet(Opie::Core::OResource::loadPixmap( "quit_icon", Opie::Core::OResource::SmallIcon )); +	connect( exitAct, SIGNAL( activated ), qApp, SLOT(quit) ); } void MainWindow::createMenus { diff -uNrd step3/mainwindow.h step4/mainwindow.h --- step3/mainwindow.h	2005-04-30 13:03:13.000000000 +0300 +++ step4/mainwindow.h	2005-05-02 22:01:29.000000000 +0300 @@ -2,6 +2,7 @@ +#include  class QAction; @@ -17,7 +18,7 @@ 	void createActions; void createMenus; -	QWidget *sourcewin; +	QTextBrowser *sourcewin; QAction *exitAct; QPopupMenu *fileMenu;
 * 1) include <qaction.h>
 * 2) include <qpopupmenu.h>
 * 3) include <qmenubar.h>
 * 1) include <opie2/oresource.h>	// For loading icons
 * 1) define MAINWINDOW_H
 * 1) include <qmainwindow.h>

Next OpieProgrammingStepByStep2