JList 重绘单个元素 [英] JList repaint single element

查看:57
本文介绍了JList 重绘单个元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 JList,它的元素由我正在为其创建缩略图的图像文件组成(在后台线程中).当这些缩略图可用时,我想强制重新绘制该项目.但是,我发现当我使用 listModel 的 fireDataChanged 方法(见下文)时,所有列表中的可见项都被重新绘制(使用我的自定义 ListCellRenderer).

I've got a JList whose elements consist of image files for which I'm creating thumbnails (in a background Thread). When these thumbnails become available, I'd like to force a repaint of just that item. However, I find that when I use the listModel's fireDataChanged method (see below), all the visible items in the list are repainted (using my custom ListCellRenderer).

public void updateElement(int index) {
    frame.listModel.fireContentsChanged(frame.listModel, index, index);
}

有没有办法只重绘索引项?

Is there any way to cause ONLY the indexed item to be repainted?

推荐答案

我发现当我使用listModel的fireDataChanged方法时(见下文),列表中的所有可见项都被重新绘制

I find that when I use the listModel's fireDataChanged method (see below), all the visible items in the list are repainted

您不应手动调用该方法.fireXXX(...) 方法只能由模型本身调用.

You should NOT invoke that method manually. The fireXXX(...) methods should only be invoked by the model itself.

您应该使用以下方法更新模型:

You should be updating the model by using the:

model.set(...);

set(...) 方法然后将调用适当的方法来通知 JList 重新绘制单元格.

The set(...) method will then invoke the appropriate method to notify the JList to repaint the cell.

这是我对一个简单的缩略图应用程序的尝试.它尝试通过以下方式增加性能改进:

Here is my attempt at a simple Thumbnail app. It attempts to add performance improvements by:

  1. 使用默认图标加载模型,以便列表不需要不断调整自身大小
  2. 使用 ExecutorService 来利用多个处理器
  3. 使用 ImageReader 读取文件.子采样属性允许您在缩放图像时使用更少的像素.

只需将类更改为指向包含一些 .jpg 文件的目录并试一试:

Just change the class to point to a directory containing some .jpg files and give it a go:

缩略图应用程序:

import java.io.*;
import java.util.concurrent.*;
import java.awt.*;
//import java.awt.datatransfer.*;
import java.awt.event.*;
import javax.swing.*;

class ThumbnailApp
{
    private DefaultListModel<Thumbnail> model = new DefaultListModel<Thumbnail>();
    private JList<Thumbnail> list = new JList<Thumbnail>(model);

    public ThumbnailApp()
    {
    }

    public JPanel createContentPane()
    {
        JPanel cp = new JPanel( new BorderLayout() );

        list.setCellRenderer( new ThumbnailRenderer<Thumbnail>() );
        list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        list.setVisibleRowCount(-1);
        Icon empty = new EmptyIcon(160, 160);
        Thumbnail prototype = new Thumbnail(new File("PortugalSpain-000.JPG"), empty);
        list.setPrototypeCellValue( prototype );
        cp.add(new JScrollPane( list ), BorderLayout.CENTER);

        return cp;
    }

    public void loadImages(File directory)
    {
        new Thread( () -> createThumbnails(directory) ).start();
    }

    private void createThumbnails(File directory)
    {
        try
        {
            File[] files = directory.listFiles((d, f) -> {return f.endsWith(".JPG");});

            int processors = Runtime.getRuntime().availableProcessors();
            ExecutorService service = Executors.newFixedThreadPool( processors - 2 );

            long start = System.currentTimeMillis();

            for (File file: files)
            {
                Thumbnail thumbnail = new Thumbnail(file, null);
                model.addElement( thumbnail );
//              new ThumbnailWorker(file, model, model.size() - 1).execute();
                service.submit( new ThumbnailWorker(file, model, model.size() - 1) );
            }

            long duration = System.currentTimeMillis() - start;
            System.out.println(duration);

            service.shutdown();
        }
        catch(Exception e) { e.printStackTrace(); }
    }

