Having multi-font cells in a JTable

Courtesy of Nobuo Tamemasa (http://www2.gol.com/users/tame/swing/examples/JTableExamples1.html)



MultiFontCellTableExample.java:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.border.*;
 
/**
 * @version 1.0 11/22/98
 */
public class MultiFontCellTableExample extends JFrame {
 
  public MultiFontCellTableExample() {
    super( "Multi-Font Cell Example" ); 
     
    AttributiveCellTableModel ml = new AttributiveCellTableModel(8,3);
    CellFont cellAtt =(CellFont)ml.getCellAttribute();
    JTable table = new JTable( ml );
    table.setRowHeight(26);
    table.setCellSelectionEnabled(true);
    table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
    table.setDefaultRenderer(Object.class ,new AttributiveCellRenderer());
    JScrollPane scroll = new JScrollPane( table );
 
    FontPanel fontPanel = new FontPanel(table, cellAtt);
    
    Box box = new Box(BoxLayout.X_AXIS);
    box.add(scroll);
    box.add(new JSeparator(SwingConstants.HORIZONTAL));
    box.add(fontPanel);
    getContentPane().add( box );
    setSize( 400, 200 );
    setVisible(true);
  }
 
  class FontPanel extends JPanel {
    String[] str_size  = {"10","12","14","16","20","24"};
    String[] str_style = {"PLAIN","BOLD","ITALIC"};
    JComboBox name,style,size;
 
    FontPanel(final JTable table, final CellFont cellAtt) {
      setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
      Box box = new Box(BoxLayout.X_AXIS);
      JPanel p2 = new JPanel(new GridLayout(3,1));
      JPanel p3 = new JPanel(new GridLayout(3,1));
      JPanel p4 = new JPanel(new FlowLayout());
      p2.add(new JLabel("Name:"));
      p2.add(new JLabel("Style:"));    
      p2.add(new JLabel("Size:"));
      Toolkit toolkit = Toolkit.getDefaultToolkit();
      name  = new JComboBox(toolkit.getFontList());
      style = new JComboBox(str_style);
      size  = new JComboBox(str_size);
      size.setEditable(true);
      JButton b_apply   = new JButton("Apply");
      b_apply.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          int[] columns = table.getSelectedColumns();
          int[] rows    = table.getSelectedRows();
          if ((rows == null) || (columns == null)) return;
          if ((rows.length<1)||(columns.length<1)) return;
          Font font = new Font((String)name.getSelectedItem(),
                              style.getSelectedIndex(),
              Integer.parseInt((String)size.getSelectedItem()));
          cellAtt.setFont(font, rows, columns);
          table.clearSelection();
          table.revalidate();
          table.repaint();        
        }
      });
      p3.add(name);
      p3.add(style);
      p3.add(size);
      p4.add(b_apply);
      box.add(p2);
      box.add(p3);
      add(box);
      add(p4);
    }
  }
   
  public static void main(String[] args) {
    MultiFontCellTableExample frame = new MultiFontCellTableExample();
    frame.addWindowListener( new WindowAdapter() {
      public void windowClosing( WindowEvent e ) {
        System.exit(0);
      }
    });
  }
}

AttributiveCellTableModel.java:

import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
 
 
/**
 * @version 1.0 11/22/98
 */
 
public class AttributiveCellTableModel extends DefaultTableModel {
 
  protected CellAttribute cellAtt;
    
