I have a table that I'm loading with rows at run time. Once loaded the user needs to choose an item from a JComboBox in the first column for each line. Then he needs to chose an item from another JComboBoxon the same line in every rows. The content of the second JComboBox depends on the selection of the first JComboBox.
The way I coded it now is changing the combobox content for the whole second column.
columnProfile.setCellEditor(new DefaultCellEditor(comboBoxProf))
Is there a way to have a combobox object different on every row so I can work on it everytime I select a value in the first combobox?
The number of rows is not fixed until the user hits submit. He can add and delete rows.
I've used the basic Table example from Oracle and made the changes to reflect what I'm currently doing
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
public class TableRenderDemo extends JPanel {
private boolean DEBUG = false;
JComboBox comboBox2;
JComboBox comboBox1;
public TableRenderDemo() {
super(new GridLayout(1,0));
JTable table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
initColumnSizes(table);
setUpSportColumn(table, table.getColumnModel().getColumn(2));
setUpYearsColumn(table, table.getColumnModel().getColumn(3));
add(scrollPane);
table.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
if (e.getColumn() == 2){
comboBox2.removeAllItems();
/*REFILL COMBOBOX WITH WHAT I NEED FOR THIS ROW ONLY*/
}
}
});
}
private void initColumnSizes(JTable table) {
MyTableModel model = (MyTableModel)table.getModel();
TableColumn column = null;
Component comp = null;
int headerWidth = 0;
int cellWidth = 0;
Object[] longValues = model.longValues;
TableCellRenderer headerRenderer =
table.getTableHeader().getDefaultRenderer();
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
comp = headerRenderer.getTableCellRendererComponent(
null, column.getHeaderValue(),
false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
comp = table.getDefaultRenderer(model.getColumnClass(i)).
getTableCellRendererComponent(
table, longValues[i],
false, false, 0, i);
cellWidth = comp.getPreferredSize().width;
if (DEBUG) {
System.out.println("Initializing width of column "
+ i + ". "
+ "headerWidth = " + headerWidth
+ "; cellWidth = " + cellWidth);
}
column.setPreferredWidth(Math.max(headerWidth, cellWidth));
}
}
public void setUpSportColumn(JTable table,
TableColumn sportColumn) {
//Set up the editor for the sport cells.
comboBox1 = new JComboBox();
comboBox1.addItem("Snowboarding");
comboBox1.addItem("Rowing");
comboBox1.addItem("Knitting");
comboBox1.addItem("Speed reading");
comboBox1.addItem("Pool");
comboBox1.addItem("None of the above");
sportColumn.setCellEditor(new DefaultCellEditor(comboBox1));
DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
sportColumn.setCellRenderer(renderer);
}
public void setUpYearsColumn(JTable table,
TableColumn yearColumn) {
comboBox2 = new JComboBox();
comboBox2.addItem("1");
comboBox2.addItem("2");
comboBox2.addItem("3");
comboBox2.addItem("4");
comboBox2.addItem("5");
comboBox2.addItem("6");
yearColumn.setCellEditor(new DefaultCellEditor(comboBox2));
//Set up tool tips for the sport cells.
DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
yearColumn.setCellRenderer(renderer);
}
class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
private Object[][] data = {
{"Kathy", "Smith",
"Snowboarding", "1", new Boolean(false)},
{"John", "Doe",
"Rowing", "1", new Boolean(true)},
{"Sue", "Black",
"Knitting", "1", new Boolean(false)},
{"Jane", "White",
"Speed reading", "1", new Boolean(true)},
{"Joe", "Brown",
"Pool", "1", new Boolean(false)}
};
public final Object[] longValues = {"Jane", "Kathy",
"None of the above",
new Integer(20), Boolean.TRUE};
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 (col < 2) {
return false;
} else {
return true;
}
}
public void setValueAt(Object value, int row, int col) {
if (DEBUG) {
System.out.println("Setting value at " + row + "," + col
+ " to " + value
+ " (an instance of "
+ value.getClass() + ")");
}
data[row][col] = value;
fireTableCellUpdated(row, col);
if (DEBUG) {
System.out.println("New value of data:");
printDebugData();
}
}
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i=0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j=0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TableRenderDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableRenderDemo newContentPane = new TableRenderDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Say you had your data held in a Map<String, List<String>> with the Map's keys representing the values held by the first JComboBox, and the Map's values representing the changing values held by the 2nd column's JComboBox (the data does not need to be set up this way, but it's easy for MCVE/demonstration purposes), and call this map dataMap, then your column editor could look something like:
column1.setCellEditor(new DefaultCellEditor(combo1) {
#SuppressWarnings("unchecked")
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
// the items that will fill our JComboBox. Initially its empty
Object[] items = new Object[]{};
// get the value in the column to the left
Object column0Value = table.getValueAt(row, column - 1);
if (column0Value != null) {
// if the value is not null, then get the map's values
// and use it to fill our items array
items = dataMap.get(column0Value).toArray();
}
// get the super component, the JComboBox that is being used
// as an editor:
JComboBox<Object> superCombo = (JComboBox<Object>) super.getTableCellEditorComponent(table, value, isSelected,
row, column);
// create a model and fill with items
DefaultComboBoxModel<Object> comboModel = new DefaultComboBoxModel<>(items);
// set the cell editor's model and return
superCombo.setModel(comboModel);
return superCombo;
}
});
For example please check this MCVE as an example that uses the above cell editor and as an example of a MCVE that would work well in your future questions
import java.awt.Component;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
#SuppressWarnings("serial")
public class TableWithMultCombos extends JPanel {
private static final String[] COLUMN_NAMES = { "Day of Week", "Number" };
private Map<String, List<String>> dataMap = new LinkedHashMap<>();
private DefaultTableModel tblModel = new DefaultTableModel(COLUMN_NAMES, 5);
private JTable table = new JTable(tblModel);
private DefaultComboBoxModel<Object> combo2Model = new DefaultComboBoxModel<>();
private JComboBox<Object> combo0 = null;
private JComboBox<Object> combo1 = new JComboBox<>(combo2Model);
public TableWithMultCombos() {
dataMap.put("Monday", Arrays.asList(new String[] { "Mon - 1", "Mon - 2", "Mon - 3", "Mon - 4" }));
dataMap.put("Tuesday", Arrays.asList(new String[] { "Tues - 1", "Tues - 2", "Tues - 3", "Tues - 4" }));
dataMap.put("Wednesday", Arrays.asList(new String[] { "Wed - 1", "Wed - 2", "Wed - 3", "Wed - 4" }));
dataMap.put("Thursday", Arrays.asList(new String[] { "Thurs - 1", "Thurs - 2", "Thurs - 3", "Thurs - 4" }));
dataMap.put("Friday", Arrays.asList(new String[] { "Fri - 1", "Fri - 2", "Fri - 3", "Fri - 4" }));
combo0 = new JComboBox<>(dataMap.keySet().toArray());
TableColumn column0 = table.getColumnModel().getColumn(0);
column0.setCellEditor(new DefaultCellEditor(combo0));
TableColumn column1 = table.getColumnModel().getColumn(1);
column1.setCellEditor(new DefaultCellEditor(combo1) {
#SuppressWarnings("unchecked")
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
// the items that will fill our JComboBox. Initially its empty
Object[] items = new Object[]{};
// get the value in the column to the left
Object column0Value = table.getValueAt(row, column - 1);
if (column0Value != null) {
// if the value is not null, then get the map's values
// and use it to fill our items array
items = dataMap.get(column0Value).toArray();
}
// get the super component, the JComboBox that is being used
// as an editor:
JComboBox<Object> superCombo = (JComboBox<Object>) super.getTableCellEditorComponent(table, value, isSelected,
row, column);
// create a model and fill with items
DefaultComboBoxModel<Object> comboModel = new DefaultComboBoxModel<>(items);
// set the cell editor's model and return
superCombo.setModel(comboModel);
return superCombo;
}
});
table.setFillsViewportHeight(true);
add(new JScrollPane(table));
}
private static void createAndShowGui() {
TableWithMultCombos mainPanel = new TableWithMultCombos();
JFrame frame = new JFrame("TableWithMultCombos");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Related
I have a JTable with numbers 1,2,3 as 1st column and the number as text in the 2nd column which can be chosen with a JCombobox. For example 1 can be represented as "1", ONE, FIRST or ONCE in the 2nd column. When I make a choice, all the comboboxes of the rows below have to be updated in cascade with the text of the same nature. So if I choose ONCE, the comboboxes of the rows below should be updated to TWICE, THRICE. If I choose FIRST, the comboboxes of the rows below should be updated to SECOND, THIRD. And so on..
At first it looks like it's working but whenever I click somewhere else on the JTable, the combobox is updated with the value of the last row. For example, if I choose ONCE in the 1st row, at first it will update the other rows to TWICE and THRICE. Then if I click on any row, the combobox selection will be updated to THRICE on the 1st row. Next time I click, the 2nd row is updated to THRICE.
What am I doing wrong here?
The combobox cell editor:
public class NumberChoiceEditor extends DefaultCellEditor {
private static final long serialVersionUID = 1L;
private String numberAsText;
private static final String[][] NUMBERS = { { "1", "ONE", "FIRST", "ONCE" }, { "2", "TWO", "SECOND", "TWICE" }, { "3", "THREE", "THIRD", "THRICE" } };
public NumberChoiceEditor() {
super(new JComboBox<>());
}
#Override
public Object getCellEditorValue() {
return numberAsText;
}
#Override
public Component getTableCellEditorComponent(final JTable table, final Object value, final boolean isSelected, final int row, final int column) {
if (value instanceof String) {
numberAsText = (String) value;
}
JComboBox<String> numberTextChoice = new JComboBox<>(NUMBERS[row]);
numberTextChoice.setSelectedItem(numberAsText);
numberTextChoice.addActionListener(e -> {
numberAsText = (String) numberTextChoice.getSelectedItem();
int nextRow = row + 1;
if (nextRow < NUMBERS.length) {
String numberText = (String) table.getValueAt(nextRow, 1);
JComboBox<String> nextRowChoices = (JComboBox<String>) getTableCellEditorComponent(table, numberText, isSelected, nextRow, column);
nextRowChoices.setSelectedIndex(numberTextChoice.getSelectedIndex());
table.setValueAt(nextRowChoices.getSelectedItem(), nextRow, 1);
}
});
return numberTextChoice;
}
}
The main class with the frame:
public class NumberTable {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JTable table = new JTable(new Object[][] { { 1, "1" }, { 2, "2" }, { 3, "3" } }, new Object[] { "Number", "Number Text" });
table.getColumn("Number Text").setCellEditor(new NumberChoiceEditor());
table.setRowHeight(25);
JFrame frame = new JFrame("Number Table");
frame.add(new JScrollPane(table));
frame.setLocationRelativeTo(null);
frame.setSize(600, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
I would use a TableModelListener. When the value is changed via the JComboBox editor, I would adjust the TableModel accordingly.
(Notes after the code.)
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class NumTable implements Runnable, TableModelListener {
private boolean adjusting;
private JFrame frame;
private JTable table;
#Override
public void run() {
createGui();
}
#Override
public void tableChanged(TableModelEvent event) {
if (!adjusting) {
adjusting = true;
int col = event.getColumn();
if (col == 1) {
NumChoiceEd editor = (NumChoiceEd) table.getColumnModel().getColumn(1).getCellEditor();
int row = event.getFirstRow();
JComboBox<String> combo = editor.getCombo(row);
if (combo != null) {
int ndx = combo.getSelectedIndex();
if (ndx >= 0) {
int rows = table.getRowCount();
for (int i = 0; i < rows; i++) {
combo = editor.getCombo(i);
String val = combo.getModel().getElementAt(ndx);
table.setValueAt(val, i, col);
}
}
}
}
adjusting = false;
}
}
private void createGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTable(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JScrollPane createTable() {
Object[][] data = new Object[][]{{1, "1"}, {2, "2"}, {3, "3"}};
Object[] columnNames = new Object[]{"Number", "Number Text"};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
model.addTableModelListener(this);
table = new JTable(model);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumnModel tcm = table.getColumnModel();
TableColumn column = tcm.getColumn(1);
column.setCellEditor(new NumChoiceEd());
JScrollPane scrollPane = new JScrollPane(table);
return scrollPane;
}
public static void main(String[] args) {
EventQueue.invokeLater(new NumTable());
}
}
class NumChoiceEd extends DefaultCellEditor {
private static final long serialVersionUID = 1L;
private JComboBox<String> oneCombo;
private JComboBox<String> twoCombo;
private JComboBox<String> threeCombo;
public NumChoiceEd() {
super(new JComboBox<>());
oneCombo = new JComboBox<>(new String[]{"1", "ONE", "FIRST", "ONCE"});
twoCombo = new JComboBox<>(new String[]{"2", "TWO", "SECOND", "TWICE"});
threeCombo = new JComboBox<>(new String[]{"3", "THREE", "THIRD", "THRICE"});
}
public JComboBox<String> getCombo(int row) {
switch (row) {
case 0:
return oneCombo;
case 1:
return twoCombo;
case 2:
return threeCombo;
default:
return null;
}
}
#Override
public Component getTableCellEditorComponent(final JTable table,
final Object value,
final boolean isSelected,
final int row,
final int column) {
if (column == 1) {
switch (row) {
case 0:
return oneCombo;
case 1:
return twoCombo;
case 2:
return threeCombo;
default:
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
else {
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
}
Rather than create a new JComboBox each time method getTableCellEditorComponent is called, I initially create all three JComboBoxes and return the relevant one.
You don't need to override method getCellEditorValue because the superclass method (in class DefaultCellEditor) will return the correct value.
Once the user changes the value (and closes the table cell editor), method tableChanged is invoked. In that method, I get the index of the value that was selected from the JComboBox and then I go through all the rows in the JTable and get the value at that index in the JComboBox for each row and set the JTable value to that value.
Because I change the TableModel in method tableChanged, that will cause the method to be called again. In order to prevent the recursive call, I use the adjusting flag.
In the below screen capture, I have selected a value from the JComboBox but I have not yet closed the editor. If I navigate to a different cell in the JTable that will close the editor and then all the displayed data will change. Note that if you navigate to column Number Text in a different row, you may not see the change since that will immediately open the JComboBox editor for the cell that you navigated to.
After I close the editor, the table looks as in the below screen capture.
Note that there is a lot of blank space in the above screen captures since the default dimensions of JTable are quite large but the space required to display the data (in this case) is small. One way to make the JTable smaller (in this case) would be to change the preferred size of the JScrollPane.
EDIT
In response to the question you asked in your comment, namely
is it possible to update on the combobox value change
Yes, it is possible. You add an ActionListener to each JComboBox that simply calls method stopCellEditing. Here is the above code, modified to include the ActionListener. The only changes are in class NumChoiceEd.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class NumTable implements Runnable, TableModelListener {
private boolean adjusting;
private JFrame frame;
private JTable table;
#Override
public void run() {
createGui();
}
#Override
public void tableChanged(TableModelEvent event) {
if (!adjusting) {
adjusting = true;
int col = event.getColumn();
if (col == 1) {
NumChoiceEd editor = (NumChoiceEd) table.getColumnModel().getColumn(1).getCellEditor();
int row = event.getFirstRow();
JComboBox<String> combo = editor.getCombo(row);
if (combo != null) {
int ndx = combo.getSelectedIndex();
if (ndx >= 0) {
int rows = table.getRowCount();
for (int i = 0; i < rows; i++) {
combo = editor.getCombo(i);
String val = combo.getModel().getElementAt(ndx);
table.setValueAt(val, i, col);
}
}
}
}
adjusting = false;
}
}
private void createGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTable(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JScrollPane createTable() {
Object[][] data = new Object[][]{{1, "1"}, {2, "2"}, {3, "3"}};
Object[] columnNames = new Object[]{"Number", "Number Text"};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
model.addTableModelListener(this);
table = new JTable(model);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumnModel tcm = table.getColumnModel();
TableColumn column = tcm.getColumn(1);
column.setCellEditor(new NumChoiceEd());
JScrollPane scrollPane = new JScrollPane(table);
return scrollPane;
}
public static void main(String[] args) {
EventQueue.invokeLater(new NumTable());
}
}
class NumChoiceEd extends DefaultCellEditor {
private static final long serialVersionUID = 1L;
private JComboBox<String> oneCombo;
private JComboBox<String> twoCombo;
private JComboBox<String> threeCombo;
public NumChoiceEd() {
super(new JComboBox<>());
ActionListener al = event -> NumChoiceEd.this.stopCellEditing(); // ADDED THIS LINE
oneCombo = new JComboBox<>(new String[]{"1", "ONE", "FIRST", "ONCE"});
oneCombo.addActionListener(al); // ADDED THIS LINE
twoCombo = new JComboBox<>(new String[]{"2", "TWO", "SECOND", "TWICE"});
twoCombo.addActionListener(al); // ADDED THIS LINE
threeCombo = new JComboBox<>(new String[]{"3", "THREE", "THIRD", "THRICE"});
threeCombo.addActionListener(al); // ADDED THIS LINE
}
public JComboBox<String> getCombo(int row) {
switch (row) {
case 0:
return oneCombo;
case 1:
return twoCombo;
case 2:
return threeCombo;
default:
return null;
}
}
#Override
public Component getTableCellEditorComponent(final JTable table,
final Object value,
final boolean isSelected,
final int row,
final int column) {
if (column == 1) {
switch (row) {
case 0:
return oneCombo;
case 1:
return twoCombo;
case 2:
return threeCombo;
default:
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
else {
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
}
I have the following code:
The issue i am having is that i want to set the last column as a checkbox boolean, tickable yes or no. However when i set the column class as boolean for the column i still get a string, why is my boolean opt for the column not working?
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import java.awt.Dimension;
import javax.swing.JButton;
/**
* TableDemo is just like SimpleTableDemo, except that it uses a custom
* TableModel.
*/
public class NewClass extends JPanel{
private boolean DEBUG = false;
public NewClass() {
JTable table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
//Add the scroll pane to this panel.
add(scrollPane);
}
class MyTableModel extends AbstractTableModel {
private String[] columnNames = { "First Name", "Last Name", "Sport",
"# of Years", "Vegetarian" };
private Object[][] data = {
{ "Mary", "Campione", "Snowboarding", new Integer(5),
new Boolean(false) },
{ "Alison", "Huml", "Rowing", new Integer(3), new Boolean(true) },
{ "Kathy", "Walrath", "Knitting", new Integer(2),
new Boolean(false) },
{ "Sharon", "Zakhour", "Speed reading", new Integer(20),
new Boolean(true) },
{ "Philip", "Milne", "Pool", new Integer(10),
new Boolean(false) } };
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) {
switch (c){
case 0:
return String.class;
case 1:
return String.class;
case 2:
return String.class;
case 3:
return String.class;
case 4:
return boolean.class;// i thought here if i define the column data type as boolean i would get checkboxes why not?
default:
return String.class;
}
}
/**
* Don't need to implement this method unless your table's editable.
*/
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
return false;
}
/**
* Don't need to implement this method unless your table's data can
* change.
*/
public void setValueAt(Object value, int row, int col) {
if (DEBUG) {
System.out.println("Setting value at " + row + "," + col
+ " to " + value + " (an instance of "
+ value.getClass() + ")");
}
data[row][col] = value;
fireTableCellUpdated(row, col);
if (DEBUG) {
System.out.println("New value of data:");
printDebugData();
}
}
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i = 0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j = 0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
NewClass newContentPane = new NewClass();
JButton button = new JButton("Enter");
JPanel mainPane = new JPanel();
mainPane.add(button,BorderLayout.NORTH);
mainPane.add(newContentPane,BorderLayout.CENTER);
//Create and set up the window.
JFrame frame = new JFrame("TableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(mainPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
//System.out.println(human1.eat());
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
This is my Jtable code.filter combo box separately working fine. but in jtable when i typed in combo box field that accept only one char as a input and perform filtering.. i can not type more characters or word.
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.RowFilter;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableRowSorter;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.Vector;
public class TableRenderDemo extends JPanel {
private boolean DEBUG = false;
private TableRowSorter<MyTableModel> sorter;
FilterComboBox acb;
public TableRenderDemo() {
super(new GridLayout(1,0));
acb = new FilterComboBox(populateArray());
JTable table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
//Create a table with a sorter.
/* MyTableModel model = new MyTableModel();
sorter = new TableRowSorter<MyTableModel>(model);
table = new JTable(model);
table.setRowSorter(sorter);
final JTextField textfield = (JTextField) acb.getEditor().getEditorComponent();
RowFilter rowFilter = RowFilter.regexFilter(textfield.getText(), 1);
sorter.setRowFilter(rowFilter);
table.remove();*/
//table.setRowSorter(sorter);
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
//Set up column sizes.
initColumnSizes(table);
//Fiddle with the Sport column's cell editors/renderers.
setUpSportColumn(table, table.getColumnModel().getColumn(2));
//Add the scroll pane to this panel.
add(scrollPane);
}
/*
* This method picks good column sizes.
* If all column heads are wider than the column's cells'
* contents, then you can just use column.sizeWidthToFit().
*/
private void initColumnSizes(JTable table) {
MyTableModel model = (MyTableModel)table.getModel();
TableColumn column = null;
Component comp = null;
int headerWidth = 0;
int cellWidth = 0;
Object[] longValues = model.longValues;
TableCellRenderer headerRenderer =
table.getTableHeader().getDefaultRenderer();
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
comp = headerRenderer.getTableCellRendererComponent(
null, column.getHeaderValue(),
false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
comp = table.getDefaultRenderer(model.getColumnClass(i)).
getTableCellRendererComponent(
table, longValues[i],
false, false, 0, i);
cellWidth = comp.getPreferredSize().width;
if (DEBUG) {
System.out.println("Initializing width of column "
+ i + ". "
+ "headerWidth = " + headerWidth
+ "; cellWidth = " + cellWidth);
}
column.setPreferredWidth(Math.max(headerWidth, cellWidth));
}
}
public static Vector<String> populateArray() {
Vector<String> test = new Vector<String>();
test.add("");
test.add("Mountain Flight");
test.add("Mount Climbing");
test.add("Trekking");
test.add("Rafting");
test.add("Jungle Safari");
test.add("Bungie Jumping");
test.add("Para Gliding");
return test;
}
public void setUpSportColumn(JTable table,
TableColumn sportColumn) {
//Set up the editor for the sport cells.
/* JComboBox comboBox = new JComboBox();
comboBox.addItem("Snowboarding");
comboBox.addItem("Rowing");
comboBox.addItem("Knitting");
comboBox.addItem("Speed reading");
comboBox.addItem("Pool");
comboBox.addItem("None of the above");
comboBox.setEditable(true);*/
acb = new FilterComboBox(populateArray());
sportColumn.setCellEditor(new DefaultCellEditor(acb));
//Set up tool tips for the sport cells.
/* DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
sportColumn.setCellRenderer(renderer);*/
}
class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
private Object[][] data = {
{"Kathy", "Smith",
"", new Integer(5), new Boolean(false)},
{"John", "Doe",
"Rowing", new Integer(3), new Boolean(true)},
{"Sue", "Black",
"Knitting", new Integer(2), new Boolean(false)},
{"Jane", "White",
"Speed reading", new Integer(20), new Boolean(true)},
{"Joe", "Brown",
"Pool", new Integer(10), new Boolean(false)}
};
public final Object[] longValues = {"Jane", "Kathy",
"None of the above",
new Integer(20), Boolean.TRUE};
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];
}
/*
* JTable uses this method to determine the default renderer/
* editor for each cell. If we didn't implement this method,
* then the last column would contain text ("true"/"false"),
* rather than a check box.
*/
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/*
* Don't need to implement this method unless your table's
* editable.
*/
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
if (col < 2) {
return false;
} else {
return true;
}
}
/*
* Don't need to implement this method unless your table's
* data can change.
*/
public void setValueAt(Object value, int row, int col) {
if (DEBUG) {
System.out.println("Setting value at " + row + "," + col
+ " to " + value
+ " (an instance of "
+ value.getClass() + ")");
}
data[row][col] = value;
fireTableCellUpdated(row, col);
if (DEBUG) {
System.out.println("New value of data:");
printDebugData();
}
}
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i=0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j=0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TableRenderDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
TableRenderDemo newContentPane = new TableRenderDemo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
FilterComboBox.java
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class FilterComboBox extends JComboBox {
private List<String> array;
JTextField textfield;
public FilterComboBox(Vector<String> array) {
super(array.toArray());
this.array = array;
this.setEditable(true);
textfield = (JTextField) this.getEditor().getEditorComponent();
textfield.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent ke) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final String inputTxt=textfield.getText();
comboFilter(inputTxt);
}
});
}
});
}
public void comboFilter(String enteredText) {
if (!this.isPopupVisible()) {
this.showPopup();
}
Vector<String> filterArray= new Vector<String>();
for (int i = 0; i < array.size(); i++) {
if (array.get(i).toLowerCase().contains(enteredText.toLowerCase())) {
filterArray.add(array.get(i));
}
}
System.out.println("val "+enteredText+" size "+filterArray);
if (filterArray.size() > 0) {
DefaultComboBoxModel model = (DefaultComboBoxModel) this.getModel();
model.removeAllElements();
for (String s: filterArray)
model.addElement(s);
textfield.setText(enteredText);
//System.out.println("set txt "+enteredText);
}
else if(filterArray.size()==0)
{
DefaultComboBoxModel model = (DefaultComboBoxModel) this.getModel();
model.removeAllElements();
textfield.setText(enteredText);
// System.out.println("set txt "+enteredText);
}
}
/* Testing Codes */
public static Vector<String> populateArray() {
Vector<String> test = new Vector<String>();
test.add("");
test.add("Mountain Flight");
test.add("Mount Climbing");
test.add("Trekking");
test.add("Rafting");
test.add("Jungle Safari");
test.add("Bungie Jumping");
test.add("Para Gliding");
return test;
}
public static void makeUI() {
JFrame frame = new JFrame("Adventure in Nepal - Combo Filter Test");
FilterComboBox acb = new FilterComboBox(populateArray());
frame.getContentPane().add(acb);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) throws Exception {
//UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
makeUI();
}
}
I'm new to GUI design and I'm trying to plan this out before I go too far the wrong way, any help would be nice. I'm trying to display a JTable with rows of Employee, which itself has datatypes of String and ArrayList<Cert>. Cert contains a String.
I'd like to have the table present the data for editing, but for a few of the columns I'd like to implement a JComboBox for selection of a String from a set of valid strings, as well as color each option differently (different background colors in the JComboBox).
Also, the ArrayList<Cert> currently displays in a cell as [xxx, xxx, ...] where XXX is the return from the toString() function for each item in the ArrayList. I think I'd like to display that ArrayList<Cert> as a read-only JComboBox, but I'm not as concerned with this item.
I'm questioning how many classes I need to create to make this happen. I already have a custom model for the JTable extending AbstractTableModel. Do I need to write an extension of JComboBox or do I just need to extend the appropriate renderer for a JComboBox as a cell and do the magic there, then assign that custom renderer to the cell renderer for the String cell?
Here's what I have so far, lightly abridged:
public class EmployeeTableModel extends AbstractTableModel {
...
private ArrayList<Employee> myDataObjects = new ArrayList<Employee>();
...
#Override
public Object getValueAt(int row, int column) {
Employee emp = myDataObjects.get(row);
switch (column) {
case 0:
return emp.getName();
case 1:
return emp.getShift();
case 2:
return emp.getCertifications();
default:
return "";
}
}
}
Employees:
public class Employee {
private String name;
private String shift;
private ArrayList<Cert> certs;
...
public String getName() {
return name;
}
public String getShift() {
return shift;
}
public ArrayList<Cert> getCerts() {
return certs;
}
...
}
And the initializations:
EmployeeTableModel etm = new EmployeeTableModel();
JTable employeeTable = new JTable();
employeeTable.setModel( etm );
you can to start with, simplest code as is possible, maybe depends if you want to see JComboBox as Renderer too by #aterai
import java.awt.BorderLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
public class TableRenderDemo extends JPanel {
private static final long serialVersionUID = 1L;
public TableRenderDemo() {
super(new BorderLayout(5, 5));
final JTable table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(table.getPreferredSize());
table.setFillsViewportHeight(true);
table.setRowHeight(20);
JScrollPane scrollPane = new JScrollPane(table);
initColumnSizes(table);
setUpSportColumn(table, table.getColumnModel().getColumn(2));
add(scrollPane, BorderLayout.CENTER);
JButton resetButton = new JButton("Reset to default");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < table.getRowCount(); i++) {
table.getModel().setValueAt("None of the above", i, 2);
}
}
});
add(resetButton, BorderLayout.SOUTH);
}
private void initColumnSizes(JTable table) {
MyTableModel model = (MyTableModel) table.getModel();
TableColumn column = null;
Component comp = null;
int headerWidth = 0;
int cellWidth = 0;
Object[] longValues = model.longValues;
TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer();
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
comp = headerRenderer.getTableCellRendererComponent(null, column.getHeaderValue(), false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
comp = table.getDefaultRenderer(model.getColumnClass(i)).getTableCellRendererComponent(table, longValues[i], false, false, 0, i);
cellWidth = comp.getPreferredSize().width;
column.setPreferredWidth(Math.max(headerWidth, cellWidth));
}
}
private void setUpSportColumn(JTable table, TableColumn sportColumn) {
ArrayList<String> listSomeString = new ArrayList<String>();
listSomeString.add("Snowboarding");
listSomeString.add("Rowing");
listSomeString.add("Knitting");
listSomeString.add("Speed reading");
listSomeString.add("Pool");
listSomeString.add("None of the above");
JComboBox comboBox = new JComboBox();
comboBox.addItem(new Item(1, "-"));
comboBox.addItem(new Item(2, "Snowboarding"));
comboBox.addItem(new Item(3, "Rowing"));
comboBox.addItem(new Item(4, "Knitting"));
comboBox.addItem(new Item(5, "Speed reading"));
comboBox.addItem(new Item(6, "Pool"));
comboBox.addItem(new Item(7, "None of the above"));
comboBox.setMaximumRowCount(3);
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JComboBox comboBox = (JComboBox) e.getSource();
Item item = (Item) comboBox.getSelectedItem();
System.out.println(item.getId() + " : " + item.getDescription());
}
});
comboBox.setRenderer(new ItemRenderer());
sportColumn.setCellEditor(new DefaultCellEditor(comboBox));
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
sportColumn.setCellRenderer(renderer);
}
class ItemRenderer extends BasicComboBoxRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value != null) {
Item item = (Item) value;
setText(item.getDescription().toUpperCase());
}
if (index == -1) {
Item item = (Item) value;
setText("" + item.getId());
}
return this;
}
}
class Item {
private int id;
private String description;
public Item(int id, String description) {
this.id = id;
this.description = description;
}
public int getId() {
return id;
}
public String getDescription() {
return description;
}
#Override
public String toString() {
return description;
}
}
class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"};
private Object[][] data = {{"Kathy", "Smith", "Snowboarding", new Integer(5), false},
{"John", "Doe", "Rowing", new Integer(3), true}, {"Sue", "Black", "Knitting", new Integer(2), false},
{"Jane", "White", "Speed reading", new Integer(20), true}, {"Joe", "Brown", "Pool", new Integer(10), false}};
public final Object[] longValues = {"Jane", "Kathy", "None of the above", new Integer(20), Boolean.TRUE};
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
return data.length;
}
#Override
public String getColumnName(int col) {
return columnNames[col];
}
#Override
public Object getValueAt(int row, int col) {
return data[row][col];
}
#Override
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
if (col < 2) {
return false;
} else {
return true;
}
}
#Override
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
System.out.println("New value of data: " + getValueAt(row, col));
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("TableRenderDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableRenderDemo newContentPane = new TableRenderDemo();
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
I'm working on a code in Java Swing. I have created a JComboBox in JTable. It's working :). But once I select a value and click on the save or cancel button, it has to reset to the default value (1st value in the combo box). I tried a lot of ways like combobox.setSelectedIndex(0). This isn't working.
Code:
String[] manTimeHr = { "00","01", "02", "03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23"};
String[] manTimeMin = {"00","01", "02", "03","04","05","06","07","08","09","10","11","12","13", "14", "15","16","17","18","19","20","21","22","23","24","25", "26", "27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59"};
String[][] data = {{"-select-","-select-"}};
String[] cols = {"Hrs","Mins"};
String[][] data1 = {{"-select-","-select-"}};
String[] cols1 = {"Hrs","Mins"};
JLabel manTimeStart = new JLabel("Start From",JLabel.LEFT);
STimeTbl = new JTable(data,cols);
hrsColumn=STimeTbl.getColumnModel().getColumn(0);
minsColumn=STimeTbl.getColumnModel().getColumn(1);
manSiteStimeHrCBx = new JComboBox(manTimeHr);
manSiteStimeHrCBx.setSelectedIndex(0);
hrsColumn.setCellEditor(new DefaultCellEditor(manSiteStimeHrCBx));
manSiteStimeMinCBx = new JComboBox(manTimeMin);
manSiteStimeMinCBx.setSelectedIndex(0);
minsColumn.setCellEditor(new DefaultCellEditor(manSiteStimeMinCBx));
JLabel manTimeEnd = new JLabel("End To",JLabel.LEFT);
ETimeTbl = new JTable(data1,cols1);
hrsColumn1=ETimeTbl.getColumnModel().getColumn(0);
minsColumn1=ETimeTbl.getColumnModel().getColumn(1);
manSiteEtimeHrCBx = new JComboBox(manTimeHr);
manSiteEtimeHrCBx.setSelectedIndex(0);
hrsColumn1.setCellEditor(new DefaultCellEditor(manSiteEtimeHrCBx));
manSiteEtimeMinCBx = new JComboBox(manTimeMin);
manSiteEtimeMinCBx.setSelectedIndex(0);
minsColumn1.setCellEditor(new DefaultCellEditor(manSiteEtimeMinCBx));
.
.
.
.
if("Save".equals(e.getActionCommand())) {
try{
mSHr = Integer.parseInt((String)manSiteStimeHrCBx.getSelectedItem());
mEHr=Integer.parseInt((String)manSiteEtimeHrCBx.getSelectedItem());
mSMin=Integer.parseInt((String)manSiteStimeMinCBx.getSelectedItem());
mEMin=Integer.parseInt((String)manServEtimeMinCBx.getSelectedItem());
}catch (Exception en){
System.out.println("Main Exception : "+ en);
return;
}
if(validateBlockTime(mSHr,mEHr,mSMin,mEMin) != true)
{
System.out.println("Enter valid Time");
return;
}
manSiteStimeHrCBx.setSelectedIndex(0);
manSiteStimeMinCBx.setSelectedIndex(0);
manSiteEtimeHrCBx.setSelectedIndex(0);
manSiteEtimeMinCBx.setSelectedIndex(0);
.
.
.
private static boolean validateBlockTime(int val3, int val4, int val5, int val6){
if(val4 > val3)
return true;
else if((val4 == val3) && (val6 > val5))
return true;
else
return false;
}
JTable tutorial contains description about Combo Box as an Editor
all data are stored in the XxxTableModel
all changes in the JTable view are described in Concepts: Editors and Renderers
then you have to know that in the XxxTableModel is stored only String value (or Double or Long or Integer or Icon, depends of value stored in ComboBoxModel) for Combo Box as an Editor
result is
quick code (sorry I'm so lazy) based on tutorial code
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import javax.swing.JButton;
public class TableRenderDemo extends JPanel {
private static final long serialVersionUID = 1L;
private boolean DEBUG = false;
public TableRenderDemo() {
super(new BorderLayout(5, 5));
final JTable table = new JTable(new MyTableModel());
table.setRowHeight(18);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
initColumnSizes(table);
setUpSportColumn(table, table.getColumnModel().getColumn(2));
add(scrollPane);
JButton resetButton = new JButton("Reset to default");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < table.getRowCount(); i++) {
table.getModel().setValueAt("None of the above", i, 2);
}
}
});
add(resetButton, BorderLayout.SOUTH);
}
private void initColumnSizes(JTable table) {
MyTableModel model = (MyTableModel) table.getModel();
TableColumn column = null;
Component comp = null;
int headerWidth = 0;
int cellWidth = 0;
Object[] longValues = model.longValues;
TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer();
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
comp = headerRenderer.getTableCellRendererComponent(null, column.getHeaderValue(), false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
comp = table.getDefaultRenderer(model.getColumnClass(i)).getTableCellRendererComponent(table, longValues[i], false, false, 0, i);
cellWidth = comp.getPreferredSize().width;
if (DEBUG) {
System.out.println("Initializing width of column " + i + ". " + "headerWidth = " + headerWidth + "; cellWidth = " + cellWidth);
}
column.setPreferredWidth(Math.max(headerWidth, cellWidth));
}
}
private void setUpSportColumn(JTable table, TableColumn sportColumn) {
JComboBox comboBox = new JComboBox();
comboBox.addItem("Snowboarding");
comboBox.addItem("Rowing");
comboBox.addItem("Knitting");
comboBox.addItem("Speed reading");
comboBox.addItem("Pool");
comboBox.addItem("None of the above");
sportColumn.setCellEditor(new DefaultCellEditor(comboBox));
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
sportColumn.setCellRenderer(renderer);
}
private class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"};
private Object[][] data = {
{"Kathy", "Smith", "Snowboarding", new Integer(5), false},
{"John", "Doe", "Rowing", new Integer(3), true},
{"Sue", "Black", "Knitting", new Integer(2), false},
{"Jane", "White", "Speed reading", new Integer(20), true},
{"Joe", "Brown", "Pool", new Integer(10), false}
};
public final Object[] longValues = {"Jane", "Kathy", "None of the above", new Integer(20), Boolean.TRUE};
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
#Override
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
#Override
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
if (col < 2) {
return false;
} else {
return true;
}
}
#Override
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
System.out.println(getValueAt(row, col));
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("TableRenderDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableRenderDemo newContentPane = new TableRenderDemo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
output from AbstractTableModel, code line 135th.
run:
None of the above
None of the above
None of the above
None of the above
None of the above
BUILD SUCCESSFUL (total time: 37 seconds)