【问题标题】:Calling C code from frame in JAVA从 JAVA 框架中调用 C 代码
【发布时间】:2015-12-13 12:39:39
【问题描述】:

我对 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");     
    }  
}

【问题讨论】:

  • 这是您的完整程序吗? JNI_Lib 是什么样的?请注意,在实际程序中,您会更加注意线程,确保 Swing 代码在 Swing 事件线程上启动,并且本机代码在其自己的线程中运行。
  • 我没有发布 C 代码,否则是的,仅此而已。
  • 这不是一个完整的程序,也不是一个完整的问题。
  • @Alex.. 我没有发布 C 文件,因为我试图在其中打印一些消息只是为了确保我能够从 java 访问 C 代码
  • @Freek.. 本教程与我的问题无关。我在重复我的问题:我想使用 GUI 通过 JNI 从 Java 中获取 C 代码。

标签: java swing java-native-interface


【解决方案1】:

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

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

为了简化一点,我没有将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

万众瞩目的“来自 C 的你好!”被打印出来了。一个(非常小的)框架是可见的。 (您可以使用JFrame.setBounds 方法调整框架的大小和位置。)

编辑:使用 Eclipse

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

上面的 CLI 示例有 java.library.path 指向包含 libJNI_Lib.so 文件的目录。对于 Eclipse 中的 Java 项目,您可以选择 Run | Run Configurations... 菜单,如果需要,在左侧面板中选择 Java 项目,在右侧面板中选择 Arguments 选项卡,并添加“-Djava.library.path=”。 (不带引号)到 VM 参数。例如,请参阅运行配置对话框的屏幕截图:

【讨论】:

  • 您使用哪个版本的 Java JDK 和哪个 C 编译器?你在什么操作系统上运行?
  • 我使用 JDK1.8、gcc 编译器和 ubuntu 作为操作系统。我也在 linuxmint 上试过。
  • 关闭 Swing 应用程序的建议:创建框架后调用frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);。这样可以确保在您关闭框架时关闭您的程序。
  • 感谢您的建议。这对我有帮助,因为现在当我关闭框架时会打印“来自 C 的 Hello”消息。但是我的座右铭并没有实现。我也尝试了您建议的代码,但仍然面临同样的问题。我没有得到与你相同的输出。 “没有同时打印来自 C 的 Hello”
  • 您可以将您的输出添加到问题中吗?对我来说,“来自 C 的你好!”在使框架可见之前(以及在我关闭框架之前)打印消息。
猜你喜欢
  • 2018-09-27
  • 2010-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多