组件可见时的java事件

cor*_*liu 3 java events swing jscrollpane componentlistener

我有一个JScrollPane包裹在一个JPanel周围,该JPanel可能包含数百个显示缩略图的JLabel(每个JLabel一个缩略图)。出于内存原因,我不想构建所有缩略图。我只想为可见的JLabel构建缩略图,并在其JLabel变得不可见时删除缩略图。当用户滚动JPanel时,它们变为可见/不可见。我试图通过使用ComponentListener来实现缩略图的加载/卸载:

addComponentListener( new ComponentAdapter() {

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

    @Override
    public void componentHidden( ComponentEvent e ) {
        setIcon( null );
    }
});
Run Code Online (Sandbox Code Playgroud)

但这是行不通的。JLabel始终为空。我可以使用scroll事件并计算应该加载哪些缩略图,但是在此之前,我想知道是否有更简单的解决方案。

Dur*_*dal 6

“可见”属性并不意味着“在屏幕上”可见。它仅指示是否显示组件本身。由于默认情况下组件是可见的,并且仅在属性更改时才通知侦听器,所以永远不会通知您的侦听器。

据我所知,没有专门的事件涉及告诉组件何时进入显示器的可见区域。另请注意,在标签上设置图标可能会更改其首选大小,从而破坏整个布局。可以通过手动为标签提供固定的首选大小来解决此问题(对于缩略图,这应该很简单)。

一种懒惰的方法是覆盖标签上的paintComponent并检查是否需要将拇指加载到paintComponent中:

 protected void paintComponent(Graphics g) {
     if (getIcon() == null) {
         // create thumbnail
     }
     super.paintComponent(g);
 }
Run Code Online (Sandbox Code Playgroud)

这不是最佳方法,因为您的代码将在Swings事件分配线程中运行。这意味着加载缩略图的任何延迟都将阻止UI的呈现。

IMO最好的方法是只请求加载缩略图,然后将实际加载推迟到后台线程。该线程完成加载后,可以使用SwingUtilities.invoke(或invokeLater)更新标签(如果我没有记错的话,它会自动触发重新绘制)。

结果是滚动滚动的标签短暂显示为空,然后在有拇指可用时立即更新。