  public AttributiveCellTableModel() {
    this((Vector)null, 0);
  }
  public AttributiveCellTableModel(int numRows, int numColumns) {
    Vector names = new Vector(numColumns);
    names.setSize(numColumns);
    setColumnIdentifiers(names);
    dataVector = new Vector();
    setNumRows(numRows);
    cellAtt = new DefaultCellAttribute(numRows,numColumns);
  }
  public AttributiveCellTableModel(Vector columnNames, int numRows) {
    setColumnIdentifiers(columnNames);
    dataVector = new Vector();
    setNumRows(numRows);
    cellAtt = new DefaultCellAttribute(numRows,columnNames.size());
  }
  public AttributiveCellTableModel(Object[] columnNames, int numRows) {
    this(convertToVector(columnNames), numRows);
  }  
  public AttributiveCellTableModel(Vector data, Vector columnNames) {
    setDataVector(data, columnNames);
  }
  public AttributiveCellTableModel(Object[][] data, Object[] columnNames) {
    setDataVector(data, columnNames);
  }
 
     
  public void setDataVector(Vector newData, Vector columnNames) {
    if (newData == null)
      throw new IllegalArgumentException("setDataVector() - Null parameter");
    dataVector = new Vector(0);
    setColumnIdentifiers(columnNames);
    dataVector = newData;
    
    //
    cellAtt = new DefaultCellAttribute(dataVector.size(),
                                       columnIdentifiers.size());
    
    newRowsAdded(new TableModelEvent(this, 0, getRowCount()-1,
                 TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
  }
 
  public void addColumn(Object columnName, Vector columnData) {
    if (columnName == null)
      throw new IllegalArgumentException("addColumn() - null parameter");
    columnIdentifiers.addElement(columnName);
    int index = 0;
    Enumeration enumeration = dataVector.elements();
    while (enumeration.hasMoreElements()) {
      Object value;
      if ((columnData != null) && (index < columnData.size()))
          value = columnData.elementAt(index);
      else
        value = null;
      ((Vector)enumeration.nextElement()).addElement(value);
      index++;
    }
 
    //
    cellAtt.addColumn();
 
    fireTableStructureChanged();
  }
 
  public void addRow(Vector rowData) {
    Vector newData = null;
    if (rowData == null) {
      newData = new Vector(getColumnCount());
    }
    else {
      rowData.setSize(getColumnCount());
    }
    dataVector.addElement(newData);
 
    //
    cellAtt.addRow();
 
    newRowsAdded(new TableModelEvent(this, getRowCount()-1, getRowCount()-1,
       TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
  }
 
  public void insertRow(int row, Vector rowData) {
    if (rowData == null) {
      rowData = new Vector(getColumnCount());
    }
    else {
      rowData.setSize(getColumnCount());
    }
 
    dataVector.insertElementAt(rowData, row);
 
    //
    cellAtt.insertRow(row);
 
    newRowsAdded(new TableModelEvent(this, row, row,
       TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
  }
 
  public CellAttribute getCellAttribute() {
    return cellAtt;
  }
 
  public void setCellAttribute(CellAttribute newCellAtt) {
    int numColumns = getColumnCount();
    int numRows    = getRowCount();
    if ((newCellAtt.getSize().width  != numColumns) ||
        (newCellAtt.getSize().height != numRows)) {
      newCellAtt.setSize(new Dimension(numRows, numColumns));
    }
    cellAtt = newCellAtt;
    fireTableDataChanged();
  }
 
  /*
  public void changeCellAttribute(int row, int column, Object command) {
    cellAtt.changeAttribute(row, column, command);
  }
 
  public void changeCellAttribute(int[] rows, int[] columns, Object command) {
    cellAtt.changeAttribute(rows, columns, command);
  }
  */
     
}

DefaultCellAttribute.java:

import java.awt.*;
 
/** 
 * @version 1.0 11/22/98
 */
 
public class DefaultCellAttribute 
//    implements CellAttribute ,CellSpan  {
      implements CellAttribute ,CellSpan ,ColoredCell ,CellFont {

  //
  // !!!! CAUTION !!!!!
  // these values must be synchronized to Table data
  //
  protected int rowSize;
  protected int columnSize;
  protected int[][][] span;                   // CellSpan
  protected Color[][] foreground;             // ColoredCell
  protected Color[][] background;             //
  protected Font[][]  font;                   // CellFont
   
  public DefaultCellAttribute() {
    this(1,1);
  }
   
  public DefaultCellAttribute(int numRows, int numColumns) {
    setSize(new Dimension(numColumns, numRows));
  }
 
  protected void initValue() {
    for(int i=0; i<span.length;i++) {
      for(int j=0; j<span[i].length; j++) {
        span[i][j][CellSpan.COLUMN] = 1;
        span[i][j][CellSpan.ROW]    = 1;
      }
    }
  }
 
 
  //
  // CellSpan
  //
  public int[] getSpan(int row, int column) {
    if (isOutOfBounds(row, column)) {
      int[] ret_code = {1,1};
      return ret_code;
    }
    return span[row][column];
  }
 
  public void setSpan(int[] span, int row, int column) {
    if (isOutOfBounds(row, column)) return;
    this.span[row][column] = span;
  }
       
  public boolean isVisible(int row, int column) {
    if (isOutOfBounds(row, column)) return false;
    if ((span[row][column][CellSpan.COLUMN] < 1)
      ||(span[row][column][CellSpan.ROW]    < 1)) return false;
    return true;
  }
 
  public void combine(int[] rows, int[] columns) {
    if (isOutOfBounds(rows, columns)) return;
    int    rowSpan  = rows.length;
    int columnSpan  = columns.length;
    int startRow    = rows[0];
    int startColumn = columns[0];
    for (int i=0;i<rowSpan;i++) {
      for (int j=0;j<columnSpan;j++) {
        if ((span[startRow +i][startColumn +j][CellSpan.COLUMN] != 1)
          ||(span[startRow +i][startColumn +j][CellSpan.ROW]    != 1)) {
          //System.out.println("can't combine");
          return ;
        }
      }
    }
    for (int i=0,ii=0;i<rowSpan;i++,ii--) {
      for (int j=0,jj=0;j<columnSpan;j++,jj--) {
        span[startRow +i][startColumn +j][CellSpan.COLUMN] = jj;
        span[startRow +i][startColumn +j][CellSpan.ROW]    = ii;
        //System.out.println("r " +ii +"  c " +jj);
      }
    }
    span[startRow][startColumn][CellSpan.COLUMN] = columnSpan;
    span[startRow][startColumn][CellSpan.ROW]    =    rowSpan;
    
  }
 
  public void split(int row, int column) {
    if (isOutOfBounds(row, column)) return;
    int columnSpan = span[row][column][CellSpan.COLUMN];
    int    rowSpan = span[row][column][CellSpan.ROW];
    for (int i=0;i<rowSpan;i++) {
      for (int j=0;j<columnSpan;j++) {
        span[row +i][column +j][CellSpan.COLUMN] = 1;
        span[row +i][column +j][CellSpan.ROW]    = 1;
      }
    }
  }
 
 
  //
  // ColoredCell
  //
  public Color getForeground(int row, int column) {
    if (isOutOfBounds(row, column)) return null;
    return foreground[row][column];
  }
  public void setForeground(Color color, int row, int column) {
    if (isOutOfBounds(row, column)) return;
    foreground[row][column] = color;
  }
  public void setForeground(Color color, int[] rows, int[] columns) {
    if (isOutOfBounds(rows, columns)) return;
    setValues(foreground, color, rows, columns);
  }
  public Color getBackground(int row, int column) {
    if (isOutOfBounds(row, column)) return null;
    return background[row][column];
  }
  public void setBackground(Color color, int row, int column) {
    if (isOutOfBounds(row, column)) return;
    background[row][column] = color;
  }
  public void setBackground(Color color, int[] rows, int[] columns) {
    if (isOutOfBounds(rows, columns)) return;
    setValues(background, color, rows, columns);
  }
  //
 
 
  //
  // CellFont
  //
  public Font getFont(int row, int column) {
    if (isOutOfBounds(row, column)) return null;
    return font[row][column];
  }
  public void setFont(Font font, int row, int column) {
    if (isOutOfBounds(row, column)) return;
    this.font[row][column] = font;
  }
  public void setFont(Font font, int[] rows, int[] columns) {
    if (isOutOfBounds(rows, columns)) return;
    setValues(this.font, font, rows, columns);
  }
  // 
 
 
  //
  // CellAttribute
  //
  public void addColumn() {
    int[][][] oldSpan = span;
    int numRows    = oldSpan.length;
    int numColumns = oldSpan[0].length;
    span = new int[numRows][numColumns + 1][2];
    System.arraycopy(oldSpan,0,span,0,numRows);
    for (int i=0;i<numRows;i++) {
      span[i][numColumns][CellSpan.COLUMN] = 1;
      span[i][numColumns][CellSpan.ROW]    = 1;
    }
  }
 
  public void addRow() {
    int[][][] oldSpan = span;
    int numRows    = oldSpan.length;
    int numColumns = oldSpan[0].length;
    span = new int[numRows + 1][numColumns][2];
    System.arraycopy(oldSpan,0,span,0,numRows);
    for (int i=0;i<numColumns;i++) {
      span[numRows][i][CellSpan.COLUMN] = 1;
      span[numRows][i][CellSpan.ROW]    = 1;
    }
  }
 
  public void insertRow(int row) {
    int[][][] oldSpan = span;
    int numRows    = oldSpan.length;
    int numColumns = oldSpan[0].length;
    span = new int[numRows + 1][numColumns][2];
    if (0 < row) {
      System.arraycopy(oldSpan,0,span,0,row-1);
    }
    System.arraycopy(oldSpan,0,span,row,numRows - row);
    for (int i=0;i<numColumns;i++) {
      span[row][i][CellSpan.COLUMN] = 1;
      span[row][i][CellSpan.ROW]    = 1;
    }
  }
 
  public Dimension getSize() {
    return new Dimension(rowSize, columnSize);
  }
 
  public void setSize(Dimension size) {
    columnSize = size.width;
    rowSize    = size.height;
    span = new int[rowSize][columnSize][2];   // 2: COLUMN,ROW
    foreground = new Color[rowSize][columnSize];
    background = new Color[rowSize][columnSize];
    font = new Font[rowSize][columnSize];
    initValue();
  }
 
  /*
  public void changeAttribute(int row, int column, Object command) {
  }
 
  public void changeAttribute(int[] rows, int[] columns, Object command) {
  }
  */
 
  protected boolean isOutOfBounds(int row, int column) {
    if ((row    < 0)||(rowSize    <= row)
      ||(column < 0)||(columnSize <= column)) {
      return true;
    }
    return false;
  }
 
  protected boolean isOutOfBounds(int[] rows, int[] columns) {
    for (int i=0;i<rows.length;i++) {
      if ((rows[i] < 0)||(rowSize <= rows[i])) return true;
    }
    for (int i=0;i<columns.length;i++) {
      if ((columns[i] < 0)||(columnSize <= columns[i])) return true;
    }
    return false;
  }
 
  protected void setValues(Object[][] target, Object value,
                           int[] rows, int[] columns) {
    for (int i=0;i<rows.length;i++) {
      int row = rows[i];
      for (int j=0;j<columns.length;j++) {
        int column = columns[j];
        target[row][column] = value;
      }
    }
  }
}

CellAttribute.java:

import java.awt.*;

/**
 * @version 1.0 11/22/98
 */

public interface CellAttribute {
  public void addColumn();
  public void addRow();
  public void insertRow(int row);
  public Dimension getSize();
  public void setSize(Dimension size);
}

ColoredCell.java:

import java.awt.*;
 
/**
 * @version 1.0 11/22/98
 */
 
public interface ColoredCell {
   
  public Color getForeground(int row, int column);
  public void setForeground(Color color, int row, int column);
  public void setForeground(Color color, int[] rows, int[] columns);
  public Color getBackground(int row, int column);
  public void setBackground(Color color, int row, int column);
  public void setBackground(Color color, int[] rows, int[] columns);
}

CellFont.java:

/*
 * (swing1.1beta3)
 * 
 */
 
import java.awt.*;
 
/**
 * @version 1.0 11/22/98
 */
 
public interface CellFont {
  public Font getFont(int row, int column);
  public void setFont(Font font, int row, int column);
  public void setFont(Font font, int[] rows, int[] columns);
}

CellSpan.java:

/*
 * (swing1.1beta3)
 * 
 */
 
/**
 * @version 1.0 11/22/98
 */
 
public interface CellSpan {
  public final int ROW    = 0;
  public final int COLUMN = 1;
   
  public int[] getSpan(int row, int column);
  public void setSpan(int[] span, int row, int column);
   
  public boolean isVisible(int row, int column);
 
  public void combine(int[] rows, int[] columns);
  public void split(int row, int column);
}

MultiSpanCellTable.java:

import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.plaf.basic.*;
import javax.swing.event.*;
 
/**
 * @version 1.0 11/26/98
 */
 
public class MultiSpanCellTable extends JTable {
 
  public MultiSpanCellTable(TableModel model) {
    super(model);
    setUI(new MultiSpanCellTableUI());
    getTableHeader().setReorderingAllowed(false);
    setCellSelectionEnabled(true);
    setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
  }
   
  public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
    Rectangle sRect = super.getCellRect(row,column,includeSpacing);
    if ((row <0) || (column<0) ||
        (getRowCount() <= row) || (getColumnCount() <= column)) {
        return sRect;
    }
    CellSpan cellAtt = (CellSpan)((AttributiveCellTableModel)getModel()).getCellAttribute();
    if (! cellAtt.isVisible(row,column)) {
      int temp_row    = row;
      int temp_column = column;
      row    += cellAtt.getSpan(temp_row,temp_column)[CellSpan.ROW];
      column += cellAtt.getSpan(temp_row,temp_column)[CellSpan.COLUMN];      
    }
    int[] n = cellAtt.getSpan(row,column);
 
    int index = 0;
    int columnMargin = getColumnModel().getColumnMargin();
    Rectangle cellFrame = new Rectangle();
    int aCellHeight = rowHeight + rowMargin;
    cellFrame.y = row * aCellHeight;
    cellFrame.height = n[CellSpan.ROW] * aCellHeight;
     
    Enumeration enumeration = getColumnModel().getColumns();
    while (enumeration.hasMoreElements()) {
      TableColumn aColumn = (TableColumn)enumeration.nextElement();
      cellFrame.width = aColumn.getWidth() + columnMargin;
      if (index == column) break;
      cellFrame.x += cellFrame.width;
      index++;
    }
    for (int i=0;i< n[CellSpan.COLUMN]-1;i++) {
      TableColumn aColumn = (TableColumn)enumeration.nextElement();
      cellFrame.width += aColumn.getWidth() + columnMargin;
    }
     
    if (!includeSpacing) {
      Dimension spacing = getIntercellSpacing();
      cellFrame.setBounds(cellFrame.x +      spacing.width/2,
                          cellFrame.y +      spacing.height/2,
                          cellFrame.width -  spacing.width,
                          cellFrame.height - spacing.height);
    }
    return cellFrame;
  }
   
   
  private int[] rowColumnAtPoint(Point point) {
    int[] retValue = {-1,-1};
    int row = point.y / (rowHeight + rowMargin);
    if ((row <0)||(getRowCount() <= row)) return retValue;
    int column = getColumnModel().getColumnIndexAtX(point.x);
 
    CellSpan cellAtt = (CellSpan)((AttributiveCellTableModel)getModel()).getCellAttribute();
 
    if (cellAtt.isVisible(row,column)) {
      retValue[CellSpan.COLUMN] = column;
      retValue[CellSpan.ROW   ] = row;
      return retValue;
    }
    retValue[CellSpan.COLUMN] = column + cellAtt.getSpan(row,column)[CellSpan.COLUMN];
    retValue[CellSpan.ROW   ] = row + cellAtt.getSpan(row,column)[CellSpan.ROW];
    return retValue;
  }
 
   
  public int rowAtPoint(Point point) {
    return rowColumnAtPoint(point)[CellSpan.ROW];
  }
 
  public int columnAtPoint(Point point) {
    return rowColumnAtPoint(point)[CellSpan.COLUMN];
  }
  
  public void columnSelectionChanged(ListSelectionEvent e) {
    repaint();
  }
 
  public void valueChanged(ListSelectionEvent e) {
    int firstIndex = e.getFirstIndex();
    int  lastIndex = e.getLastIndex();
    if (firstIndex == -1 && lastIndex == -1) { // Selection cleared.
      repaint();
    }
    Rectangle dirtyRegion = getCellRect(firstIndex, 0, false);
    int numCoumns = getColumnCount();
    int index = firstIndex;
    for (int i=0;i<numCoumns;i++) {
      dirtyRegion.add(getCellRect(index, i, false));
    }
    index = lastIndex;
    for (int i=0;i<numCoumns;i++) {
      dirtyRegion.add(getCellRect(index, i, false));
    }
    repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
  }
  
}

MultiSpanCellTableUI.java:

import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.plaf.basic.*;
 
/**
 * @version 1.0 11/26/98
 */
 
public class MultiSpanCellTableUI extends BasicTableUI {
 
  public void paint(Graphics g, JComponent c) {
    Rectangle oldClipBounds = g.getClipBounds();
    Rectangle clipBounds    = new Rectangle(oldClipBounds);
    int tableWidth   = table.getColumnModel().getTotalColumnWidth();
    clipBounds.width = Math.min(clipBounds.width, tableWidth);
    g.setClip(clipBounds);
 
    int firstIndex = table.rowAtPoint(new Point(0, clipBounds.y));
    int  lastIndex = table.getRowCount()-1;
 
    Rectangle rowRect = new Rectangle(0,0,
      tableWidth, table.getRowHeight() + table.getRowMargin());
    rowRect.y = firstIndex*rowRect.height;
 
    for (int index = firstIndex; index <= lastIndex; index++) {
      if (rowRect.intersects(clipBounds)) {
        //System.out.println();                  // debug
        //System.out.print("" + index +": ");    // row
        paintRow(g, index);
      }
      rowRect.y += rowRect.height;
    }
    g.setClip(oldClipBounds);
  }
 
  private void paintRow(Graphics g, int row) {
    Rectangle rect = g.getClipBounds();
    boolean drawn  = false;
    
    AttributiveCellTableModel tableModel = (AttributiveCellTableModel)table.getModel();
    CellSpan cellAtt = (CellSpan)tableModel.getCellAttribute();
    int numColumns = table.getColumnCount();
 
    for (int column = 0; column < numColumns; column++) {
      Rectangle cellRect = table.getCellRect(row,column,true);
      int cellRow,cellColumn;
      if (cellAtt.isVisible(row,column)) {
        cellRow    = row;
        cellColumn = column;
          //  System.out.print("   "+column+" ");  // debug
      } else {
        cellRow    = row + cellAtt.getSpan(row,column)[CellSpan.ROW];
        cellColumn = column + cellAtt.getSpan(row,column)[CellSpan.COLUMN];
          //  System.out.print("  ("+column+")");  // debug
      }
      if (cellRect.intersects(rect)) {
        drawn = true;
        paintCell(g, cellRect, cellRow, cellColumn);
      } else {
        if (drawn) break;
      } 
    }
 
  }
 
  private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {
    int spacingHeight = table.getRowMargin();
    int spacingWidth  = table.getColumnModel().getColumnMargin();
 
    Color c = g.getColor();
    g.setColor(table.getGridColor());
    g.drawRect(cellRect.x,cellRect.y,cellRect.width-1,cellRect.height-1);
    g.setColor(c);
 
    cellRect.setBounds(cellRect.x + spacingWidth/2, cellRect.y + spacingHeight/2,
                       cellRect.width - spacingWidth, cellRect.height - spacingHeight);
 
    if (table.isEditing() && table.getEditingRow()==row &&
        table.getEditingColumn()==column) {
      Component component = table.getEditorComponent();
      component.setBounds(cellRect);
      component.validate();
    }
    else {
      TableCellRenderer renderer = table.getCellRenderer(row, column);
      Component component = table.prepareRenderer(renderer, row, column);

      if (component.getParent() == null) {
        rendererPane.add(component);
      }
      rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
                                  cellRect.width, cellRect.height, true);
    }
  }    
}

Programmatically selecting a JTable cell

Use setRowSelectionInterval and setColumnSelectionInterval.

Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame 
{
   public Main() {
      super("Table example, Wines from Bordeaux");
 
      Object[][] tabledata = {
            { "Chateau Meyney, St. Estephe", 	   new Integer(1994), "$18.75"},
            { "Chateau Montrose, St. Estephe", 	   new Integer(1975), "$54.25" },
            { "Chateau Gloria, St. Julien", 	   new Integer(1993), "$22.99" },
            { "Chateau Beychevelle, St. Julien",   new Integer(1970), "$61.63" },
            { "Chateau La Tour de Mons, Margeaux", new Integer(1975), "$57.03" },
            { "Chateau Brane-Cantenac, Margeaux",  new Integer(1978), "$49.92" },
      };
 
      String columnheaders[] = { "Wine", "Vintage", "Price" };
 
      JTable table = new JTable(tabledata, columnheaders);
      table.setPreferredScrollableViewportSize(new Dimension(500, 70));
      JScrollPane scrollPane = new JScrollPane(table);
 
      getContentPane().add(scrollPane);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      // programmatically select rows
      table.setRowSelectionInterval(1, 2);
      table.setColumnSelectionInterval(1, 2);
 
      pack();
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.show();
   }
}

Using skins in a Java GUI

JFrame inherits from Frame, a heavyweight component and associated with its native screen resource (peer). If the underlying operating system does not support non-rectangular shapes, a skin is not possible.
The Robot class, (come with 1.3) allows you to capture screen rectangles (method createScreenCapture). A possibility is to use JWindow and set the background image with the data you get from the Robot class. Then add a MouseMotionListener, intercept the mouseDragged event and update the background of your JWindow.
You may want to look at the following sites:

http://www.enteract.com/~grieves/ which does some fancy things with the JInternalFrame
http://www.L2FProd.com/ and http://www.lookandfeel.com SkinRegion, Java irregular windows

Showing the trademark symbol in a JLabel

Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
   
public class Main extends JFrame {
   public Main() {
      getContentPane().setLayout(new FlowLayout());
 
      final JLabel label = new JLabel("Javau2122");
      getContentPane().add(label);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent event) {
            System.exit(0);   
         }      
      });
 
      pack();
   }
 
   public static void main(String[] args) {
      (new Main()).show();
   }
}

Getting the FontMetrics of all available fonts on your system?

This code will display some FontMetrics information about the font you select.

Main.java:

import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
 
public class Main extends JFrame {
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
 
