|
|
|
Home > Computing > Linux > Archos PMA430 (and other Archos AV) stuff > My first Qtopia application
My first Qtopia application -- how to get started with Qtopia development -- part 4
Last modified: Tue Nov 20 07:56:02 2007
A more complex graphical program
In this section, I will introduce a slightly more complex graphical
example. It doesn't do much more than the previous example but it
introduces the vital concept of `slots and signals', and also
explains how to use the Meta-Object Compiler (MOC).
In the previous example, the application's main window was a simple
instance of QMainWindow. There is a limit to what the
application can do, because we can't add any new functionality to
this pre-defined object. In a real application, the minimum we
will have to do is to create a new main window class. In many simple
application, this is the only new class that needs to be defined -- the
application may consist only of a main window containing prefined
user interface objects such as buttons and list boxes.
In this example, we will define a new class called FrmMain,
which is a subclass of QMainWindow. By convention,
Qtopia windows that accept data entry are called `forms', usually
abbreviated to Frm in class names. This window
will have a menu bar, which will contain a `File' menu, which will
contain a `Quit' command. Selecting `Quit' will close the application.
Creating the interface for the main window class
Following sensible C++ coding conventions, we will define the
new main window class in a separate .cpp file. In
This means that we need to define the interface in a separate
header file, so that code that uses the new class knows how
to refer to it. In fact, we must define the interface in a
separate header file, to get the Meta-Object Compiler
(see below) to work. I will assume that the new header file will be
called FrmMain.h, while the class implementation
will go in FrmMain.cpp (later). Here is
the header file:
#include <qmainwindow.h>
class FrmMain : public QMainWindow
{
Q_OBJECT
public:
FrmMain(QWidget* parent=0, const char* name=0, WFlags fl=0);
public slots:
void cmdFileQuit();
};
Note that we are defining FrmMain to be a subclass
of QMainWindow. The unusual thing about this
class definition, if you aren't familiar with Qt development, is
the line:
public slots:
The term `slots' is defined in the macro Q_OBJECT, which
is why it has to be included. A `slot' is a function that is capable
of responding to an event generated elsewhere in the application. I
will show later how selecting a command from a menu generates an
event, and that event is connected to the `slot'. For now, note
that cmdFileQuit() is a function that will be defined
in FrmMain.cpp, and which will be invoked in response
to a user interface action.
Creating the main window class implementation
As you should be able to see from the interface definition, we need
to implement the class constructor, and the method
cmdFileQuit(). Here is the code, in FrmMain.cpp.
#include <qpopupmenu.h>
#include <qmenubar.h>
#include "FrmMain.h"
FrmMain::FrmMain(QWidget* parent, const char* name, WFlags fl)
: QMainWindow(parent, name, fl)
{
setCaption("Hello, World!");
QMenuBar *menubar = this->menuBar();
QPopupMenu *mnuFile = new QPopupMenu(this, "MenuFile");
menubar->insertItem("&File", mnuFile);
mnuFile->insertItem("&Quit", this,
SLOT(cmdFileQuit()), 0, 1);
}
void FrmMain::cmdFileQuit()
{
this->close();
}
The constructor creates a menu bar and inserts the menu items into it.
The interesting line is this one:
mnuFile->insertItem("&Quit", this,
SLOT(cmdFileQuit()), 0, 1);
This line inserts the `Quit' menu item, and links the event generated
by the selection of this menu item to the `slot' function
cmdFileQuit(). The consequence is that this function will
be invoked when the user selects the Quit menu item. The user interface
event is a particular type of what Qt calls a `signal'. It is possible
for a class to define its own signals, and for other classes to implement
slots to receive these signals. This is a very powerful method for
decoupling classes from one another, but beyond the scope of this
article.
Compiling the main window class
We already know how to do this, from the previous section.
/opt/Embedix/tools/bin/arm-linux-g++ \
-I /opt/Qtopia/sharp/include/ \
-DQWS -fno-rtti -o FrmMain.o -c FrmMain.cpp
This (all being well) produces FrmMain.o
from FrmMain.cpp and FrmMain.h.
Creating and compiling the main class
This is essentially the same as in the previous section, but instead
of creating an instance of QMainWindow, we must create
an instance of FrmMain. So here's the code, in
hello3.cpp.
#include <qmainwindow.h>
#include <qpe/qpeapplication.h>
#include "FrmMain.h"
int main(int argc, char** argv)
{
QPEApplication app(argc, argv);
QMainWindow* mainWindow = new FrmMain();
app.showMainWidget(mainWindow);
return app.exec();
}
To compile it:
/opt/Embedix/tools/bin/arm-linux-g++ \
-I /opt/Qtopia/sharp/include/ \
-DQWS -fno-rtti -o hello3.o -c hello3.cpp
The Meta-Object Compiler
At this point we have two object files, hello3.o and
FrmMain.o, which should be linkable to produce the complete
application. But try it:
/opt/Embedix/tools/bin/arm-linux-g++ \
-L /opt/Qtopia/sharp/lib/ -o hello3 \
hello3.o FrmMain.o -lqpe -lqte -ljpeg -luuid
You'll get a heap of error messages, like this:
FrmMain.o(.text+0x450): undefined reference to
`FrmMain::QPaintDevice virtual table'
Yeuch! It looks as if something is missing and, indeed, it is. The
problem is that the slots-and-signals architecture of Qt needs
some infrastructure to make it work. This infrastructure cannot be
included in the base classes (such as QMainWindow), because
it depends on the way slots and signals are defined. So -- and this
is a major departure from most C++ programming models -- it must be
generated dynamically. Trolltech provide a tool for this: the
Meta-Object Compiler (MOC). The MOC reads header files that describe
user interface objects, and generates C++ source files that contain
the necessary slots-and-signals plumbing.
So what we need to do is to run moc on FrmMain.h
to produce a C++ file (which I will call FrmMain_moc.cpp),
and then this needs to be compiled. Finally, the compiled MOC output needs
to be linked with the other object files to produce the application.
So here we go:
/opt/Qtopia/sharp/bin/moc -o FrmMain_moc.cpp FrmMain.h
/opt/Embedix/tools/bin/arm-linux-g++ \
-I /opt/Qtopia/sharp/include/ -DQWS -fno-rtti \
-o FrmMain_moc.o -c FrmMain_moc.cpp
The first line produces the C++ class line, and the second compiles
it.
So now we can link FrmMain.o, hello3.o, and
FrmMain_moc.o.
/opt/Embedix/tools/bin/arm-linux-g++ \
-L /opt/Qtopia/sharp/lib/ -o hello3 \
hello3.o FrmMain.o FrmMain_moc.o \
-lqpe -lqte -ljpeg -luuid
We should end up with the executable hello3, which we
can strip, copy, and test as before. Now when you run the application
on the PMA430, you should see a menu bar, and when you select
File-Quit the application should close.
OK, so the application is not very sophisticated. But it demonstrates
everything you need to know to compile, link, and test
applications for the PMA430. There is nothing more to it than this.
Of course, there is a great deal more to Qtopia than this, but
Qtopia itself is well documented, and there are loads of
sample applications around.
So, we've got an application, simple as it is, that works. The problem is
that we can only run it from the command prompt, which is not ideal for
end users. So now we need to know how to package it for distribution.
Go to part 5...
|
|
|
|
Shameless plug
|
 By the author of this site. Buy on-line from Amazon USA | UK
|
|