How to get jComboBox on certain cell in jTable? - java

I'm trying to create a jComboBox in a certain cell from a jTable. If on the same line in column 4 you have the value "FN", you will have on the column 5 a jComboBox with 3 options ("SSAA-MM-JJ", "SSAA/MM/JJ", "SAAMMJJ"), but all the other cells on column 5 must remain untouched if the value from the cell on column 4 on the same row is not "FN".
What do I do wrong?
Here is what i've tried:
package rdjcsv;
import java.awt.Component;
import javax.swing.AbstractCellEditor;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.TableCellEditor;
/**
*
* #author acucu
*/
class MyCellEditor extends AbstractCellEditor implements TableCellEditor {
DefaultCellEditor other = new DefaultCellEditor(new JTextField());
DefaultCellEditor checkbox = new DefaultCellEditor(new JComboBox(new Object[] {"abc"}));
private DefaultCellEditor lastSelected;
#Override
public Object getCellEditorValue() {
return lastSelected.getCellEditorValue();
}
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
if(column == 4 && table.getValueAt(row, column-1).toString().contains("FN")){
if(row == 0) {
lastSelected = checkbox;
return checkbox.getTableCellEditorComponent(table, value, isSelected, row, column);
}
lastSelected = other;
return other.getTableCellEditorComponent(table, value, isSelected, row, column);
}
return other.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
And the call:
String[] values = new String[] {"SSAA-MM-JJ", "SSAA/MM/JJ", "SAAMMJJ"};
TableColumn col = jTable1.getColumnModel().getColumn(4);
col.setCellEditor(new MyComboBoxEditor(values));
col.setCellRenderer(new MyComboBoxRenderer(values));
The output:
jComboBox es on every cell from the 5th column.

Your image is showing the output from the cell renderer, not the cell editor, since only one cell editor should be visible at any time. You don't want the renderer to look like a JComboBox but rather to display as text, as a label. This suggests other problems with your program.
Other issues:
Your code above risks a NPE since lastSelected can be null when it starts out.
Why are you checking that row == 0? Do you to use the JComboBox editor for the first row only?
Post your minimal example program if still stuck,
for example, mine:
import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
#SuppressWarnings("serial")
public class ComboEditorEg extends JPanel {
private MyTableModel model = new MyTableModel();
private JTable table = new JTable(model);
public ComboEditorEg() {
for (int i = 0; i < 10; i++) {
String textA = i % 2 == 0 ? "SA" : "FN";
String textB = i % 2 == 0 ? "A" : "B";
Object[] row = new String[] { textA, textB };
model.addRow(row);
}
table.getColumnModel().getColumn(1).setCellEditor(new MyCellEditor());
setLayout(new BorderLayout());
add(new JScrollPane(table));
}
private static void createAndShowGui() {
ComboEditorEg mainPanel = new ComboEditorEg();
JFrame frame = new JFrame("ComboEditorEg");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
#SuppressWarnings("serial")
class MyTableModel extends DefaultTableModel {
public static final String[] COL_NAMES = { "Foo 1", "Foo 2" };
public MyTableModel() {
super(COL_NAMES, 0);
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
}
#SuppressWarnings("serial")
class MyCellEditor extends AbstractCellEditor implements TableCellEditor {
DefaultCellEditor other = new DefaultCellEditor(new JTextField());
DefaultCellEditor checkbox = new DefaultCellEditor(new JComboBox<String>(new String[] { "abc",
"def", "ghi" }));
private DefaultCellEditor lastSelected = other; // so it's not null
#Override
public Object getCellEditorValue() {
return lastSelected.getCellEditorValue();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column) {
if (table.getValueAt(row, column - 1).toString().contains("FN")) {
lastSelected = checkbox;
return checkbox.getTableCellEditorComponent(table, value, isSelected, row, column);
}
return other.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}

Related

How to do a selection in cascade of JCombobox choices in a JTable?

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);
}
}
}

JTable change color for entire column when values changed - Swing

I tried to find here for a long time answer for my question but without the exact result i expected.
I have JTable which every time i am changing values in entire column (only in one column every time).
I want to listen to a table changes and when data changes in the column, the color in the column will be changed too and all other columns will be in the default color.
This is the code for the table listener:
Class CustomCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component rendererComp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
table.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
if(***here i want to know which column changed or something like that***){
rendererComp.setBackground(Color.CYAN);
}
}
});
return rendererComp ;
}
}
and this is the code for the table creation:
private void createTable() {
tablePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
DefaultTableModel tableModel = new DefaultTableModel(){
#Override
public boolean isCellEditable(int row, int column) {
//all cells false
return false;
}
};
contentTable = new JTable(tableModel);
contentTable.setGridColor(Color.LIGHT_GRAY);
for(int i=0; i<columnSize; i++) {
tableModel.addColumn("0");
}
for(int i=0; i<rawSize; i++) {
tableModel.addRow(new Object[] { "" });
}
for(int i=0; i<rawSize; i++) {
for(int j=0; j<tableModel.getRowCount(); j++) {
tableModel.setValueAt("0", j, i);
}
}
for(int i=0; i<ramSize; i++) {
contentTable.getColumnModel().getColumn(i).setCellRenderer(new CustomCellRenderer());
}
JScrollPane scrollPane = new JScrollPane(contentTable);
scrollPane.setPreferredSize(new Dimension(400, 150));
tablePanel.add(scrollPane);
}
Store the desired state in the TableModel; let the TableCellRenderer use the state to condition the view accordingly. In the example below, as soon as setValueAt() updates any cell, edited is marked true. The render, which is applied to column zero, changes the display accordingly. Note how clearEdited() invokes fireTableDataChanged() to force the table to render all cells when called in the Clear handler.
Addendum: The update below shows one approach to handling multiple columns independently. The CustomModel now contains a Map<Integer, Boolean> to store the edited state for each column to which the CustomRenderer is applied. As an aside, the CustomRenderer now invokes convertColumnIndexToModel() and sets the selection color correctly.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
/**
* #see http://stackoverflow.com/a/37439731/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CustomModel model = new CustomModel();
model.setColumnIdentifiers(new String[]{"A", "B"});
for (int i = 0; i < 16; i++) {
model.addRow(new String[]{"A:" + i, "B:" + i});
}
JTable table = new JTable(model) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(100, getRowHeight() * getRowCount() / 2);
}
};
table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer(model));
table.getColumnModel().getColumn(1).setCellRenderer(new CustomRenderer(model));
f.add(new JScrollPane(table));
JPanel p = new JPanel();
p.add(new JButton(new UpdateAction("Update A", model, 0)));
p.add(new JButton(new UpdateAction("Update B", model, 1)));
p.add(new JButton(new AbstractAction("Clear") {
#Override
public void actionPerformed(ActionEvent e) {
model.clearEdited(0);
model.clearEdited(1);
}
}));
f.add(p, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class CustomModel extends DefaultTableModel {
private final Map<Integer, Boolean> edited = new HashMap<>();
public boolean isEdited(int column) {
return edited.get(column) != null && edited.get(column);
}
public void clearEdited(int column) {
edited.put(column, false);
fireTableDataChanged();
}
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
#Override
public void setValueAt(Object aValue, int row, int column) {
super.setValueAt(aValue, row, column);
edited.put(column, true);
}
}
private static class CustomRenderer extends DefaultTableCellRenderer {
private final CustomModel model;
public CustomRenderer(CustomModel model) {
this.model = model;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
Component c = super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, col);
if (model.isEdited(table.convertColumnIndexToModel(col))) {
c.setBackground(Color.cyan);
} else if (isSelected) {
c.setBackground(table.getSelectionBackground());
} else {
c.setBackground(table.getBackground());
}
return c;
}
}
private static class UpdateAction extends AbstractAction {
private final CustomModel model;
private final int column;
public UpdateAction(String name, CustomModel model, int column) {
super(name);
this.model = model;
this.column = column;
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < model.getRowCount(); i++) {
model.setValueAt(model.getValueAt(i, column), i, column);
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Test()::display);
}
}

JTable copy value from view of cellrenderer

I have a JTable with a cellrenderer and my table is non-editable. When i select a cell and copy (ctrl-c) the value, its copying not the shown in the cell, it is copying the value which store in model. How could I copy cell value which shown in table.
public class TableDemo {
public static void main(String[] args) {
Vector<String> values = new Vector<String>();
values.add("Val1");
values.add("Val2");
JTable table = new JTable(new Object[][] { { "key", values },
{ "key2", values } }, new String[] { "Col1", "Col2" });
table.getColumnModel().getColumn(1).setCellRenderer(new MyTableCellRenderer());
table.setCellSelectionEnabled(true);
JFrame jf = new JFrame();
jf.getContentPane().add(table);
jf.setSize(500, 500);
jf.setVisible(true);
}
}
class MyTableCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
row, column);
#SuppressWarnings("unchecked")
Vector<String> values = (Vector<String>) value;
setText(values.get(row));
return this;
}
}
You need to implement your own copy command. Here is the solution.
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
public class TableDemo {
public static void main(String[] args) {
final Vector<String> values = new Vector<String>();
values.add("Val1");
values.add("Val2");
final JTable table = new JTable(new Object[][] { { "key", values },
{ "key2", values } }, new String[] { "Col1", "Col2" });
table.getColumnModel().getColumn(1).setCellRenderer(new MyTableCellRenderer());
table.registerKeyboardAction(new CopyAction(), KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_FOCUSED);
table.setCellSelectionEnabled(true);
final JFrame jf = new JFrame();
jf.getContentPane().add(table);
jf.setSize(500, 500);
jf.setVisible(true);
}
private static class CopyAction extends AbstractAction {
/**
* {#inheritDoc}
*/
#Override
public void actionPerformed(ActionEvent e) {
final JTable tbl = (JTable) e.getSource();
final int row = tbl.getSelectedRow();
final int col = tbl.getSelectedColumn();
if (row >= 0 && col >= 0) {
final TableCellRenderer renderer = tbl.getCellRenderer(row, col);
final Component comp = tbl.prepareRenderer(renderer, row, col);
if (comp instanceof JLabel) {
final String toCopy = ((JLabel) comp).getText();
final StringSelection selection = new StringSelection(toCopy);
final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(selection, selection);
}
}
}
}
}
#SuppressWarnings("serial")
class MyTableCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
row, column);
#SuppressWarnings("unchecked")
final
Vector<String> values = (Vector<String>) value;
setText(values.get(row));
return this;
}
}