      getContentPane().setLayout(new BorderLayout());
      FontRendering fr = new FontRendering();
      getContentPane().add(BorderLayout.CENTER, fr);
      getContentPane().add(BorderLayout.NORTH, new FontRenderingControls(fr));
   } 
 
   public static class FontRenderingControls extends JPanel implements ActionListener {
      FontRendering fr;
 
      public FontRenderingControls(FontRendering fr) {
         this.fr = fr;
 
         Vector v = new Vector();
         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
         Font f[] = ge.getAllFonts();
         for (int i = 0; i < f.length; i++) {
            if (f[i].canDisplayUpTo(f[i].getName()) > 0) {
               v.addElement(f[i].getName());
            }
         }      
 
         final JComboBox fontCombo = new JComboBox(v);
         add(fontCombo);
         fontCombo.addActionListener(this);
      }
 
      public void actionPerformed(ActionEvent e) {
         JComboBox fontCombo = (JComboBox) e.getSource();
         fr.font = (String) fontCombo.getSelectedItem();
         fr.repaint();
      }
   }
 
   public static class FontRendering extends JPanel {
      public String text = "Easter Island";
      public String font = "Helvetica";
 
      public void paint(Graphics g) {
         Graphics2D g2d = (Graphics2D) g;
 
         Font f = g2d.getFont();
  
         g2d.setFont(new Font(font, Font.BOLD, 36));
         g2d.drawString(text, 10, 40); 
 
         FontMetrics fm = g2d.getFontMetrics();
    
         g2d.setFont(f);
         FontMetrics fm2 = g2d.getFontMetrics();
         g2d.drawString("FontMetrics:", 10, 60);
         g2d.drawString("Ascent: "      + 
                          fm.getAscent(), 50, 60 + fm2.getHeight());
         g2d.drawString("Descent: "     + 
                          fm.getDescent(), 50, 60 + fm2.getHeight() * 2);
         g2d.drawString("Height: "      + 
                          fm.getHeight(), 50, 60 + fm2.getHeight() * 3);
         g2d.drawString("Leading: "     + 
                          fm.getLeading(), 50, 60 + fm2.getHeight() * 4);
         g2d.drawString("MaxAdvance: "  + 
                          fm.getMaxAdvance(), 50, 60 + fm2.getHeight() * 5);
         g2d.drawString("MaxAscent: "   + 
                          fm.getMaxAscent(), 50, 60 + fm2.getHeight() * 6);
         g2d.drawString("MaxDescent: "  + 
                          fm.getMaxDescent(), 50, 60 + fm2.getHeight() * 7);
      }
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setVisible(true);
      main.setSize(300, 300);
   }
}

