在JAVA中从帧调用C代码

时间:2015-12-13 12:39:39

标签: java swing java-native-interface

我是java编程的新手,所以如果这听起来像个愚蠢的问题,我会提前道歉。

我正在使用JNI通过创建Swing JFrame来调用C代码并显示它。代码非常简单,如果我将框架可见性设置为false(即调用“hello”方法),Java代码工作正常,而当我将框架可见性设置为true时,没有任何反应(即“hello”方法是不叫)。

Test.java

public class Test extends JFrame {

    private JPanel contentPane;
    public static Container root;

    /**
     * Launch the application.
     */

     public static void main(String[] args) {

        try {
            Test frame = new Test();

            new JNIServer().hello("world");  // where hello is native method
            frame.setVisible(true);

        } catch (Exception e) {
            e.printStackTrace();        
        }
    }       
}

JNIServer.java

public class JNIServer{

    public native void hello(String name);  

    static {  
         System.out.println("Inload library");
         System.loadLibrary("JNI_Lib");     
    }  
}

1 个答案:

答案 0 :(得分:0)

正如Hovercraft Full Of Eels已经建议的那样,您可以尝试使用单独的线程。我还会尝试添加一些println语句,以查明问题的原因。

为了重现您的问题,我使用Java SE 1.8.0_66-b17(java -version)和gcc(Ubuntu 4.8.4-2ubuntu1~14.04)4.8.4(gcc)测试了Ubuntu 14.04 64位 - 版本)。

为了简化一些事情,我没有将String参数传递给hello方法/函数,暂时跳过该转换。这些是我用来测试的源文件:

// Test.java

import java.awt.Container;
import javax.swing.*;

public class Test extends JFrame {
    private JPanel contentPane;
    public static Container root;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {

        try {
            Test frame = new Test();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            frame.callNativeFunction();

            System.out.println("Test.main - before setting frame visible");
            frame.setVisible(true);
            System.out.println("Test.main - after setting frame visible");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void callNativeFunction() {
        Thread nativeFunctionThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Test.run - before calling hello.");
                new JNIServer().hello();  // where hello is native method
                System.out.println("Test.run - after calling hello.");
            }
        });

        nativeFunctionThread.start();
    }
}


// JNIServer.java

public class JNIServer {
    public native void hello();

    static {  
        System.out.println("Inload library");
        System.loadLibrary("JNI_Lib");
    }  
}


// JNIServer.h (generated)

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNIServer */

#ifndef _Included_JNIServer
#define _Included_JNIServer
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JNIServer
 * Method:    hello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JNIServer_hello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif


// JNI_Lib.c

#include <jni.h>
#include <stdio.h>

JNIEXPORT void JNICALL Java_JNIServer_hello(JNIEnv * environment,
                                            jobject java_object) {
    printf("Hello from C!\n");
}

为了构建应用程序,我运行了以下命令:

javac Test.java
java Test
javah JNIServer

gcc -fPIC -o libJNI_Lib.so -shared -I /usr/lib/jvm/java-8-oracle/include -I /usr/lib/jvm/java-8-oracle/include/linux JNI_Lib.c -lc

java -Djava.library.path=. Test

这是java -Djava.library.path=. Test命令的输出:

Test.main - before setting frame visible
Test.run - before calling hello.
Inload library
Hello from C!
Test.run - after calling hello.
Test.main - after setting frame visible

备受期待的&#34;你好,来自C!&#34;被打印了。可以看到(非常小的)框架。 (您可以使用JFrame.setBounds方法调整帧的大小和位置。)

编辑:使用Eclipse

虽然应该可以合并Java and C project in Eclipse,但我建议从一个较小的步骤开始:使用两个单独的Eclipse项目(甚至更小:创建一个引用CLI创建的库的Java项目C项目)。如果这样做,您可以使用组合的Eclipse项目。

上面的CLI示例使用java.library.path指向具有libJNI_Lib.so文件的目录。对于Eclipse中的Java项目,可以选择Run |运行Configurations ...菜单,如有必要,在左侧面板中选择Java项目,在右侧面板中选择Arguments选项卡,然后添加&#34; -Djava.library.path =。&#34; (没有引号)到VM参数。例如,请参阅“运行配置”对话框的此屏幕截图:

Screenshot of the Run Configurations dialog