ToolTip Table
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall */ import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.text.NumberFormat; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; public class ToolTipTable { public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} JFrame f = new JFrame("Tool Tip Table"); JTable tbl = new JTable(new CurrencyTableModel()); tbl .setDefaultRenderer(java.lang.Number.class, new ToolTipFractionCellRenderer(10, 3, 6, SwingConstants.RIGHT)); TableColumnModel tcm = tbl.getColumnModel(); tcm.getColumn(0).setPreferredWidth(150); tcm.getColumn(0).setMinWidth(150); TextWithIconCellRenderer renderer = new TextWithIconCellRenderer(); tcm.getColumn(0).setCellRenderer(renderer); tcm.getColumn(1).setPreferredWidth(100); tcm.getColumn(1).setMinWidth(100); // Add the stripe renderer. StripedTableCellRenderer.installInTable(tbl, Color.lightGray, Color.white, null, null); // Add the custom header renderer MultiLineHeaderRenderer headerRenderer = new MultiLineHeaderRenderer( SwingConstants.CENTER, SwingConstants.BOTTOM); headerRenderer.setBackground(Color.blue); headerRenderer.setForeground(Color.white); headerRenderer.setFont(new Font("Dialog", Font.BOLD, 12)); int columns = tableHeaders.length; for (int i = 0; i < columns; i++) { tcm.getColumn(i).setHeaderRenderer(headerRenderer); tcm.getColumn(i).setHeaderValue(tableHeaders[i]); } tbl.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); tbl.setPreferredScrollableViewportSize(tbl.getPreferredSize()); JScrollPane sp = new JScrollPane(tbl); f.getContentPane().add(sp, "Center"); f.pack(); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); f.setVisible(true); } // Header values. Note the table model provides // string column names that are the default header // values. public static Object[][] tableHeaders = new Object[][] { new String[] { "Currency" }, new String[] { "Yesterday's", "Rate" }, new String[] { "Today's", "Rate" }, new String[] { "Rate", "Change" } }; } class FractionCellRenderer extends DefaultTableCellRenderer { public FractionCellRenderer(int integer, int fraction, int align) { this.integer = integer; // maximum integer digits this.fraction = fraction; // exact number of fraction digits this.align = align; // alignment (LEFT, CENTER, RIGHT) } protected void setValue(Object value) { if (value != null && value instanceof Number) { formatter.setMaximumIntegerDigits(integer); formatter.setMaximumFractionDigits(fraction); formatter.setMinimumFractionDigits(fraction); setText(formatter.format(((Number) value).doubleValue())); } else { super.setValue(value); } setHorizontalAlignment(align); } protected int integer; protected int fraction; protected int align; protected static NumberFormat formatter = NumberFormat.getInstance(); } class TextWithIconCellRenderer extends DefaultTableCellRenderer { protected void setValue(Object value) { if (value instanceof DataWithIcon) { if (value != null) { DataWithIcon d = (DataWithIcon) value; Object dataValue = d.getData(); setText(dataValue == null ? "" : dataValue.toString()); setIcon(d.getIcon()); setHorizontalTextPosition(SwingConstants.RIGHT); setVerticalTextPosition(SwingConstants.CENTER); setHorizontalAlignment(SwingConstants.LEFT); setVerticalAlignment(SwingConstants.CENTER); } else { setText(""); setIcon(null); } } else { super.setValue(value); } } } class MultiLineHeaderRenderer extends JPanel implements TableCellRenderer { public MultiLineHeaderRenderer(int horizontalAlignment, int verticalAlignment) { this.horizontalAlignment = horizontalAlignment; this.verticalAlignment = verticalAlignment; switch (horizontalAlignment) { case SwingConstants.LEFT: alignmentX = (float) 0.0; break; case SwingConstants.CENTER: alignmentX = (float) 0.5; break; case SwingConstants.RIGHT: alignmentX = (float) 1.0; break; default: throw new IllegalArgumentException( "Illegal horizontal alignment value"); } setBorder(headerBorder); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); setOpaque(true); background = null; } public void setForeground(Color foreground) { this.foreground = foreground; super.setForeground(foreground); } public void setBackground(Color background) { this.background = background; super.setBackground(background); } public void setFont(Font font) { this.font = font; } // Implementation of TableCellRenderer interface public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { removeAll(); invalidate(); if (value == null) { // Do nothing if no value return this; } // Set the foreground and background colors // from the table header if they are not set if (table != null) { JTableHeader header = table.getTableHeader(); if (header != null) { if (foreground == null) { super.setForeground(header.getForeground()); } if (background == null) { super.setBackground(header.getBackground()); } } } if (verticalAlignment != SwingConstants.TOP) { add(Box.createVerticalGlue()); } Object[] values; int length; if (value instanceof Object[]) { // Input is an array - use it values = (Object[]) value; } else { // Not an array - turn it into one values = new Object[1]; values[0] = value; } length = values.length; // Configure each row of the header using // a separate JLabel. If a given row is // a JComponent, add it directly.. for (int i = 0; i < length; i++) { Object thisRow = values[i]; if (thisRow instanceof JComponent) { add((JComponent) thisRow); } else { JLabel l = new JLabel(); setValue(l, thisRow, i); add(l); } } if (verticalAlignment != SwingConstants.BOTTOM) { add(Box.createVerticalGlue()); } return this; } // Configures a label for one line of the header. // This can be overridden by derived classes protected void setValue(JLabel l, Object value, int lineNumber) { if (value != null && value instanceof Icon) { l.setIcon((Icon) value); } else { l.setText(value == null ? "" : value.toString()); } l.setHorizontalAlignment(horizontalAlignment); l.setAlignmentX(alignmentX); l.setOpaque(false); l.setForeground(foreground); l.setFont(font); } protected int verticalAlignment; protected int horizontalAlignment; protected float alignmentX; // These attributes may be explicitly set // They are defaulted to the colors and attributes // of the table header protected Color foreground; protected Color background; // These attributes have fixed defaults protected Border headerBorder = UIManager .getBorder("TableHeader.cellBorder"); protected Font font = UIManager.getFont("TableHeader.font"); } class DataWithIcon { public DataWithIcon(Object data, Icon icon) { this.data = data; this.icon = icon; } public Icon getIcon() { return icon; } public Object getData() { return data; } public String toString() { return data.toString(); } protected Icon icon; protected Object data; } class CurrencyTableModel extends AbstractTableModel { protected String[] columnNames = { "Currency", "Yesterday", "Today", "Change" }; // Constructor: calculate currency change to create the last column public CurrencyTableModel() { for (int i = 0; i < data.length; i++) { data[i][DIFF_COLUMN] = new Double( ((Double) data[i][NEW_RATE_COLUMN]).doubleValue() - ((Double) data[i][OLD_RATE_COLUMN]).doubleValue()); } } // Implementation of TableModel interface public int getRowCount() { return data.length; } public int getColumnCount() { return COLUMN_COUNT; } public Object getValueAt(int row, int column) { return data[row][column]; } public Class getColumnClass(int column) { return (data[0][column]).getClass(); } public String getColumnName(int column) { return columnNames[column]; } protected static final int OLD_RATE_COLUMN = 1; protected static final int NEW_RATE_COLUMN = 2; protected static final int DIFF_COLUMN = 3; protected static final int COLUMN_COUNT = 4; protected static final Class thisClass = CurrencyTableModel.class; protected Object[][] data = new Object[][] { { new DataWithIcon("Belgian Franc", new ImageIcon(thisClass .getResource("belgium.gif"))), new Double(37.6460110), new Double(37.6508921), null }, { new DataWithIcon("British Pound", new ImageIcon(thisClass .getResource("gb.gif"))), new Double(0.6213051), new Double(0.6104102), null }, { new DataWithIcon("Canadian Dollar", new ImageIcon(thisClass .getResource("canada.gif"))), new Double(1.4651209), new Double(1.5011104), null }, { new DataWithIcon("French Franc", new ImageIcon(thisClass .getResource("france.gif"))), new Double(6.1060001), new Double(6.0100101), null }, { new DataWithIcon("Italian Lire", new ImageIcon(thisClass .getResource("italy.gif"))), new Double(1181.3668977), new Double(1182.104), null }, { new DataWithIcon("German Mark", new ImageIcon(thisClass .getResource("germany.gif"))), new Double(1.8191804), new Double(1.8223421), null }, { new DataWithIcon("Japanese Yen", new ImageIcon(thisClass .getResource("japan.gif"))), new Double(141.0815412), new Double(121.0040432), null } }; } class ToolTipFractionCellRenderer extends FractionCellRenderer { public ToolTipFractionCellRenderer(int integer, int fraction, int maxFraction, int align) { super(integer, fraction, align); this.maxFraction = maxFraction; // Number of tooltip fraction digits } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (value != null && value instanceof Number) { formatter.setMaximumIntegerDigits(integer); formatter.setMaximumFractionDigits(maxFraction); formatter.setMinimumFractionDigits(maxFraction); ((JComponent) comp).setToolTipText(formatter .format(((Number) value).doubleValue())); } return comp; } protected int maxFraction; } class StripedTableCellRenderer implements TableCellRenderer { public StripedTableCellRenderer(TableCellRenderer targetRenderer, Color evenBack, Color evenFore, Color oddBack, Color oddFore) { this.targetRenderer = targetRenderer; this.evenBack = evenBack; this.evenFore = evenFore; this.oddBack = oddBack; this.oddFore = oddFore; } // Implementation of TableCellRenderer interface public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { TableCellRenderer renderer = targetRenderer; if (renderer == null) { // Get default renderer from the table renderer = table.getDefaultRenderer(table.getColumnClass(column)); } // Let the real renderer create the component Component comp = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); // Now apply the stripe effect if (isSelected == false && hasFocus == false) { if ((row & 1) == 0) { comp.setBackground(evenBack != null ? evenBack : table .getBackground()); comp.setForeground(evenFore != null ? evenFore : table .getForeground()); } else { comp.setBackground(oddBack != null ? oddBack : table .getBackground()); comp.setForeground(oddFore != null ? oddFore : table .getForeground()); } } return comp; } // Convenience method to apply this renderer to single column public static void installInColumn(JTable table, int columnIndex, Color evenBack, Color evenFore, Color oddBack, Color oddFore) { TableColumn tc = table.getColumnModel().getColumn(columnIndex); // Get the cell renderer for this column, if any TableCellRenderer targetRenderer = tc.getCellRenderer(); // Create a new StripedTableCellRenderer and install it tc.setCellRenderer(new StripedTableCellRenderer(targetRenderer, evenBack, evenFore, oddBack, oddFore)); } // Convenience method to apply this renderer to an entire table public static void installInTable(JTable table, Color evenBack, Color evenFore, Color oddBack, Color oddFore) { StripedTableCellRenderer sharedInstance = null; int columns = table.getColumnCount(); for (int i = 0; i < columns; i++) { TableColumn tc = table.getColumnModel().getColumn(i); TableCellRenderer targetRenderer = tc.getCellRenderer(); if (targetRenderer != null) { // This column has a specific renderer tc.setCellRenderer(new StripedTableCellRenderer(targetRenderer, evenBack, evenFore, oddBack, oddFore)); } else { // This column uses a class renderer - use a shared renderer if (sharedInstance == null) { sharedInstance = new StripedTableCellRenderer(null, evenBack, evenFore, oddBack, oddFore); } tc.setCellRenderer(sharedInstance); } } } protected TableCellRenderer targetRenderer; protected Color evenBack; protected Color evenFore; protected Color oddBack; protected Color oddFore; }