Adding a JButton inside my JSplitPane divider

Main.java:

import javax.swing.plaf.basic.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.awt.*;
 
public class Main extends JFrame
{
   JSplitPane splitPane;
  
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 
                                 new JPanel(), new JPanel());
      splitPane.setDividerSize(20);
  
      JButton button = new JButton("Exit!");
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            System.exit(0);
         }
      });
 
      setJMenuBar(getMainMenuBar());
 
      splitPane.setUI(new ButtonDividerUI(button));
 
      getContentPane().add(splitPane);
 
      addComponentListener(new ComponentAdapter() {
         public void componentShown(ComponentEvent event) {
            splitPane.setDividerLocation(0.5);  
                
            removeComponentListener(this);
         }
      });
   }
 
   public JMenuBar getMainMenuBar() {
      JMenuBar mainBar = new JMenuBar();
      JMenu menu = new JMenu("JSplitPane");
      JMenuItem item1 = new JMenuItem("HORIZONTAL_SPLIT");
      JMenuItem item2 = new JMenuItem("VERTICAL_SPLIT");
      menu.add(item1);
      menu.add(item2);
      mainBar.add(menu);
 
      item1.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
         }
      });
 
      item2.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
         }
      });
 
      return mainBar;
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(300, 300);
      main.setVisible(true);
   }
}
 
