2011-09-11 46 views
2

我有一個class GridPanel extends JPanel,靜態內部類ToolSelectComboBox extends JComboBox,它又有兩個靜態內部類ToolSelectComboBoxModel implements ComboBoxModelToolSelectComboBoxRenderer implements ListCellRenderer。該面板顯示ToolSelectComboBox(TSCB),其構造函數將其模型和渲染器設置爲我創建的自定義模型。該框已正確創建,其模型和渲染器正常工作。ImageIcon慢在ListCellRenderer

但是,渲染器的getListCellRendererComponent(...)方法在其返回的JLabel上使用ImageIcon。圖標裝入正確,但是,我第一次單擊組合框(每次運行),圖像需要恰好(或至少非常非常接近)比第二多一點加載。我會認爲這是在加載文件有些滯後,但

  • 這是我的本地文件系統
  • 當我添加System.out.println命令和result.setIcon(...)命令後,他們按照對方之前,4KB的文件幾乎立即。

,我發現奇怪的是,println命令被解僱兩次,一旦當我點擊框,再次圖標加載時。

也可能值得注意的是,由於這是設計用於重寫父抽象類的單個方法(用於生成圖標的路徑)的多個類的工作,所以當我注意到這是工作緩慢時,我在一個TreeMap<Tool.ImageSize, ImageIcon>(其中Tool是我創建具有ImageIcon getIcon()方法的接口。

所有改變了代碼從簡單地與getIcon命令檢索圖標,存儲各種尺寸的圖標(16,32,和64像素的平方)我進口秩序。

任何幫助,將不勝感激!

我很抱歉,如果我發佈了太多的代碼,但我想確保它是可以理解的。另一方面,如果你需要了解更多的代碼,請不要猶豫,問問。

代碼(以「*」打頭,類似於註釋文本行全部倒塌JavaDoc標籤,不只是亂七八糟的代碼):

public class GridPanel extends JPanel { 

    public static class ToolSelectComboBox extends JComboBox { 

     // Combo box model `ToolSelectComboBoxModel` snipped 

     * A renderer for the {@link ToolSelectComboBoxModel}. This may 
     public static class ToolSelectComboBoxRenderer implements 
       ListCellRenderer { 

      * The default renderer. Only the icon and text are modified. 
      protected DefaultListCellRenderer d = new DefaultListCellRenderer(); 

      @Override 
      public Component getListCellRendererComponent(final JList list, 
        final Object value, final int index, 
        final boolean isSelected, final boolean cellHasFocus) { 
       if (!ToolSelectComboBoxModel.class.isInstance(list.getModel())) { 
        throw new IllegalStateException(
          "Cannot use a ToolSelectComboBoxRenderer on any list model type other than ToolSelectComboBoxModel."); 
       } 
       final JLabel result = (JLabel) d.getListCellRendererComponent(
         list, value, index, isSelected, cellHasFocus); 
       result.setText(null); 
       if (value != null) { 
        result.setIcon(((Tool) value) 
          .getIcon(Tool.IconSize.SIZE_32PX)); 
       } 
       return result; 
      } 
     } 

     public ToolSelectComboBox() { 
      setModel(new ToolSelectComboBoxModel()); 
      ((ToolSelectComboBoxModel) getModel()).add(new CircleTool()); // shown below 
      setRenderer(new ToolSelectComboBoxRenderer()); 
     } 
    } 

    * Create the panel. 
    public GridPanel() { 
     setLayout(new BorderLayout(0, 0)); 

     final ToolSelectComboBox toolSelectComboBox = new ToolSelectComboBox(); 
     add(toolSelectComboBox, BorderLayout.NORTH); 

     final SquareGrid squareGrid = new SquareGrid(); // another class; this works fine 
     add(squareGrid, BorderLayout.CENTER); // irrelevant to problem 

    } 

} 

CircleTool類只有一個方法(重寫AbstractTool的抽象方法來獲得圖像路徑),而且由於該方法的工作原理(它獲取的路徑罰款,它只是加載緩慢),我沒有將這個類的圖標。

AbstractTool類:

public abstract class AbstractTool implements Tool { 

    /** 
    * A {@link TreeMap} to map the icon sizes to their icons. 
    */ 
    protected final TreeMap<Tool.IconSize, ImageIcon> map = new TreeMap<Tool.IconSize, ImageIcon>(); 

    /** 
    * Constructs the tool and sets up the {@linkplain #map}. 
    */ 
    public AbstractTool() { 
     for (final Tool.IconSize size : Tool.IconSize.values()) { 
      System.out.println("Putting value for " + size); 
      map.put(size, 
        new ImageIcon(Tool.class.getResource(getImagePath(size)))); 
     } 
    } 

    @Override 
    public ImageIcon getIcon(final IconSize size) { 
     return map.get(size); 
    } 

    /** 
    * Gets the image path for the given image size. 
    * 
    * @param size 
    *   the size 
    * @return the image path 
    */ 
    protected abstract String getImagePath(Tool.IconSize size); 

} 

回答

3

但是,我第一次單擊組合框(每次運行),圖像需要比第二多一點加載。我會假設這是加載文件的一些滯後

這也是我的猜測。

除了

當我添加之前的System.out.println命令和result.setIcon(...)命令後,當您單擊組合框上的他們按照對方几乎立即

所有代碼都在EDT上運行,這意味着每個圖標都會按順序加載。

但是System.out.println()在單獨的線程上運行,因此它立即顯示。

解決方法是在程序啓動時加載圖標。那就是每當你定義/添加圖標到你的地圖時,你應該在那個時候閱讀它們。您可能希望在單獨的線程上執行此操作,以免阻止GUI顯示。

編輯:

下面是一個簡單的SSCCE在組合框中顯示的圖標:

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

public class ComboBoxIcon extends JFrame 
{ 
    JComboBox comboBox; 

    public ComboBoxIcon() 
    { 
     Object[] items = 
     { 
      new ImageIcon("about16.gif"), 
      new ImageIcon("add16.gif"), 
      new ImageIcon("copy16.gif") 
     }; 
     comboBox = new JComboBox(items); 
     getContentPane().add(comboBox, BorderLayout.NORTH); 
    } 

    public static void main(String[] args) 
    { 
     JFrame frame = new ComboBoxIcon(); 
     frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 
} 

如果您需要更多的幫助,那麼你需要發表您SSCCE演示該問題。

+0

感謝您的回覆!你說的關於在單獨的Thread上運行的'println'命令是有道理的;我沒有想到這一點。但是,事件派發線程是什麼?維基百科的文章並沒有讓我清楚,我對Java相當陌生(並且習慣了C++,我聽說這是一個麻煩從轉移),所以請原諒我的無知:)。我認爲通過將'ImageIcon'放入我的'TreeMap'中,圖標會自動加載;情況並非如此?如果沒有,我該怎麼做? 'loadImage()'是受保護的;我應該使用'getImage()'嗎? – wchargin

+0

我嘗試了'getImage()',並且在新的'Thread'和默認'Thread'內都出現了滯後時間。你會建議我做什麼?我應該只是創建一個圖形對象並將它繪製到圖標上? – wchargin

+0

是創建ImageIcon應該導致圖像被加載。從你的代碼中看不出你何時或如何做到這一點。所以我不知道在創建和顯示GUI時是否這樣做,或者是否在單擊組合框時發生。它似乎是後者。 EDT是Event Dispatch Thread。 GUI的所有更新都應在此主題上執行。閱讀[併發中的Swing](http://download.oracle.com/javase/tutorial/uiswing/concurrency/index.html)瞭解更多信息。我包含了我的SSCCE,可以在預加載時立即顯示圖標。 – camickr