Dynamic jcombobox items inside jtable

I am trying to create a Jtable with two combobox in each row. I have checked for tutorials on that and found that I can add static data inside combobox. But how come I can have dynamic data loaded into a combobox.
Even, whenever the user selects the combobox 1 from the row, then based on that, the combobox 2 will be updated.
Can anybody help me on this?
If I do removeAllItems() from the combobox, then the combobox 2 will updated, but I am unable to add new entries.
Thanks in advance.
Table has two columns both are rendered as JComboBox. Now, selection of Column-2 items are dependent on the Column-1 selection.
import java.awt.Component;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class ComboBoxExample {
private void createUI() {
JFrame frame = new JFrame();
Object[] columNames = {"Combo-1", "Combo-2"};
Object[][] data = {{"", ""}, {"", ""}, {"", ""}, {"", ""}};
JTable table = new JTable(data, columNames);
table.getColumnModel().getColumn(0).setCellEditor(new CustomComboBoxEditor());
table.getColumnModel().getColumn(1).setCellEditor(new CustomComboBoxEditor());
frame.add(new JScrollPane(table));
frame.setTitle("Column -2 based on Column - 1 ComboBox Selection.");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new ComboBoxExample().createUI();
}
};
EventQueue.invokeLater(r);
}
}
class CustomComboBoxEditor extends DefaultCellEditor {
// Declare a model that is used for adding the elements to the `ComboBox`
private DefaultComboBoxModel model;
private List<String> obtainedList;
public CustomComboBoxEditor() {
super(new JComboBox());
this.model = (DefaultComboBoxModel)((JComboBox)getComponent()).getModel();
obtainedList = new ArrayList<String>();
obtainedList.add("One");
obtainedList.add("Two");
obtainedList.add("Three");
obtainedList.add("Four");
obtainedList.add("Five");
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if(column == 0) {
model.removeAllElements();
for(int i = 0; i < obtainedList.size(); i++) {
model.addElement(obtainedList.get(i));
}
} else {
model.removeAllElements();
String selectedItem = (String) table.getValueAt(row, 0);
for(int i = 0; i < obtainedList.size(); i++) {
if(!selectedItem.equals(obtainedList.get(i)))
model.addElement(obtainedList.get(i));
}
} // Close else
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
Try something like this, you can change DATA in this example, and repaint and do the Renderer of the cell:
public void example(){
TableColumn tmpColum =table.getColumnModel().getColumn(1);
String[] DATA = { "Data 1", "Data 2", "Data 3", "Data 4" };
JComboBox comboBox = new JComboBox(DATA);
DefaultCellEditor defaultCellEditor=new DefaultCellEditor(comboBox);
tmpColum.setCellEditor(defaultCellEditor);
tmpColum.setCellRenderer(new CheckBoxCellRenderer(comboBox));
table.repaint();
}
/**
Custom class for adding elements in the JComboBox.
*/
class CheckBoxCellRenderer implements TableCellRenderer {
JComboBox combo;
public CheckBoxCellRenderer(JComboBox comboBox) {
this.combo = new JComboBox();
for (int i=0; i<comboBox.getItemCount(); i++){
combo.addItem(comboBox.getItemAt(i));
}
}
public Component getTableCellRendererComponent(JTable jtable, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
combo.setSelectedItem(value);
return combo;
}
}
After removeAllItems() call, add items in combobox as
combobox.addItem("one");
combobox.addItem("two");

If a cell value is same, changing a cell background in JTable

I have a question for JTable.
When I select a cell and then there are same value cell in JTable which I chose, that cells highlight background red color.
I don't know what to do....
P.S: I am sorry, I do not know how to enter the code in here...;;
You can implement ListSelectionListener to track selection changes in a table. Then implement TableCellRenderer that would change background of a cell with the same value of a selected object. Check out How to Use Tables for more details on JTable, renderers and selection.
Here is a very simple example that demonstrates this idea:
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.Color;
import java.awt.Component;
public class TableDemo {
private static void createAndShowGUI() {
JFrame frame = new JFrame("TableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPanel = new JPanel();
String[] columnNames = { "Column1", "Column2" };
Object[][] data = { { "1", "3" }, { "2", "5" }, { "7", "1" },
{ "5", "3" } };
JTable table = new JTable();
MyModel model = new MyModel(Color.RED, table.getBackground());
model.setDataVector(data, columnNames);
table.setModel(model);
table.setColumnSelectionAllowed(true);
table.setDefaultRenderer(Object.class, new TestCellRenderer());
SelectionListener listener = new SelectionListener(table);
table.getSelectionModel().addListSelectionListener(listener);
table.getColumnModel().getSelectionModel()
.addListSelectionListener(listener);
JScrollPane scrollPane = new JScrollPane(table);
contentPanel.add(scrollPane);
contentPanel.setOpaque(true);
frame.add(contentPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
static class TestCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
Component c = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
MyModel model = (MyModel) table.getModel();
c.setBackground(model.getCellColor(row, column));
return c;
}
}
static class MyModel extends DefaultTableModel {
private Object selectedObject;
private Color selectedColor;
private Color normalColor;
public MyModel(Color selectedColor, Color normalColor) {
this.selectedColor = selectedColor;
this.normalColor = normalColor;
}
public Color getCellColor(int row, int column) {
if (getValueAt(row, column).equals(selectedObject))
return selectedColor;
return normalColor;
}
public void setSelectedObject(Object selectedObject) {
this.selectedObject = selectedObject;
fireTableRowsUpdated(0, getRowCount());
}
}
static class SelectionListener implements ListSelectionListener {
private JTable table;
SelectionListener(JTable table) {
this.table = table;
}
public void valueChanged(ListSelectionEvent e) {
int rowIndex = table.getSelectedRow();
int colIndex = table.getSelectedColumn();
if (!e.getValueIsAdjusting() && colIndex != -1 && rowIndex != -1) {
((MyModel) table.getModel()).setSelectedObject(table
.getValueAt(rowIndex, colIndex));
}
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Here is a result:
EDIT: solution using renderer only, without table model
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.Color;
import java.awt.Component;
public class TableDemo {
private static void createAndShowGUI() {
JFrame frame = new JFrame("TableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPanel = new JPanel();
String[] columnNames = { "Column1", "Column2" };
Object[][] data = { { "1", "3" }, { "2", "5" }, { "7", "1" },
{ "5", "3" } };
JTable table = new JTable(new DefaultTableModel(data, columnNames));
table.setColumnSelectionAllowed(true);
TestCellRenderer renderer = new TestCellRenderer();
table.setDefaultRenderer(Object.class, renderer);
SelectionListener listener = new SelectionListener(table);
table.getSelectionModel().addListSelectionListener(listener);
table.getColumnModel().getSelectionModel()
.addListSelectionListener(listener);
JScrollPane scrollPane = new JScrollPane(table);
contentPanel.add(scrollPane);
contentPanel.setOpaque(true);
frame.add(contentPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
static class TestCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
Component c = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
int columnIndex = table.getSelectedColumn();
int rowIndex = table.getSelectedRow();
if (columnIndex != -1 && rowIndex != -1){
Object selectedValue = table.getValueAt(rowIndex, columnIndex);
if (value.equals(selectedValue)) {
c.setBackground(Color.RED);
} else {
c.setBackground(table.getBackground());
}
}
return c;
}
}
static class SelectionListener implements ListSelectionListener {
private JTable table;
SelectionListener(JTable table) {
this.table = table;
}
public void valueChanged(ListSelectionEvent e) {
int rowIndex = table.getSelectedRow();
int colIndex = table.getSelectedColumn();
if (!e.getValueIsAdjusting() && colIndex != -1 && rowIndex != -1){
table.repaint();
}
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Categories