class ButtonDividerUI extends BasicSplitPaneUI
{
   protected JButton button;
 
   public ButtonDividerUI(JButton button) {
      this.button = button;
   }
 
   public BasicSplitPaneDivider createDefaultDivider() {
      BasicSplitPaneDivider divider = new BasicSplitPaneDivider(this) {
         public int getDividerSize() { 
            if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
               return button.getPreferredSize().width; 
            }
            return button.getPreferredSize().height;
         }
      };
 
      divider.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
      divider.add(button);
 
      return divider;
   }
}

Programmatically maximizing a JInternalFrame

Call setMaximum(true) on your JInternalFrame instance. Or call the method maximizeFrame of the DestopManager providing it with the instance of the JInternalFrame to be maximized. Here’s an example:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.net.*;
 
public class Main extends JFrame implements ActionListener {
   JDesktopPane desktop;
   JInternalFrame frame;
 
   public Main() {
      setTitle("JInternalFrame Actions");
      desktop = new JDesktopPane(); 
      createInternalFrame(); 
      setContentPane(desktop);
      setJMenuBar(createMenuBar());
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      setSize(500, 400);
   }
 
   protected JMenuBar createMenuBar() {
      JMenuBar menuBar = new JMenuBar();
 
      JMenu menu = new JMenu("JInternalFrame Actions");
      JMenuItem menuItem = new JMenuItem("Maximize");
      menuItem.addActionListener(this);
      menu.add(menuItem);
      menuBar.add(menu);
 
      return menuBar;
   }
 
