在某些情况下,Swing app不会显示

时间:2012-03-02 17:44:28

标签: java swing windows-xp

我正在编写一个实用程序来帮助测试更大的系统,如果我在系统中运行它,我的UI根本不显示。我自己运行时工作正常。更多细节:

  1. 我正在测试的系统有很多进程,由控制器管理。部署后,controller.exe会生成并终止子进程,包括我的java应用程序。当控制器启动时,我的应用程序运行良好(可以正常工作,生成日志等)但Swing UI根本无法渲染。
  2. 我可以从命令行自己启动我的应用程序,UI显示就好了。根据Process Explorer,Path,Command Line和Current Directory都与从控制器启动应用程序时观察到的值相同。
  3. 当应用程序无法访问时,单击Process Explorer中的“Bring to Front”会弹出一个对话框,显示为。 “这个过程找不到可见的窗户。”单击手动生成的进程上的相同按钮会使Swing UI按预期显示在前面。
  4. 我在Windows XP中对此进行了测试。控制器进程在SYSTEM下运行。我使用"at 09:45 /interactive cmd.exe" trick为我的手动启动生成一个命令提示符作为SYSTEM。 Process Explorer验证两个方法(手动/控制器)将java进程生成为SYSTEM。
  5. 这两个过程之间唯一明显的区别是父母。系统进程作为controller.exe的子进程生成,而我的手动执行是cmd.exe的子进程。
  6. 我使用jdwp远程调试了隐形进程,一切看起来都很正常。 UI代码执行,不会抛出异常,我的JLists甚至会填充他们监视的数据。据我所知,一切正常;我只是看不到任何一个。
  7. 如果在其他地方已经回答,我道歉。我尽力搜索,但我能找到的所有问题都是关于某些组件无法呈现,而不是整个应用程序无法显示。

    谢谢!

    编辑: 根据反馈,我换了一个尽可能小的演示程序。这是整个代码:

    import java.awt.BorderLayout;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.SwingUtilities;
    
    public class AceProbe
    {
      public static void main(String[] args)
      {
        SwingUtilities.invokeLater(new Runnable()
        {
          @Override
          public void run()
          {
            JFrame frame = new JFrame("Visible?");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.getContentPane().add(new JLabel("Test"), BorderLayout.CENTER);
            frame.pack();
            frame.setVisible(true);
          }
        });
      }
    }
    

    从命令行运行此命令会按预期显示该窗口。但是,当控制器生成进程时,不会显示任何内容。当由控制器生成时,我可以使用-agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address=8000远程调试进程,并验证所有线程是否按预期生成,并且不会抛出任何异常。

    我从这里的直觉是控制器处于一些奇怪的图形配置中,因为父进程是新的java进程,也许Swing没有使用正确的GraphicsDevice?我尝试添加此代码:

    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    for(GraphicsDevice d : ge.getScreenDevices())
    {
      Log.println(d);
      for (GraphicsConfiguration c : d.getConfigurations())
      {
        Log.println(c);
        Log.println(c.getBounds());
      }
    }
    

    日志包含:

    Win32GraphicsDevice[screen=0]
    sun.awt.Win32GraphicsConfig@13f459d[dev=Win32GraphicsDevice[screen=0],pixfmt=0]
    java.awt.Rectangle[x=0,y=0,width=1920,height=1080]
    

    这似乎表明只有一个配置有一个配置,所以我有点亏。

2 个答案:

答案 0 :(得分:5)

Concurency in Swing存在问题。 Swing是单线程的,所有输出到Swing GUI必须在EDT上完成。

  • 基本上你可以通过将输出包装到invokeLaterinvokeAndWait

  • 中的GUI来解决这个问题
  • 正确的方法是从SwingWorkerRunnable#Thread调用后台任务(在Runnable中,输出必须包含在invokeLater或{{1}中}})

修改

invokeAndWait

EDIT2:

功能测试返回

enter image description here

来自HP Elite,WinXp,Java6,低调GPU

enter image description here

答案 1 :(得分:2)

解决方案是将应用程序拆分为2个组件(数据收集和ui /处理),并让它们通过RMI进行通信。

事实证明,Windows服务无法生成GUI。我做了一些sc query并发现controller.exe是一项服务。由于它是java进程的父进程,java获得相同的服务权限,这意味着没有gui。有some workarounds,但它们是为了向后兼容而存在,在新代码中应该避免使用。

重申java没有引发任何异常是很重要的。似乎这种情况应该抛出一些东西来表明java进程没有创建新窗口的权限,但代码“正常”运行。窗口永远不会出现。

底线:如果另一个进程正在启动您的虚拟机,并且您没有错误但没有ui,请检查以确保您的虚拟机没有作为服务启动。如果是,则需要将ui代码提取到单独的进程中。