在JTable单元格中渲染BufferedImage

我需要在一个JTable列中显示BufferedImage。 我覆盖了JTable方法

@Override public Class getColumnClass(int column) { if (column == 1){ return BufferedImage.class; } return super.getColumnClass(column); } 

但我仍然获得对象的字符串表示而不是图像本身。有人知道我缺少什么吗?

我将填充需要使用ImageIcons显示图像的列,并让getColumnClass()方法返回Icon.class,然后使用显示Icon的JLabel渲染它。 事实上,我相信DefaultCellRenderer确实是一个JLabel,因此它应该已经知道如何处理Icons。

是的,所有模型需要的是知道它拥有图标。 例如,以下代码适用于以下程序:

  DefaultTableModel model = new DefaultTableModel(COL_NAMES, 0) { @Override public Class getColumnClass(int column) { if (getRowCount() > 0) { return getValueAt(0, column).getClass(); } return super.getColumnClass(column); } }; 

例如:

 import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.table.DefaultTableModel; public class ImageColumnTest2 { public static final String IMAGE_SHEET_PATH = "http://speckycdn.sdm.netdna-cdn.com/" + "wp-content/uploads/2010/08/flag_icons_04.jpg"; public static final String[] COUNTRIES = { "Denmark", "China", "Chile", "Canada", "Belgium", "Austria", "Argentina", "France", "Malaysina", "Lebanon", "Korea", "Japan", "Italy", "Ireland", "India", "Hong Kong", "Greece", "Germany" }; public static final int COLS = 6; public static final int ROWS = 3; private static final String[] COL_NAMES = {"Country", "Flag"}; private JTable table = new JTable(); private JScrollPane mainPane = new JScrollPane(table); public ImageColumnTest2() throws IOException { DefaultTableModel model = new DefaultTableModel(COL_NAMES, 0) { @Override public Class getColumnClass(int column) { if (getRowCount() > 0) { return getValueAt(0, column).getClass(); } return super.getColumnClass(column); } }; URL url = new URL(IMAGE_SHEET_PATH); BufferedImage img = ImageIO.read(url); int x1 = 15; // sorry about the magic numbers img = img.getSubimage(x1, 0, img.getWidth() - 2 * x1, img.getHeight()); int y1 = 20 ; // ditto! int w = img.getWidth() / COLS; int h = img.getHeight() / ROWS; for (int row = 0; row < ROWS; row++) { int y = (row * img.getHeight()) / ROWS; for (int col = 0; col < COLS; col++) { int x = (col * img.getWidth()) / COLS; BufferedImage subImg = img.getSubimage(x, y, w, h); subImg = subImg.getSubimage(x1, 0, subImg.getWidth() - 2 * x1, subImg.getHeight() - y1); ImageIcon icon = new ImageIcon(subImg); String country = COUNTRIES[col + row * COLS]; Object[] rowData = {country, icon}; model.addRow(rowData); } } table.setModel(model); table.setRowHeight(((ImageIcon)model.getValueAt(0, 1)).getIconHeight()); } public JComponent getMainComponent() { return mainPane; } private static void createAndShowGui() { ImageColumnTest2 imgColumnTest = null; try { imgColumnTest = new ImageColumnTest2(); } catch (MalformedURLException e) { e.printStackTrace(); System.exit(-1); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } JFrame frame = new JFrame("ImageColumnTest"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(imgColumnTest.getMainComponent()); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } } 

BufferedImage没有默认的TableCellRenderer ,你将不得不提供一个

创建一个从DefaultTableCellRenderer扩展的新类。 重写getTableCellRendererComponent方法

在这个方法中,检查传入的值是否为BufferedImage ,如果是,则创建一个ImageIcon实例,将BufferedImage传递给它。

使用cell setIcon方法,将ImageIcon的新实例传递给它

使用表实例,使用setDefaultRenderer方法将单元格渲染器与BufferedImage类相关联

 table.setDefaultRenderer(BufferedImage.class, myInstanceOfBufferedImageCellRenderer) 

有关详细信息,请查看使用自定义渲染器

添加了示例

因此,我使用自己和气垫船的想法一起提出了一个快速的例子。

在此处输入图像描述

我个人认为,只要为每个BufferedImage创建一次ImageIcon并维护该引用,Hovercraft的想法将使用更少的资源并且更快地使用单元重新加载器。

您可以让自定义单元格渲染器执行相同的操作,但您需要使用WeakHashMap来维护BufferedImageIcon之间的引用,并且仍然存在永远不会收集相关BufferedImage的风险,留下Icon参考闲逛。

如果你没有以渲染的方式对BufferedImage做任何特别的事情,我会使用Hovercraft的建议,从易用性和资源管理的角度来看。

 public class BufferedImageTableCellRenderer { public static void main(String[] args) { new BufferedImageTableCellRenderer(); } public BufferedImageTableCellRenderer() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } File[] files = new File("some folder some where").listFiles(new FileFilter() { @Override public boolean accept(File pathname) { String name = pathname.getName().toLowerCase(); return name.endsWith(".gif") || name.endsWith(".jpg") || name.endsWith(".png"); } }); ImageTableModel model = new ImageTableModel(); for (File file : files) { try { model.add(ImageIO.read(file)); } catch (IOException ex) { ex.printStackTrace(); } } JTable table = new JTable(model); table.setRowHeight(100); table.setDefaultRenderer(BufferedImage.class, new BufferedImageCellRenderer()); JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new JScrollPane(table)); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class BufferedImageCellRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (value instanceof BufferedImage) { setIcon(new ImageIcon((BufferedImage)value)); setText(null); } else { setText("Bad image"); } return this; } } public class ImageTableModel extends AbstractTableModel { private List images = new ArrayList<>(25); private List icons = new ArrayList<>(25); @Override public int getRowCount() { return images.size(); } public void add(BufferedImage image) { images.add(image); icons.add(new ImageIcon(image)); fireTableRowsInserted(images.size() - 1, images.size() - 1); } @Override public int getColumnCount() { return 2; } @Override public Object getValueAt(int rowIndex, int columnIndex) { Object value = null; switch (columnIndex) { case 0: value = images.get(rowIndex); break; case 1: value = icons.get(rowIndex); break; } return value; } @Override public Class getColumnClass(int columnIndex) { Class clazz = String.class; switch (columnIndex) { case 0: clazz = BufferedImage.class; break; case 1: clazz = Icon.class; break; } return clazz; } @Override public String getColumnName(int column) { String name = null; switch (column) { case 0: name = "BufferedImage"; break; case 1: name = "Icon"; break; } return name; } } }