Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaJNI:从C使用JNI创建Swing窗口_Java_C_Swing_Java Native Interface_Awt - Fatal编程技术网

JavaJNI:从C使用JNI创建Swing窗口

JavaJNI:从C使用JNI创建Swing窗口,java,c,swing,java-native-interface,awt,Java,C,Swing,Java Native Interface,Awt,我使用JNI调用一个静态java方法,该方法反过来创建一个Swing JFrame并显示它。代码相当简单,Java代码是独立工作的(即,Javastartawt做它应该做的),而当使用JNI从C调用时,进程挂起 我正在Mac OS X 10.8 Mountain Lion上使用JDK 1.7.009 这是我用来调用静态方法的C代码: JavaVM*jvm; JNIEnv*env=创建虚拟机(&jvm); jclass类=(*env)->FindClass(env,“StartAWT”); jme

我使用JNI调用一个静态java方法,该方法反过来创建一个Swing JFrame并显示它。代码相当简单,Java代码是独立工作的(即,
Javastartawt
做它应该做的),而当使用JNI从C调用时,进程挂起

我正在Mac OS X 10.8 Mountain Lion上使用JDK 1.7.009

这是我用来调用静态方法的C代码:

JavaVM*jvm;
JNIEnv*env=创建虚拟机(&jvm);
jclass类=(*env)->FindClass(env,“StartAWT”);
jmethodID方法=(*env)->GetStaticMethodID(env,类,“run”,“V”);
(*env)->CallStaticVoidMethod(env,类,方法);
(*jvm)->破坏JavaVM(jvm);
StartAWT
类如下所示:

公共类StartAWT{
公共静态类启动程序实现Runnable{
公开募捐{
System.out.println(“在AWT队列上运行”);
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame=newjframe(“那是一个帧!”);
JLabel标签=新的JLabel(“A标签”);
frame.getContentPane().add(标签);
frame.pack();
frame.setVisible(true);
}
}
公共静态类GUI实现可运行{
公开募捐{
试一试{
System.out.println(“将把某些东西放到AWT队列上。”);
SwingUtilities.invokeAndWait(newstarter());
}捕获(异常exc){
抛出新的运行时异常(exc);
}
}
}
公共静态无效运行(){
线程gui=新线程(new gui());
gui.start();
}
}
当我启动应用程序时,我确实看到
将在AWT队列上放置一些内容
,但不会看到
在AWT队列上运行

我相信我的C进程中的虚拟机没有AWT事件队列,但我也不知道如何设置它(我也不确定这是原因)

为了使用JNI显示基于AWT的GUI,应该做些什么

--

编辑:我插入了循环以查看哪些线程处于活动状态,哪些线程处于非活动状态(可以在中看到)。在这个版本中,我在另一个线程中调用
SwingUtilities.invokeAndWait
。结果:主线程处于活动状态(C)。Java调度的第一个线程(不是主线程)是活动的;执行调用
invokeAndWait
的线程被阻塞(我认为invokeAndWait甚至没有返回),甚至没有输入应该在EventQueue上运行的函数

我还尝试直接调用
SwingUtilities.invokeAndWait
,这将给出以下消息:

2013-02-02 13:50:23.629 swing[1883:707]Cocoa AWT:Apple AWT Java VM已加载到第一个线程--无法启动AWT。(
0 liblwawt.dylib 0x0000000117e87ad0 JNI_OnLoad+468
1 libjava.dylib 0x00000001026076f1 Java\u Java\u lang\u类加载器\u 00024 NativeLibrary\u加载+207
2???0x000000010265af90 0x0+4335185808
)
这也是我在StackOverflow的其他问题中读到的,比如下面评论中建议的问题。然而,我找不到解决原来问题的办法。也许值得注意的是,在出现上述消息之后,主线程仍然处于活动状态,即进程既没有死锁也没有崩溃

--

EDIT:我在Linux上测试了代码,代码正常工作。所以我相信这是MacOSX与Cocoa AWT之间的问题,但我不知道如何规避它

--

编辑:我还尝试将JVM的整个调用移动到一个新的本机线程上。这可以在Mac OS X 10.6和Apple Java 32位(1.6.0_37)上运行,但会导致与上述相同的死锁。在Mac OS X 10.8上,更糟糕的是,应用程序崩溃时只显示一条消息“Trace/BPT trap:5”(即)


我也试着按照描述绑定二进制文件,但是启动失败,消息是
lsopenurlswithrole(),消息是-10810
,这是一个未知错误,据苹果公司称。后者也会在不尝试使用AWT的情况下发生(仅JVM调用失败)。

最后我找到了一个解决方案

问题不是在哪个线程上创建虚拟机,而是在哪个线程上初始化AWT事件队列。换句话说:第一次加载AWT类时,它可能不会加载到主线程上。因此,步骤1:在另一个线程上加载(例如)
java.awt.Component

但是现在EventQueue将阻塞,因为它将工作委托给Cocoa主事件队列,而Cocoa主事件队列没有运行——这是肯定的,因为它将只在主线程上运行,而主线程是我的应用程序。因此,主运行循环需要在主线程上启动:

void
runCocoaMain()
{
    void* clazz = objc_getClass("NSApplication");
    void* app = objc_msgSend(clazz, sel_registerName("sharedApplication"));

    objc_msgSend(app, sel_registerName("run"));
}
我必须将我的应用程序与Cocoa框架链接,并包含
。主线程在调用runCocoaMain后被阻塞(因为事件循环正在那里运行),因此需要为应用程序本身求助于另一个线程


使用上述代码段运行EventQueue后,AWT类在另一个线程上的加载将成功,您可以继续加载。

我通过的说明解决了类似的问题,即在另一个线程中启动JVM后启动
CFRunLoopRun()

请参见此。谢谢,我已经检查了Q&A和我的申请;但它毕竟不起作用(正如在另一个问题中,也没有给出解决方案);我只使用了
JavaApplicationStub
,但我不知道它是如何工作的。我想知道引用的JVM TI是否有任何相关内容。它在Linux(Ubuntu12.04 LTS 32位)上的工作原理与预期完全一致。万岁!我找到了一个解决方案,请看我的回答:我不完全理解。你能帮我吗