I want the program to have the ability to
disable some of the cells in the table.
(For example, when the user clicks on
a checkbox, the program would disable
the checkbox below it.)
What I mean by "disable" is that
the checkbox would either not be
displayed at all, or it would be
greyed out and would not respond
to mouse clicks.
Can someone tell me how to accomplish this?
Here's the program...
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class CheckboxTable extends JFrame {
class SimpleCellRenderer extends JLabel implements
ListCellRenderer, TableCellRenderer {
public SimpleCellRenderer(JTable table) {
JTableHeader header = table.getTableHeader();
setOpaque(true);
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
setHorizontalAlignment(CENTER);
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
setHorizontalAlignment(SwingConstants.LEFT);
setHorizontalTextPosition(SwingConstants.RIGHT);
}
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean cellHasFocus,
int row, int column) {
setText((value == null) ? "" : value.toString());
setHorizontalAlignment(SwingConstants.LEFT);
setHorizontalTextPosition(SwingConstants.RIGHT);
return this;
}
public Component getListCellRendererComponent(JList list,
Object value, int index, boolean isSelected, boolean
cellHasFocus) {
setText((value == null) ? "" : value.toString());
return this;
}
}
class CheckboxTableModel extends DefaultTableModel {
public CheckboxTableModel(Object[][] x, Object[] y) {
super(x, y);
}
public Class getColumnClass(int i) {
return Boolean.class;
}
}
// instance variables
int numRows, numColumns;
String columnHeadings[], rowHeadings[];
Boolean[][] bitGrid;
public CheckboxTable(int numRows, int numColumns) {
super();
this.numRows = numRows;
this.numColumns = numColumns;
// Initalize the bit grid so that all checkboxes are off.
bitGrid = new Boolean[numRows][numColumns];
for (int row = 0; row < numRows; row++)
for (int col = 0; col < numColumns; col++)
bitGrid[row][col] = new Boolean(false);
// Initalize the column heading Strings.
columnHeadings = new String[numColumns];
for (int col = 0; col < numColumns; col++)
columnHeadings[col] = "Column "+col;
// Initalize the row heading Strings.
rowHeadings = new String[numRows];
for (int row = 0; row < numRows; row++)
rowHeadings[row] = "Row "+row;
// Construct the table.
final JTable table =
new JTable(new CheckboxTableModel(bitGrid,
columnHeadings));
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.setColumnSelectionAllowed(false);
table.setRowSelectionAllowed(false);
// Make a scroll pane, put the table in it, and add it to the
window.
JScrollPane scroll = new JScrollPane(table);
getContentPane().add(scroll, BorderLayout.CENTER);
// Set the width and cell renderer for the table's columns.
final JTableHeader tableHeader = table.getTableHeader();
for (Enumeration e =
tableHeader.getColumnModel().getColumns();
e.hasMoreElements(); ) {
TableColumn col = (TableColumn)e.nextElement();
col.setHeaderRenderer(new SimpleCellRenderer(table));
col.setMinWidth(100);
col.setMaxWidth(100);
}
// Set the width, height and cell renderer for the table's
rows.
ListModel rowHeaderListModel = new AbstractListModel() {
public int getSize() { return getNumRows(); }
public Object getElementAt(int index) {
return getRowHeading(index);
}
};
final JList rowHeader = new JList(rowHeaderListModel);
rowHeader.setFixedCellWidth(100);
rowHeader.setFixedCellHeight(table.getRowHeight());
rowHeader.setCellRenderer(new SimpleCellRenderer(table));
scroll.setRowHeaderView(rowHeader);
// Specify what to do if the user clicks on a column header.
MouseAdapter columnHeaderMouseListener =
new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
TableColumnModel columnModel =
table.getColumnModel();
int UIColumnNum =
columnModel.getColumnIndexAtX(e.getX());
int columnNum =
table.convertColumnIndexToModel(UIColumnNum);
int columnWidth =
columnModel.getColumn(0).getWidth();
System.out.println("Clicked on column " +
columnNum);
}
};
tableHeader.addMouseListener(columnHeaderMouseListener);
// Specify what to do if the user clicks on a row header.
MouseAdapter rowHeaderMouseListener =
new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int rowNum =
rowHeader.locationToIndex(e.getPoint());
System.out.println("Clicked on row " + rowNum);
}
};
rowHeader.addMouseListener(rowHeaderMouseListener);
// Specify what to do if the user clicks on a table cell.
MouseAdapter tableCellMouseListener =
new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
TableColumnModel columnModel =
table.getColumnModel();
int UIColumnNum =
columnModel.getColumnIndexAtX(e.getX());
int columnNum =
table.convertColumnIndexToModel(UIColumnNum);
int rowNum =
rowHeader.locationToIndex(e.getPoint());
System.out.println("Clicked on row " + rowNum +
", column " + columnNum);
}
};
table.addMouseListener(tableCellMouseListener);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setSize(600, 400);
setVisible(true);
}
public int getNumRows() {
return numRows;
}
public int getNumColumns() {
return numColumns;
}
public String getColumnHeading(int i) {
return columnHeadings[i];
}
public String getRowHeading(int i) {
return rowHeadings[i];
}
public static void main(String[] args) {
int numRows = 25, numColumns = 10;
if (args.length == 2) {
numRows = Integer.parseInt(args[0]);
numColumns = Integer.parseInt(args[1]);
}
CheckboxTable cbt = new CheckboxTable(numRows, numColumns);
}
}
This is an anonymous inner class of the instance of the JTableModel ...
public boolean isCellEditable(int
row, int col) {
if (getGlobalSaveFlag())
// no columns are editable when global save flag is set
return false;
else
return (col == 0 ? true : false); // only column 0 is editable
}
};
What I was doing was to have an external JCheckbox drive whether the JTable's checkboxes were editable or not (none of the other columns was ever editable, in my case); the checkboxes in the JTable were in column 0. You could do something similar, but use a different method than my getGlobalSaveFlag() method; yours would probably return the particular column and row that you want to disable (or enable).
I also registered a ChangeListener with a stateChanged(ChangeEvent ce) method to drive a "set columns" method:
private final void setSaveColumns(boolean b) {
javax.swing.table.TableColumn dbSaveCol;
dbSaveCol = table.getColumnModel().getColumn(0);
ServerCheckBoxRenderer dbrenderer = new ServerCheckBoxRenderer(! b, null);
dbSaveCol.setCellRenderer(dbrenderer);
tablePane.repaint();
} // end setSaveColumns method
Then your job is to make sure your cell renderer is up to the task!
Here's my class constructor:
public ServerCheckBoxRenderer(boolean setEnable, CheckBoxStateListener checkBoxStateListener)
Then the rendering looks kinda like this:
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int col) {if (isSelected) {
cBox.setBackground(table.getSelectionBackground());
setForeground( table.getSelectionForeground() );
setBackground( table.getSelectionBackground() );
}
else {
cBox.setBackground(table.getBackground());
setForeground( table.getForeground() );
setBackground( table.getBackground() );
}if (setEnable) {
cBox.setSelected( ((Boolean)value).booleanValue() );
cBox.setEnabled(table.getModel().isCellEditable(row, col));
}
else {
cBox.setSelected( ((Boolean)value).booleanValue() );
cBox.setEnabled(setEnable);
}
Good luck! Hope this helps ...
Michael