   public void actionPerformed(ActionEvent ae) {
      if (ae.getActionCommand().equals("Maximize")) {
 
         desktop.getDesktopManager().maximizeFrame(frame);
 
         /* OR:
 
         try {
            frame.setMaximum(true);
         } 
         catch(java.beans.PropertyVetoException e) {
         }
 
         */
         
      }
   }
 
   protected void createInternalFrame() {
      frame = new JInternalFrame("InternalFrame", 
         true,    // resizable
         true,    // closable
         true,    // maximizable
         true);   // iconifiable
      frame.setVisible(true); 
      desktop.add(frame);
      frame.setSize(200, 200);
      frame.setLocation(30, 30);
      try {
         frame.setSelected(true);
      } catch (java.beans.PropertyVetoException e) {}
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setVisible(true);
   }
}

Showing a different tooltip for every item in a JComboBox

Modify the behavior of the ListRenderer such that it includes the currently selected JComboBox item in determining the tooltip text. Here’s an example:

import javax.swing.plaf.basic.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
    
public class Main extends JFrame
{ 
   public Main() {
      getContentPane().setLayout(new FlowLayout());
      
      final JComboBox combobox = new JComboBox(new String[] { "Item 1", "Item 2", "Item 3" });
 
      getContentPane().add(combobox);
 
      combobox.setRenderer(new BasicComboBoxRenderer() {
         public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 
            if (isSelected) { 
               setBackground(list.getSelectionBackground()); 
               setForeground(list.getSelectionForeground()); 
               if (index > -1) {
                  list.setToolTipText("Tooltip #" + new Integer(index).toString()); 
               }
            }
            else { 
               setBackground(list.getBackground()); 
               setForeground(list.getForeground()); 
            } 
            setFont(list.getFont()); 
            setText((value == null) ? "" : value.toString()); 
 
            return this; 
         }
      });
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });      
   
      setSize(new Dimension(200, 200));
   } 
 
   public static void main(String[] args) throws Exception {
      Main main = new Main();
      main.setVisible(true);
   }
}

