2012-03-02 92 views
3

我正在编写一个实用程序以帮助测试更大的系统,并且如果通过系统运行它,我的UI完全不显示。当我自己运行它时它工作正常。更多细节:Swing应用程序在某些情况下不显示

  1. 我测试的系统有很多进程,由控制器管理。部署时,controller.exe会生成并终止子进程,包括我的Java应用程序。当由控制器启动时,我的应用运行正常(工作,生成日志等),但Swing UI根本不呈现。
  2. 我可以从命令行自己启动我的应用程序,并且UI显示得很好。根据Process Explorer,路径,命令行和当前目录与从应用程序从控制器启动时观察到的值完全相同。
  3. 当该应用程序不可见时,单击Process Explorer中的“带到前面”弹出一个对话框。 “在这个过程中找不到可见的窗口。”单击手动衍生进程上的相同按钮可以使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甚至会使用它们监视的数据填充。据我所知,一切都有效。我什么都看不到。

我很抱歉,如果这已被其他地方回答。我尽力搜索,但是我能找到的所有问题都是关于某些组件无法呈现的问题,从来没有整个应用程序显示失败。

谢谢!

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

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] 
[email protected][dev=Win32GraphicsDevice[screen=0],pixfmt=0] 
java.awt.Rectangle[x=0,y=0,width=1920,height=1080] 

这似乎表明有一个配置只有一台设备,所以我在一个小的损失的。

回答

2

解决的办法是分割该应用分成2个部分(数据收集和ui /处理)并让他们通信通过RMI

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

重申一点,java没有提出任何例外。看起来这种情况应该抛出一些东西来表明java进程没有创建新窗口的权限,但代码运行“正常”。该窗口从未出现。底线:如果另一个进程启动你的虚拟机,并且你没有错误,但没有用户界面,请检查以确保你的虚拟机不作为服务启动。如果是这样,您需要将ui代码提取到单独的进程中。

+1

对于一个问题,+1太复杂了:-) – mKorbel 2012-03-05 21:15:08

5

您遇到了Concurency in Swing的问题。 Swing是单线程的,并且所有输出到Swing GUI的输出都必须在EDT上完成。

  • 基本上你可以在invokeLaterinvokeAndWait包裹输出到GUI解决

  • 正确的方法是从SwingWorkerRunnable#Thread调用后台任务(S)(在Runnable,输出必须包裹成invokeLaterinvokeAndWait

EDIT

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

public class SSCCE extends JFrame { 

    private static final long serialVersionUID = 1L; 

    public SSCCE() { 
     super("SSCCE"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setContentPane(createContent()); 
     pack(); 
     centerFrameOnMonitor(0); 
     setVisible(true); 
    } 

    private JComponent createContent() { 
     JPanel ret = new JPanel(); 
     JButton button = new JButton("I have a tooltip"); 
     button.setToolTipText("I wonder where this tooltip is going to popup!"); 
     ret.add(button); 
     return ret; 
    } 

    /** 
    * Centers this frame in the middle of the monitor with the monitorIndex specified. This method assumes that all monitors are laid out 
    * horizontally. The 0th index monitor would be the one furthest left. 
    * @param monitorIndex 
    */ 
    private void centerFrameOnMonitor(int monitorIndex) { 
     GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
     GraphicsDevice[] devices = e.getScreenDevices(); 
     if (monitorIndex < 0 || monitorIndex >= devices.length) { 
      throw new RuntimeException("Monitor Index out of bounds: " + monitorIndex); 
     } 
     Arrays.sort(devices, new Comparator<GraphicsDevice>() { 

      @Override 
      public int compare(GraphicsDevice a, GraphicsDevice b) { 
       return (int) (a.getDefaultConfiguration().getBounds().getX() - b.getDefaultConfiguration().getBounds().getX()); 
      } 
     }); 
     GraphicsConfiguration gc = devices[monitorIndex].getDefaultConfiguration(); 
     Rectangle gcBounds = gc.getBounds(); 
     Point p = new Point((int) (gcBounds.getX() + (gcBounds.getWidth()/2 - this.getWidth()/2)), (int) (gcBounds.getY() + (gcBounds.getHeight()/2 - this.getHeight()/2))); 
     this.setLocation(p); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       SSCCE sSCCE = new SSCCE(); 
      } 
     }); 
    } 
} 

EDIT2:

能力测试从HP精英,WINXP,的Java6,低轮廓GPU retuns

enter image description here

enter image description here

+0

感谢您的回复。我已经用SwingWorker.invokeLater()包装了发布。我的主要课程是AceProbe。所以当我从命令行运行java -cp lib/* AceProbe时,它就可以工作。但是当控制器运行完全相同的命令时,它不起作用。 – 2012-03-02 20:25:37

+0

@Eric Grunzke问题可能无处不在,将根据可运行的代码将问题分解为单独的问题 – mKorbel 2012-03-02 20:36:24

+0

有意义。我编辑了原文,表明问题存在于最简单的用户界面中。有更好的分割,还是我可以提供的一些信息? – 2012-03-02 20:56:51

相关问题