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();
}
});
}
}
Related
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());
}
}
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 want to implement a custom JComboBox as an CellEditor for a JTable. I took the original Java Example and modified it by implementing a Sports class
Please run the source code, click on the JComboBox and you will note that the selected item is not selected anymore when the ComboBox opens.
I want to keep the renderered item in the combobox selection.
Original: http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#combobox
public class Sport {
private Integer id;
private String name;
public Sport(String name){
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
}
public class TableRenderDemo extends JPanel {
private boolean DEBUG = false;
public TableRenderDemo() {
super(new GridLayout(1,0));
JTable table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
//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 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");
sportColumn.setCellEditor(new DefaultCellEditor(comboBox));
//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 Sport("Snowboarding"),
new Integer(5), new Boolean(false)},
{"John", "Doe",
new Sport("Rowing"), new Integer(3), new Boolean(true)},
{"Sue", "Black",
new Sport("Knitting"), new Integer(2), new Boolean(false)},
{"Jane", "White",
new Sport("Speed reading"), new Integer(20), new Boolean(true)},
{"Joe", "Brown",
new Sport("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();
}
});
}
}
Ok I included the following, but still the same problem:
public void setUpSportColumn(JTable table,
TableColumn sportColumn) {
//Set up the editor for the sport cells.
JComboBox<Sport> comboBox = new JComboBox();
comboBox.addItem(new Sport("Snowboarding"));
comboBox.addItem(new Sport("Rowing"));
comboBox.addItem(new Sport("Knitting"));
comboBox.addItem(new Sport("Speed reading"));
comboBox.addItem(new Sport("Pool"));
comboBox.addItem(new Sport("None of the above"));
sportColumn.setCellEditor(new DefaultCellEditor(comboBox));
//Set up tool tips for the sport cells.
DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
sportColumn.setCellRenderer(renderer);
// sportColumn.setCellEditor(new MyCellEditor());
}
You also need to override the equals(...) and hashcode(...) methods of the Sport class. Java Collection methods rely on these methods to determine equality of a object instance when doing searches.
#Override
public boolean equals(Object object)
{
Sport sport = (Sport)object;
return this.name.equals( sport.getName() );
}
#Override
public int hashCode()
{
return name.hashCode();
}
Also, read the Object API for more information on these methods.
Your model contains instances of Sport class but the JCombobox contains strings. That's why set selection can't find proper value.
Try to add sports like this
comboBox.addItem(new Sport("Rowing"));
And either override toString() method of Sport class to return the name (easier way). Or add a custom renderer to the sports combo box.
I'm working on jTable and I intend on deleting specific rows as part of the data manipulation to be conducted on the table. Essentially I've been able to successfully delete a row which the user would specify but I what I really want to do is to delete several rows based on boolean states or check boxes that are selected as part one of the four columns of the table.
I've attached a screenshot as to the current result of running the code and would like to be able to delete the rows based on the selected boolean states or check boxes.
Below is my code including my table model code which extends the AbstractTableModel:
package com.TableRowSelectProgramatically;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
#SuppressWarnings("serial")
public class JTableRowSelectProgramatically extends JPanel {
public MyTableModel MyTableModel;
public String Cell1 = "ABCD";
public JTableRowSelectProgramatically() {
initializePanel();
}
private void initializePanel() {
setLayout(null);
setPreferredSize(new Dimension(1250, 700));
// Table model
MyTableModel = new MyTableModel();
// Table
final JTable table = new JTable(MyTableModel);
table.setFillsViewportHeight(true);
// Row data
Object[] values = {Cell1, "EFGH", "IJKL", new Boolean(false)};
Object[] values2 = {"UVWX","QRST","MNOP", new Boolean(false)};
Object[] values3 = {"ABCD","YZAB","CDEF", new Boolean(false)};
final Object[] values4 = {"QWERTY","YTREWQ","QWERTY", new Boolean(false)};
// Insert row data
MyTableModel CustomTableModel = (MyTableModel) table.getModel();
CustomTableModel.insertData(values);
CustomTableModel.insertData(values2);
CustomTableModel.insertData(values3);
CustomTableModel.insertData(values);
CustomTableModel.insertData(values2);
CustomTableModel.insertData(values3);
CustomTableModel.insertData(values);
CustomTableModel.insertData(values2);
CustomTableModel.insertData(values3);
// Create edit menu label
JLabel labelEditMenu = new JLabel("EDIT MENU:\n");
// Create add row btn
JButton addRow = new JButton("Add Row");
// Attach listener for add row btn
addRow.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
MyTableModel.insertData(values4);
}
});
// Create delete row btn
JButton deleteRow = new JButton("Delete Row");
// Attach listener for delete btn
deleteRow.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
MyTableModel.removeRow(1);
}
});
// Create scroll pane
JScrollPane pane = new JScrollPane(table);
pane.setBounds(30, 30, 500, 500);
//
JTextField AgentIDTextField = new JTextField();
// Populate the JPanel
JPanel dataEntryPanel = new JPanel(new FlowLayout());
//dataEntryPanel.setBackground(Color.orange);
dataEntryPanel.setBounds(540, 30, 500, 50);
//dataEntryPanel.add(AgentIDTextField);
dataEntryPanel.add(labelEditMenu);
dataEntryPanel.add(addRow);
dataEntryPanel.add(deleteRow);
// Join up GUI
add(pane);
add(dataEntryPanel);
}
// Enable visibity of frame
public static void showFrame() {
JPanel panel = new JTableRowSelectProgramatically();
JFrame frame = new JFrame("Test table");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
// Launch prog
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTableRowSelectProgramatically.showFrame();
}
});
}
// Create custom table model for data entry
class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"COLUMN 0", "COLUMN 1", "COLUMN 2", "COLUMN 3"};
private Vector data = new Vector();
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#SuppressWarnings("rawtypes")
#Override
public Object getValueAt(int row, int col) {
return ((Vector) data.get(row)).get(col);
}
public String getColumnName(int col){
return columnNames[col];
}
public Class getColumnClass(int c){
return getValueAt(0,c).getClass();
}
public void setValueAt(Object value, int row, int col){
((Vector) data.get(row)).setElementAt(value, col);
fireTableCellUpdated(row,col);
}
public boolean isCellEditable(int row, int col){
if (3 == col){
return true;
}
else {
return false;
}
}
public void insertData(Object[] values){
data.add(new Vector());
for(int i =0; i<values.length; i++){
System.out.println("data.size is: " + data.size());
((Vector) data.get(data.size()-1)).add(values[i]);
}
fireTableDataChanged();
}
public void removeRow(int row){
data.removeElementAt(row);
fireTableDataChanged();
}
}
}
New attempt at deleting rows of a JTable:
public void deleteRow() {
for (int i = 0; i < getRowCount(); i++) {
Object columnState = getValueAt(i, 3);
System.out.println("STEP 6 - In row " + i + " boolean value is: " + columnState);
boolean columnStateAsBoolean = (Boolean) columnState;
System.out.println("STEP 6 - In row " + i + " Column State As Boolean is: " + columnStateAsBoolean);
if(columnStateAsBoolean == true) {
removeRow(i);
}
System.out.println("-------------------------------------");
}
}
I really want to do is to delete several rows based on boolean states or check boxes
create a loop that starts on the last row and counts down to 0.
Then for every row you use the table.getValueAt(...) method to get the Boolean value of the column.
If the value is true then delete the row.
//Try something like this
int rowCount=table.getSelectedRowCount();//get selected row's count
int row;
if(rowCount>0)
{
while((row=table.getSelectedRow())!=-1)
(DefaultTableModel)table.getModel().removeRow(table.convertRowIndexToModel(row));
}
EDIT
I've tried changing the table model back to DefaultTableModel but I am getting an Exception when compiling my code and I can't figure out why!
Here's my table init:
jTable1.setModel(new Table1Model());
jTable1.setDefaultRenderer(Color.class,new ColorRenderer(true));
jTable1.getColumnModel().getColumn(5).setCellEditor(new ColorEditor());
My class extending the model:
class Table1Model extends DefaultTableModel {
//private String[] columnNames = {"Station #",
private Object[] columnNames = {"Station #",
"Name",
"avg Time",
"Buffer",
"Buffer Parts",
"Color"};
private Object[][] data = {
{"1", "Station 1",
new Integer(10), false, new Integer(0), Color.red},
{"2", "Station 2",
new Integer(10), false, new Integer(0), Color.blue},
{"3", "Station 3",
new Integer(10), false, new Integer(0), Color.green},
{"4", "Station 4",
new Integer(10), false, new Integer(0), Color.orange},
{"5", "Station 5",
new Integer(10), false, new Integer(0), Color.black}
};
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
//int length = data.length;
//int datalength = Integer.parseInt(length);
return data.length;
}
#Override
public String getColumnName(int col) {
return columnNames[col].toString();
}
#Override
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.
*/
#Override
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/*
* Don't need to implement this method unless your table's
* editable.
*/
#Override
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
if (col == 0) { return false; }
else if (col == 4) {
boolean di = (Boolean) getValueAt(row,(col-1));
if (!di) { return false; }
else { return true; }
}
else { return true; }
}
/*
* Don't need to implement this method unless your table's
* data can change.
*/
#Override
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
/*public void removeRow(int row) {
data.removeRow(row);
}*/
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("--------------------------");
}
}
This generates the following error:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at SimGui$Table1Model.getRowCount(SimGui.java:863)
at javax.swing.table.DefaultTableModel.setDataVector(DefaultTableModel.java:224)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:124)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:106)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:86)
at SimGui$Table1Model.<init>(SimGui.java:832)
at SimGui.initComponents(SimGui.java:265)
at SimGui.<init>(SimGui.java:34)
at SimGui$16.run(SimGui.java:789)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:701)
at java.awt.EventQueue.access$000(EventQueue.java:102)
at java.awt.EventQueue$3.run(EventQueue.java:662)
at java.awt.EventQueue$3.run(EventQueue.java:660)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:671)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)
Can you help me figure out what's wrong?
Also, will I be able to use the ColorEditor with the DefaultTableModel?
You have two obvious choices here: either give your class a getVectorData() method or else give it another similarly useful method that allows you to extract the nucleus of your data from your model. You probably shouldn't use an AbstractTableModel variable though but rather use a variable of your own custom type that extends AbstractTableModel to allow you to be able to call custom methods of your model.
i.e.,
MyTableModel model = (MyTableModel)jTable1.getModel();
SomeCollection myKeyData = model.getMyKeyData();
Also, this statement:
I have recently created my own class to extend AbstractTableModel to be able to insert some logic on isCellEditable and setValueAt.
Doesn't make sense to me since you could always use a DefaultTableModel and simply override those two methods. But if you use a DefaultTableModel, don't also have it hold the 2D array of object as you're trying to do. Rather feed the data into its internal data via the appropriate constructor or via its addRow(...) method. Else you lose all the power that DefaultTableModel has to offer.
Edit
If you want to use a DefaultTableModel to leverage its methods, then you cannot use a separate data "nucleus" for your model (here your Object[][]), but instead must load your data into the model that is held inside of the DefaultTableModel super class. This can be done either via the correct super constructor or by adding rows of data using its addRow(...) method.
For example, here I load your data into a DefaultTableModel override:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.table.*;
public class TableModelTest extends JPanel {
private static final Object[][] DATA = {
{ "1", "Station 1", new Integer(10), false, new Integer(0), Color.red },
{ "2", "Station 2", new Integer(10), false, new Integer(0), Color.blue },
{ "3", "Station 3", new Integer(10), false, new Integer(0),
Color.green },
{ "4", "Station 4", new Integer(10), false, new Integer(0),
Color.orange },
{ "5", "Station 5", new Integer(10), false, new Integer(0),
Color.black } };
private MyTableModel myTableModel = new MyTableModel(DATA);
private JTable table = new JTable(myTableModel);
public TableModelTest() {
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
table.getColumnModel().getColumn(5)
.setCellRenderer(new ColorCellRenderer());
table.getColumnModel().getColumn(5).setCellEditor(new ColorCellEditor());
}
private static void createAndShowGui() {
TableModelTest mainPanel = new TableModelTest();
JFrame frame = new JFrame("TableModelTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ColorCellEditor extends AbstractCellEditor implements TableCellEditor {
Color currentColor;
JButton button;
JColorChooser colorChooser;
JDialog dialog;
protected static final String EDIT = "edit";
public ColorCellEditor() {
ActionListener actionListener = new MyActionListener();
button = new JButton();
button.setActionCommand(EDIT);
button.addActionListener(actionListener);
button.setBorderPainted(false);
colorChooser = new JColorChooser();
dialog = JColorChooser.createDialog(button, "Pick a Color", true,
colorChooser, actionListener, null);
}
private class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (EDIT.equals(e.getActionCommand())) {
button.setBackground(currentColor);
colorChooser.setColor(currentColor);
dialog.setVisible(true);
fireEditingStopped();
} else {
currentColor = colorChooser.getColor();
}
}
}
public Object getCellEditorValue() {
return currentColor;
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
currentColor = (Color) value;
return button;
}
}
class ColorCellRenderer implements TableCellRenderer {
private static final int IMG_WIDTH = 70;
private static final int IMG_HEIGHT = 20;
private JLabel label = new JLabel();
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean arg2, boolean arg3, int arg4, int arg5) {
Color color = (Color) value;
BufferedImage img = new BufferedImage(IMG_WIDTH, IMG_HEIGHT,
BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics();
g.setColor(color);
g.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT);
g.dispose();
ImageIcon icon = new ImageIcon(img);
label.setIcon(icon);
return label;
}
}
class MyTableModel extends DefaultTableModel {
private static final String[] COLUMN_NAMES = { "Station #", "Name",
"avg Time", "Buffer", "Buffer Parts", "Color" };
public MyTableModel(Object[][] data) {
super(data, COLUMN_NAMES);
}
#Override
public boolean isCellEditable(int row, int col) {
if (col == 0) {
return false;
} else if (col == 4) {
boolean di = (Boolean) getValueAt(row, (col - 1));
if (!di) {
return false;
} else {
return true;
}
} else {
return true;
}
}
public 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++) {
Object datum = getValueAt(i, j);
// System.out.print(" " + data[i][j]);
System.out.print(" " + datum);
}
System.out.println();
}
System.out.println("--------------------------");
}
}