bjg
asked on
JTable question...
I am trying to create a JTable which has two columns. The first column I want to be a JCheckBox (and I want the user to be able to set it checked or unchecked in the table as well as display the cell checked or unchecked depending on the data set that the model contains). The second column I want to have a JTextField as the CellRenderer but I don't want it to be editable, so it's not a CellEditor, just a CellRenderer. I also do not want to display the column headers. How can I do this?
This is an example of such a table:
String[] columnNames = {DIRECTORY, FILE_SPEC, IS_RECURSIVE, PARSER_START_STATE, URL_PREFIX};
DefaultTableModel model = new DefaultTableModel(columnNa mes, 0)
{
public Class getColumnClass(int columnIndex)
{
if (columnIndex == 2) // This makes the third column displayed as a checkbox
{
return (new Boolean(true)).getClass();
}
else
{
return super.getColumnClass(colum nIndex); // Other columns are labels
}
}
};
JTable newTable = new JTable(model)
{
public boolean isCellEditable(int row, int column)
{
return (column != 1); // This makes the second column non-editable
}
};
newTable.setTableHeader(nu ll); // That should take care of the header
String[] columnNames = {DIRECTORY, FILE_SPEC, IS_RECURSIVE, PARSER_START_STATE, URL_PREFIX};
DefaultTableModel model = new DefaultTableModel(columnNa
{
public Class getColumnClass(int columnIndex)
{
if (columnIndex == 2) // This makes the third column displayed as a checkbox
{
return (new Boolean(true)).getClass();
}
else
{
return super.getColumnClass(colum
}
}
};
JTable newTable = new JTable(model)
{
public boolean isCellEditable(int row, int column)
{
return (column != 1); // This makes the second column non-editable
}
};
newTable.setTableHeader(nu
ASKER
How can I make the first column an editable JCheckBox, and the second column a non-editable JTextField?
ASKER
Do I have to create a custom CellRenderer, and a custom CellEditor, and then set each column's editor or renderer appropriately?
Simply replace the literal 2 with literal 0 in the code above. And shorten the list of column names to two entries. The rest stays the same.
ASKER
Do I have to create a custom CellRenderer, and a custom CellEditor, and then set each column's editor or renderer appropriately?
ASKER
How do I make the other columns JTextFields, rather than JLabels?
I want to support multiple lines of text for each cell (not the JCheckBox cell, but the JTextField cell)
I want to support multiple lines of text for each cell (not the JCheckBox cell, but the JTextField cell)
ASKER
How do I make the other columns JTextFields, rather than JLabels?
I want to support multiple lines of text for each cell (not the JCheckBox cell, but the JTextField cell)
I want to support multiple lines of text for each cell (not the JCheckBox cell, but the JTextField cell)
No, just try the code I supplied, no ther changes should be required. DefaultTableModel and DefaultCellRenderer should take care of all the details.
If the cell is editable, it will use JTextField a cell editor. I am not sure with multiple lines of text, that will probably require a custom renderer/editor.
ASKER
How do I make the other columns JTextFields, rather than JLabels?
I want to support multiple lines of text for each cell (not the JCheckBox cell, but the JTextField cell)
I want to support multiple lines of text for each cell (not the JCheckBox cell, but the JTextField cell)
ASKER
I don't want the JTextField cell to be editable, I want the JCheckBox field to be editable or selectable. The only reason why I want to use the JTextField as the other cell, is so I can support multiple lines of text. How can I set this up in the table?
I see what you want. Yes, if you want to have a text field as a renderer you have to create one of your own. I am not sure how it solves your problem, beacuse text field as far as I know display only one line of text.
Look at the code of DefaultTableCellRenderer (which extends JLabel) and create something similar by extending JTextField. (Make sure you call setEditable(false)). I think it will look no diffrenet that it looks with the label, but you can try.
To set the new cell editor only for specific column, get a TableColumn object for the desired column and call setCellRenderer().
Look at the code of DefaultTableCellRenderer (which extends JLabel) and create something similar by extending JTextField. (Make sure you call setEditable(false)). I think it will look no diffrenet that it looks with the label, but you can try.
To set the new cell editor only for specific column, get a TableColumn object for the desired column and call setCellRenderer().
ASKER
Well, I finally have most of it working. I have it working how I want, just not looking how I want. When I tell the first column to be a Boolean and editable, it results in a cell with a selectable checkbox. This is what I want. But the default look of the checkbox is centered in the cell, and it does not highlight when you select the row. How can I change this so that it is in the upper left of the cell and highlights like the rest of the row?
You can change the way check box looks by extending DefaultCellEditor class and overriding getTableCellEditorComponen t() method. In that method first check whether editorComponent is a check box (it is a protected member so you can do it). If it is, change its appearance, then call super.getTableCellEditorCo mponent().
ASKER
I tried that and it didn't work
ASKER
I tried that and it didn't work
ASKER
If I set a custom Editor for the CheckBox column, it only shows that renderer when I select the JCheckBox, and then it shows the default renderer for the CheckBox column after I have selected it. If I also set a custom renderer, I can't select and deselect the JCheckBox. How can I get this to work?
Here is my code:
package Lccs.Gui.Awt;
import com.sun.java.swing.*;
import com.sun.java.swing.border. *;
import com.sun.java.swing.table.* ;
import java.awt.*;
import java.util.*;
public class CheckBoxTable extends JTable
{
public CheckBoxTable(Object data[][])
{
super();
this.data = data;
verifyDataElements();
setSelectionMode(ListSelec tionModel. SINGLE_SEL ECTION);
setShowHorizontalLines(tru e);
setShowVerticalLines(false );
String columns[];
if (hasCheckBox)
{
columns = new String[2];
columns[0] = "Selection";
columns[1] = "Information";
} else
{
columns = new String[1];
columns[0] = "Information";
}
tableModel = new InnerTableModel(columns, data);
setModel(tableModel);
setDefaultRenderer(Object. class, new InnerTextFieldCellRenderer ());
//setDefaultRenderer(Boole an.class, new InnerCheckBoxCellRenderer( ));
setDefaultEditor(Boolean.c lass, new InnerCellEditor());
if (hasCheckBox)
{
TableColumn col = getColumn(columns[0]);
col.setWidth(30);
col.setMinWidth(30);
col.setMaxWidth(30);
}
setRowHeight(getMeasuredRo wHeight()) ;
setTableHeader(null);
setCellSelectionEnabled(fa lse);
}
private void verifyDataElements() throws IllegalArgumentException
{
if (data[0].length > 1)
{
for (int i = 0; i < data.length; i++)
{
if (!(data[i][0] instanceof Boolean))
{
throw new IllegalArgumentException(
"First element of row must be a Boolean Object." );
}
}
hasCheckBox = true;
} else
hasCheckBox = false;
}
private int getMeasuredRowHeight()
{
int tokenCount = 0;
for (int i = 0; i < data.length; i++)
{
String str = null;
if (hasCheckBox)
str = (String)data[i][1];
else
str = (String)data[i][0];
StringTokenizer tok = new StringTokenizer(str, "\n");
tokenCount = tok.countTokens();
}
return (20 * tokenCount);
}
public void setData(Object data[][])
{
tableModel.setData(data);
revalidate();
repaint();
}
//Inner Class - TableModel
class InnerTableModel extends AbstractTableModel
{
String[] columnNames = null;
Object[][] data = null;
public InnerTableModel(String columns[], Object data[][])
{
this.columnNames = columns;
this.data = data;
}
public void setData(Object newData[][])
{
this.data = newData;
}
public int getColumnCount()
{
return columnNames.length;
}
public int getRowCount()
{
return data.length;
}
public String getColumnName(int col)
{
return columnNames[col];
}
public Object getValueAt(int row, int col)
{
return data[row][col];
}
public Class getColumnClass(int c)
{
return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int row, int col)
{
if (hasCheckBox)
{
if (col == 0)
return true;
}
return false;
}
public void setValueAt(Object value, int row, int col)
{
data[row][col] = value;
}
}
//Inner Class - TableCellRenderer
class InnerTextFieldCellRenderer extends JTextField implements
TableCellRenderer
{
public InnerTextFieldCellRenderer ()
{
super();
setOpaque(true);
setEditable(false);
setBorder(new EmptyBorder(0,5,0,5));
}
public Component getTableCellRendererCompon ent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
if (isSelected)
{
setForeground(SystemColor. textHighli ghtText);
setBackground(SystemColor. textHighli ght);
}
else
{
setBackground(table.getBac kground()) ;
setForeground(table.getFor eground()) ;
}
setFont(table.getFont());
if (value != null)
{
setText(value.toString());
}
return this;
}
} //End Inner Class
//Inner Class - TableCellRenderer
class InnerCheckBoxCellRenderer extends JCheckBox implements
TableCellRenderer
{
public InnerCheckBoxCellRenderer( )
{
super();
setOpaque(true);
setVerticalAlignment(TOP);
setHorizontalAlignment(LEF T);
}
public Component getTableCellRendererCompon ent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
if (isSelected)
{
setForeground(SystemColor. textHighli ghtText);
setBackground(SystemColor. textHighli ght);
}
else
{
setBackground(table.getBac kground()) ;
setForeground(table.getFor eground()) ;
}
return this;
}
} //End Inner Class
class InnerCellEditor extends DefaultCellEditor
{
InnerCellEditor()
{
super(new JCheckBox());
}
public Component getTableCellEditorComponen t(JTable table, Object value,
boolean isSelected,
int row, int column)
{
((JCheckBox)editorComponen t).setVert icalAlignm ent(JCheck Box.TOP);
((JCheckBox)editorComponen t).setHori zontalAlig nment(JChe ckBox.LEFT );
if (isSelected)
{
editorComponent.setBackgro und(System Color.text HighlightT ext);
editorComponent.setForegro und(System Color.text Highlight) ;
}
else
{
editorComponent.setBackgro und(table. getBackgro und());
editorComponent.setForegro und(table. getForegro und());
}
return editorComponent;
}
}
private boolean hasCheckBox;
private InnerTableModel tableModel;
private Object data[][];
}
Here is my code:
package Lccs.Gui.Awt;
import com.sun.java.swing.*;
import com.sun.java.swing.border.
import com.sun.java.swing.table.*
import java.awt.*;
import java.util.*;
public class CheckBoxTable extends JTable
{
public CheckBoxTable(Object data[][])
{
super();
this.data = data;
verifyDataElements();
setSelectionMode(ListSelec
setShowHorizontalLines(tru
setShowVerticalLines(false
String columns[];
if (hasCheckBox)
{
columns = new String[2];
columns[0] = "Selection";
columns[1] = "Information";
} else
{
columns = new String[1];
columns[0] = "Information";
}
tableModel = new InnerTableModel(columns, data);
setModel(tableModel);
setDefaultRenderer(Object.
//setDefaultRenderer(Boole
setDefaultEditor(Boolean.c
if (hasCheckBox)
{
TableColumn col = getColumn(columns[0]);
col.setWidth(30);
col.setMinWidth(30);
col.setMaxWidth(30);
}
setRowHeight(getMeasuredRo
setTableHeader(null);
setCellSelectionEnabled(fa
}
private void verifyDataElements() throws IllegalArgumentException
{
if (data[0].length > 1)
{
for (int i = 0; i < data.length; i++)
{
if (!(data[i][0] instanceof Boolean))
{
throw new IllegalArgumentException(
"First element of row must be a Boolean Object." );
}
}
hasCheckBox = true;
} else
hasCheckBox = false;
}
private int getMeasuredRowHeight()
{
int tokenCount = 0;
for (int i = 0; i < data.length; i++)
{
String str = null;
if (hasCheckBox)
str = (String)data[i][1];
else
str = (String)data[i][0];
StringTokenizer tok = new StringTokenizer(str, "\n");
tokenCount = tok.countTokens();
}
return (20 * tokenCount);
}
public void setData(Object data[][])
{
tableModel.setData(data);
revalidate();
repaint();
}
//Inner Class - TableModel
class InnerTableModel extends AbstractTableModel
{
String[] columnNames = null;
Object[][] data = null;
public InnerTableModel(String columns[], Object data[][])
{
this.columnNames = columns;
this.data = data;
}
public void setData(Object newData[][])
{
this.data = newData;
}
public int getColumnCount()
{
return columnNames.length;
}
public int getRowCount()
{
return data.length;
}
public String getColumnName(int col)
{
return columnNames[col];
}
public Object getValueAt(int row, int col)
{
return data[row][col];
}
public Class getColumnClass(int c)
{
return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int row, int col)
{
if (hasCheckBox)
{
if (col == 0)
return true;
}
return false;
}
public void setValueAt(Object value, int row, int col)
{
data[row][col] = value;
}
}
//Inner Class - TableCellRenderer
class InnerTextFieldCellRenderer
TableCellRenderer
{
public InnerTextFieldCellRenderer
{
super();
setOpaque(true);
setEditable(false);
setBorder(new EmptyBorder(0,5,0,5));
}
public Component getTableCellRendererCompon
boolean isSelected, boolean hasFocus, int row, int column)
{
if (isSelected)
{
setForeground(SystemColor.
setBackground(SystemColor.
}
else
{
setBackground(table.getBac
setForeground(table.getFor
}
setFont(table.getFont());
if (value != null)
{
setText(value.toString());
}
return this;
}
} //End Inner Class
//Inner Class - TableCellRenderer
class InnerCheckBoxCellRenderer extends JCheckBox implements
TableCellRenderer
{
public InnerCheckBoxCellRenderer(
{
super();
setOpaque(true);
setVerticalAlignment(TOP);
setHorizontalAlignment(LEF
}
public Component getTableCellRendererCompon
boolean isSelected, boolean hasFocus, int row, int column)
{
if (isSelected)
{
setForeground(SystemColor.
setBackground(SystemColor.
}
else
{
setBackground(table.getBac
setForeground(table.getFor
}
return this;
}
} //End Inner Class
class InnerCellEditor extends DefaultCellEditor
{
InnerCellEditor()
{
super(new JCheckBox());
}
public Component getTableCellEditorComponen
boolean isSelected,
int row, int column)
{
((JCheckBox)editorComponen
((JCheckBox)editorComponen
if (isSelected)
{
editorComponent.setBackgro
editorComponent.setForegro
}
else
{
editorComponent.setBackgro
editorComponent.setForegro
}
return editorComponent;
}
}
private boolean hasCheckBox;
private InnerTableModel tableModel;
private Object data[][];
}
Yes, you should be defining you custome renderer as well. Try setting it using:
table.setDefaultRenderer(B oolean.TYP E, new InnerCheckBoxCellRenderer( ));
table.setDefaultRenderer(B
ASKER
I did that and it didn't work, that's why I commented it out.
Sorry, I missed it. What if you disable the check box in your renderer. The problem might stem from the fact that checkbox component used as a renderer receives the mouse events instead of the table.
ASKER
Nope, that didn't work either.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I guess you answered my original question, but I already have that part working. I am just trying to set a custom cell editor and cell renderer for the boolean (JCheckBox) column of the table because I don't like the default look of the JCheckBox in the center, I want the JCheckBox in the upper left hand corner. So how do I do that?
ASKER
How can I make the JCheckBox column mutually exclusive, so that only one can be selected at a time?
ASKER