Creating a JTextField as an element of JList

This example uses an EditableJList, a custom JList that only allows an EditableJList.EditableListModel as model. Our EditableListModel can only contain JTextComponents (JTextField, JTextArea, …) items.
The behavior is such that when double-clicking on the JList, the selected item is detected using the method locationToIndex and a border is added to it. The border will be removed when the textfield looses focus. To ensure that the JList element is being updated while editing the textfield, every DocumentEvent is captured and fireContentsChanged is called.
Main.java:

import javax.swing.event.*;
import javax.swing.text.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
  
public class Main extends JFrame {
 
   public Main() {
      getContentPane().setLayout(new BorderLayout());
 
      EditableJList.EditableListModel listModel = new EditableJList.EditableListModel();
 
      // populate listmodel
      Random r = new Random();
      for (int i=0; i&lt;50; i++) {
         String item = &quot;list item # &quot; + (Math.abs(r.nextInt()) % 100);
         JTextField tc = new JTextField(item);
//         JTextArea tc = new JTextArea(item);
//         JEditorPane tc = new JEditorPane(&quot;text/html&quot;, &quot;&lt;h3&gt;&quot; + item + &quot;&lt;/h3&gt;&quot;);
         listModel.addElement(tc);
      }
 
      EditableJList list = new EditableJList(listModel); 
      getContentPane().add(BorderLayout.CENTER, new JScrollPane(list));    
  
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent event) {
            System.exit(0);   
         }      
      });
 
      pack();
   }
 
   public static void main(String[] args) {
      (new Main()).show();
   }
}
 
