hi all,
the following document demonstrates how to call a simple Qt embedded
helloworld application from within a Java program. I hope it will be of
some use to those of us who want to use Qt graphics in a Java
application for embedded systems.
Regards,
Jharana

*********************************************************
Disclaimer

This message (including any attachments) contains 
confidential information intended for a specific 
individual and purpose, and is protected by law. 
If you are not the intended recipient, you should 
delete this message and are hereby notified that 
any disclosure, copying, or distribution of this
message, or the taking of any action based on it, 
is strictly prohibited.

*********************************************************
Visit us at http://www.mahindrabt.com

This document describes how to interface a Java Program with a qt embedded application with the help of JNI(Java Native Interface) using kaffe-1.0.6 JVM and qt-embedded 2.3.1 toolkit.

We will try out a simple Java Program which calls the qt-embedded hello world function from within itself.

For better understanding of JNI principles, please refer to the following link:

http://java.sun.com/docs/books/tutorial/native1.1/

The JNI allows Java code that runs within a Java Virtual Machine (VM) to operate with applications and libraries written in other languages, such as C, C++, and assembly. In our case, we will use the Kaffe JVM and Qt embedded toolkit as the native language.

Let us start with our example, writing a java program that calls the Qt function to display the helloworld widget.

For the purpose of this document we will assume that KAFFEDIR is the path where kaffe is installed on your machine, and QTDIR points to the Qt-embedded directory.

  • Writing the Java code

Let us begin by writing the Java program. Create a Java class that declares the native method; this class contains the declaration or signature for the native method. It also includes a main method which calls the native method.

The name of my program is Tryqt1.java and it contains the following code:

class Tryqt1 {

// a declaration for the native function to be called

public native void displayTryqt1();

// call to load the shared object library libTry.so containing the native function

static {

System.loadLibrary("Try");

}

public static void main(String[] args) {

//call the native function to display the hello world widget

new Tryqt1().displayTryqt1();

}

}

When you write a method implementation in a language other than Java, you must include the keyword native as part of the method's definition within the Java class. The native keyword signals to the Java compiler that the function is a native language function.

The System.loadLibrary method loads the shared library that will be created when you compile the implementation code. Place this method within a static initializer. The argument to System.loadLibrary is the shared library name. This can be any name that you choose.

The main method instantiates the Tryqt1 object and calls the displayTryqt1 native method.

  • Compile the java code

Use the Kaffe Java compiler to compile the class that you created in the previous step. Here's the command to use:

kjc Tryqt1.java

before you compile make sure that the PATH variable points to KAFFEDIR/bin, the CLASSPATH variable points to KAFFEDIR/share/kaffe/Klasses.jar as well as the native directory where you are working, the variable QTDIR is defined properly, and the variable LD_LIBRARY_PATH=$QTDIR/lib:$KAFFEDIR/lib:/$KAFFEDIR/lib/kaffe:.

The Tryqt1.class file will be created on successful compile.

  • Create the .h file

In this step, you use the kaffeh utility program to generate a header file (a .h file) from the Tryqt1 class. The header file provides a C function signature for the implementation of the native method displayTryqt1 defined in that class.

Run kaffeh now on the Tryqt1 class that you created in the previous steps.

kaffeh �jni Tryqt1

The name of the header file is the Java class name with a .h appended to the end. For example, the command shown above will generate a file named Tryqt1.h.

The file looks something like this:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

#ifndef _Included_Tryqt1

#define _Included_Tryqt1

#ifdef __cplusplus

extern "C" {

#endif

JNIEXPORT void JNICALL Java_Tryqt1_displayTryqt1(JNIEnv*, jobject);

#ifdef __cplusplus

}

#endif

#endif

The name of the native language function that implements the native method consists of the prefix Java_, the package name, the class name, and the name of the native method. Between each name component is an underscore "_" separator. We are not implementing a package hence our signature is the keyword Java followed by the classname, Tryqt1, followed by the method name i.e displayTryqt1.

  • Write the native method implementation

Now, you can finally write the implementation for the native method in a language other than Java.

Here's the C++ language implementation for the native method Java_Tryqt1_displayTryqt1. This implementation is in the file named hello.cpp

#include <qapplication.h>

#include <qpushbutton.h>

#include <stdio.h>

#include <jni.h>

#include "Tryqt1.h"

#include <stdio.h>

int qt1_show()

{

char *argv1[2] = { "qt1", "-qws"};

int argc = 2;

printf("you are in qt");

QApplication a(argc, argv1);

QPushButton *hello=new QPushButton( "Hello world!", 0 );

hello->resize( 100, 30 );

QObject::connect( hello, SIGNAL(clicked()), &a, SLOT(quit()) );

a.setMainWidget( hello );

hello->show();

return a.exec();

//return 0;

}

JNIEXPORT void JNICALL Java_Tryqt1_displayTryqt1(JNIEnv* env, jobject obj)

{

int i=qt1_show();

printf("%d", i);

}

 

 

The hello.cpp file includes two important header files apart from the regular qt header files:

  1. jni.h - This header file provides information that the native language code requires to interact with the Java runtime system. When writing native methods, you must always include this file in your native language source files.
  2. Tryqt1.h - The .h file that you generated in Step 3: Create the .h File.

The qt1_show function contains the qt code for creating a widget with a hello world button. When the button is pressed, the application exits.

  • Create the shared library

Now, you must compile hello.cpp into a shared library, which you name Try to match the library name used in the System.loadLibrary method. Since we are compiling a qt program and it needs to link with qt libraries too, we use the following command:

g++ -c �I$QTDIR/include �I$KAFFEDIR/include/kaffe -pipe -DQWS -fno-exceptions -fno-rtti -O2 -o Try.o hello.cpp

g++ -shared -L$QTDIR/lib -Wl,-rpath,$QTDIR/lib -o libTry.so Try.o -lqte

 

Be sure to replace the variables QTDIR and KAFFEDIR with the actual paths.

  • Run the program

Now run the Java application (the Tryqt1 class) with the Kaffe interpreter, as follows:

kaffe Tryqt1

You should see the Helloworld widget popping up on the terminal.

If you get java.lang.UnsatisfiedLinkError, check the variable LD_LIBRARY_PATH and make sure that it includes the paths for Qt libs, kaffe libs as well as yuur current directory which conatins the libTry.so file.

This program demonstrates a very basic kind of interfacing between Java and qt-embedded using JNI but can be used as an initial stepping stone to creating more complicated applications with qt-embedded and java using JNI. There are various ways of passing variables back and forth, of calling Java methods from C++ etc. They are explained in detail in the java tutorial on JNI from Sun.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Reply via email to