2012-03-02 72 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

相關問題