    private static void createAndShowGUI()
    {
        ThumbnailApp app = new ThumbnailApp();

        JFrame frame = new JFrame("ListDrop");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane( app.createContentPane() );
        frame.setSize(1600, 900);
        frame.setVisible(true);

//      File directory = new File("C:/Users/netro/Pictures/TravelSun/2019_01_Cuba");
        File directory = new File("C:/Users/netro/Pictures/TravelAdventures/2018_PortugalSpain");
        app.loadImages( directory );
    }
    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(() -> createAndShowGUI());
    }
}

缩略图工作者:

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.util.Iterator;
//import java.util.concurrent.*;
import javax.imageio.*;
import javax.imageio.stream.*;
import javax.swing.*;

class ThumbnailWorker extends SwingWorker<Image, Void>
{
    private File file;
    private DefaultListModel<Thumbnail> model;
    private int index;

    public ThumbnailWorker(File file, DefaultListModel<Thumbnail> model, int index)
    {
        this.file = file;
        this.model = model;
        this.index = index;
    }

    @Override
    protected Image doInBackground() throws IOException
    {
//      Image image = ImageIO.read( file );

        Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
        ImageReader reader = readers.next();
        ImageReadParam irp = reader.getDefaultReadParam();
//      irp.setSourceSubsampling(10, 10, 0, 0);
        irp.setSourceSubsampling(5, 5, 0, 0);
        ImageInputStream stream = new FileImageInputStream( file );
        reader.setInput(stream);
        Image image = reader.read(0, irp);

        int width = 160;
        int height = 90;

        if (image.getHeight(null) > image.getWidth(null))
        {
            width = 90;
            height = 160;
        }

        BufferedImage scaled = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = scaled.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        g2d.drawImage(image, 0, 0, width, height, null);
        g2d.dispose();
        image = null;

        return scaled;
   }

   @Override
   protected void done()
   {
       try
       {
           ImageIcon icon = new ImageIcon( get() );
           Thumbnail thumbnail = model.get( index );
           thumbnail.setIcon( icon );
           model.set(index, thumbnail);
           System.out.println("finished: " + file);
       }
       catch (Exception e)
       {
           e.printStackTrace();
       }
   }
}

缩略图渲染器

import java.awt.Component;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class ThumbnailRenderer<E> extends JLabel implements ListCellRenderer<E>
{
    public ThumbnailRenderer()
    {
        setOpaque(true);
        setHorizontalAlignment(CENTER);
        setVerticalAlignment(CENTER);
        setHorizontalTextPosition( JLabel.CENTER );
        setVerticalTextPosition( JLabel.BOTTOM );
        setBorder( new EmptyBorder(4, 4, 4, 4) );
    }

    /*
     *  Display the Thumbnail Icon and file name.
     */
    public Component getListCellRendererComponent(JList<? extends E> list, E value, int index, boolean isSelected, boolean cellHasFocus)
    {
        if (isSelected)
        {
            setBackground(list.getSelectionBackground());
            setForeground(list.getSelectionForeground());
        }
         else
        {
            setBackground(list.getBackground());
            setForeground(list.getForeground());
        }

        //Set the icon and filename

        Thumbnail thumbnail = (Thumbnail)value;
        setIcon( thumbnail.getIcon() );
        setText( thumbnail.getFileName() );

        return this;
    }
}

缩略图:

import java.io.File;
import javax.swing.Icon;

public class Thumbnail
{
    private File file;
    private Icon icon;

    public Thumbnail(File file, Icon icon)
    {
        this.file = file;
        this.icon = icon;
    }

    public Icon getIcon()
    {
        return icon;
    }

    public void setIcon(Icon icon)
    {
        this.icon = icon;
    }

    public String getFileName()
    {
        return file.getName();
    }
}

我在一个包含 302 个图像的目录上进行了测试.使用 ExecutorService 将加载时间从 2:31 缩短到 0:35.

I tested on a directory with 302 images. Using the ExecutorService got the load time down from 2:31 to 0:35.

这篇关于JList 重绘单个元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