class EditableJList extends JList {
   public EditableJList(EditableListModel listModel) {
      setModel(listModel);
      addMouseListener();
 
      // set our custom cell renderer
      setCellRenderer(new TextComponentCellRenderer()); 
   }
 
   private void addMouseListener() {  
      MouseListener mouseListener = new MouseAdapter() {
         public void mouseClicked(MouseEvent e) {
            if (e.getClickCount() == 2) {
               EditableListModel listModel = (EditableListModel) getModel();
 
               // determine the clicked item
               int index = locationToIndex(e.getPoint());
               Object value = listModel.getElementAt(index);
               final JTextComponent tc = (JTextComponent) value;
 
               // set the appropriate border for editing 
               String classname = tc.getClass().getName().toString();
               classname = classname.substring(classname.lastIndexOf(&quot;.&quot;));
               tc.setBorder(UIManager.getBorder(classname + &quot;border&quot;));
 
               // make this border appear in the JList
               listModel.updateItem(index);
 
               tc.addFocusListener(new FocusListener() {
                  public void focusGained(FocusEvent fe) {
                     // no selection color desired when editing a JTextComponent
                     clearSelection();
                  }
 
                  public void focusLost(FocusEvent fe) {
                     // remove the border again when stopped editing
                     tc.setBorder(null);
                  }
               });
 
               // request the focus on this component to be able to edit it
               tc.requestFocus();
 
               // listen to all key events on the JTextComponent and update the 
               // JList item every time.  Without this, you won't see the changes.           
               tc.getDocument().addDocumentListener(new UpdateListDocumentListener(listModel, index));
            }
         }
      };
 
      addMouseListener(mouseListener);
   }
 
   // DocumentListener that takes care of updating a JList item
   // when editing it.  Calls updateItem on our custom EditableListModel
   private class UpdateListDocumentListener implements DocumentListener {
      private EditableListModel elm;
      private int index;
 
      public UpdateListDocumentListener(EditableListModel elm, int index) {
         this.elm = elm;
         this.index = index;
      }
 
      public void insertUpdate(DocumentEvent e) {
         elm.updateItem(index);
      }
 
      public void removeUpdate(DocumentEvent e) {
         elm.updateItem(index);
      }
 
      public void changedUpdate(DocumentEvent e) {
         elm.updateItem(index);
      }
   }
 
   private class TextComponentCellRenderer implements ListCellRenderer {
      public Component getListCellRendererComponent(
         JList list,
         Object value,            // value to display
         int index,               // cell index
         boolean isSelected,      // is the cell selected
         boolean cellHasFocus)    // the list and the cell have the focus
      {
         JTextComponent tc = (JTextComponent) value;
         if (isSelected) {
            tc.setBackground(list.getSelectionBackground());
            tc.setForeground(list.getSelectionForeground());
         }
         else {
            tc.setBackground(list.getBackground());
            tc.setForeground(list.getForeground());
         }
 
         tc.setEnabled(list.isEnabled());
         tc.setFont(list.getFont());
         tc.setBorder(null);
 
         return (Component) value;
      }
   }
 
   public static class EditableListModel extends DefaultListModel {
      public void updateItem(int index) {
         fireContentsChanged(this, index, index);
      }

      public void addElement(JTextComponent tc) {
         super.addElement(tc);
      }
   }
}

Disable the keyboard accellerator that has been assigned to a JMenuItem

Set the accelerator to null. This example assigns accelerators to the JMenuItems ‘male’ and ‘female’. Press CTRL-M and CTRL-F to invoke them. After 5 selections, the accelerators will be disabled.

Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
   
public class Main extends JFrame implements ActionListener {
   JMenuItem menuItem1;
   JMenuItem menuItem2;
 
   public Main() {
      getContentPane().setLayout(new FlowLayout());
 
      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("Sex");
      menuItem1 = new JMenuItem("male");
      menuItem2 = new JMenuItem("female");
 
      // add the MenuItems to the Menu 
      menu.add(menuItem1);
      menu.add(menuItem2);
      menuItem1.setAccelerator(KeyStroke.getKeyStroke('M', Event.CTRL_MASK));
      menuItem2.setAccelerator(KeyStroke.getKeyStroke('F', Event.CTRL_MASK));
 
      // listen for events on these MenuItems
      menuItem1.addActionListener(this);
      menuItem2.addActionListener(this);
 
      menuBar.add(menu);
 
      this.setJMenuBar(menuBar); 
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent event) {
            System.exit(0);   
         }      
      });
 
      setSize(400, 400);
   }
 
   private int count = 0;
   public void actionPerformed(ActionEvent ae) {
      System.out.println(ae.getActionCommand());
 
      count++;
      if (count == 5) {
         System.out.println("now disabling accelerators");
 
         menuItem1.setAccelerator(null);
         menuItem2.setAccelerator(null);
      }
   }
 
   public static void main(String[] args) {
      (new Main()).show();
   }
}