2016-02-05 72 views
1

我有一個JScrollPane環繞一個JPanel,它包含潛在的數百個顯示縮略圖圖像的JLabel(每個JLabel一個縮略圖)。出於記憶的原因,我不想構建所有的縮略圖。我只想爲可見的JLabel構建縮略圖,並在JLabel不可見時刪除縮略圖。當用戶滾動JPanel時,它們變得可見/不可見。我試圖通過像這樣使用ComponentListener來實現加載/卸載縮略圖:Java組件變得可見時的事件

addComponentListener(new ComponentAdapter() { 

    @Override 
    public void componentShown(ComponentEvent e) { 
     setIcon(new ImageIcon(getThumb())); 
    } 

    @Override 
    public void componentHidden(ComponentEvent e) { 
     setIcon(null); 
    } 
}); 

但是這不起作用。 JLabels總是空的。我可以使用滾動事件並計算應該加載哪些縮略圖,但在此之前我想知道是否有更簡單的解決方案。

回答

2

「可見」屬性並不意味着「在屏幕上」可見。它僅指示組件本身是否被顯示。由於默認組件是可見的,只有當屬性更改時纔會通知偵聽器,因此您的偵聽器從未得到通知。

據我所知,沒有涉及告訴組件何時進入顯示器的可見區域的專用事件。另請注意,在標籤上設置圖標可能會改變其首選尺寸,從而破壞整個佈局。這可以通過手動爲標籤提供固定的首選大小(縮略圖時應該很簡單)來解決。

懶惰的做法是覆蓋在標籤上的paintComponent並檢查拇指需要的paintComponent被加載:

protected void paintComponent(Graphics g) { 
    if (getIcon() == null) { 
     // create thumbnail 
    } 
    super.paintComponent(g); 
} 

這是不是最好的方法,因爲你的代碼中運行鞦韆事件派遣線程。這意味着加載縮略圖的任何延遲都會阻止呈現您的用戶界面。

一個更爲理智的方法IMO將僅對請求加載縮略圖並將實際加載推遲到後臺線程。當線程完成加載時,它可以使用SwingUtilities.invoke(或invokeLater)更新標籤(如果我沒有弄錯,它會自動觸發重新繪製)。

效果是,滾動的標籤顯示爲空,然後在拇指可用時立即更新。

+0

謝謝杜蘭達爾。你的方法非常好,但我也需要使用一個具有固定容量的隊列,這會排除舊圖標(這可能會變得不可見)。 – corneliu

+0

@corneliu然後你可以讓你的隊列成爲一個LIFO隊列,首先提供最近的請求,並清除隊列另一端的標籤圖標。這樣一來,只有固定數量的縮略圖會同時存在。但爲了減少重新加載,只要可用內存允許,我可能還會使用SoftReference使用緩存來保留縮略圖。 – Durandal

+0

再次感謝您。這正是我想到的那種隊列。我將調查SoftReference提示。聽起來很有希望。 – corneliu