在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
来维护BufferedImage
和Icon
之间的引用,并且仍然存在永远不会收集相关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; } } }