I would like to have a JTable with JComboBoxes that is always visible. My problem is when I click on a JComboBox and select a value, my JComboBox is not updated.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class trial extends JFrame {
private ArrayList<JComboBox> comboslist= new ArrayList <JComboBox>();/*list of my
comboboxes*/
public static void main(String[] args) {
trial tr= new trial();
}
public trial(){
this.setSize(new Dimension(600,100));
String[] ColData={"Index","Field Name","Value","Range"};
Object[][] TrowData={ };
DefaultTableModel model = new DefaultTableModel(TrowData, ColData);
final List<TableCellEditor> editors = new ArrayList<TableCellEditor>();
JComboBox combo1= new JComboBox();
combo1.addItem("don");
combo1.addItem("mump");
combo1.setEditable(true);
combo1.setBackground(Color.WHITE);
Object[] rowdata = {"cars","books","chicken","soup"};
model.addRow(rowdata);
DefaultCellEditor dce1 = new DefaultCellEditor(combo1);
editors.add(dce1);
JComboBox combo2= new JComboBox();
combo2.addItem("sop");
combo2.addItem("act");
combo2.setEditable(true);
combo2.setBackground(Color.WHITE);
Object[] rowdata2 = {"goats","cats","salads","dogs"};
model.addRow(rowdata2);
DefaultCellEditor dce2= new DefaultCellEditor(combo2);
editors.add(dce2);
comboslist.add(combo1);
comboslist.add(combo2);
JTable table = new JTable(model)
{
// Determine editor to be used by row
public TableCellEditor getCellEditor(int row, int column)
{
int modelColumn = convertColumnIndexToModel( column );
if (modelColumn == 2)
return editors.get(row);
else
return super.getCellEditor(row, column);
}
};
table.setRowHeight(0, 30);
table.setRowHeight(1, 30);
table.setPreferredScrollableViewportSize(new Dimension(800, 150));
table.setFillsViewportHeight(true);
TableColumn valCol= table.getColumnModel().getColumn(2);
int x=0;
for(JComboBox cb: comboslist ){
valCol.setCellRenderer(new ComboBoxCellRenderer(cb,x++));
}
this.add(table);
this.setVisible(true);
}
private class ComboBoxCellRenderer extends JComboBox implements TableCellRenderer {
private JComboBox combo;
private int idx=0;
private ComboBoxCellRenderer comboRenderer;
public ComboBoxCellRenderer(JComboBox com,int ind)
{
for (int i = 0; i < com.getItemCount(); i++)
{
addItem(com.getItemAt(i));
}
comboRenderer=this;
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if(comboslist.get(row).getSelectedItem()!=null)
{
if(isSelected && row==idx)
{
setSelectedItem(comboslist.get(row).getSelectedItem().toString());
comboRenderer.setSelectedItem(comboslist.get(row).getSelectedItem().toString());
}
}else
{
setSelectedItem(value);
}
return this;
}
}
}
You've kinda got in backwards and twisted around. Instead of trying to have a number of combobox editors, you should have one, which is then configured based on the row.
Based on this idea, you could have a single class act as both the renderer and the editor, for example
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractCellEditor;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
public class Trial extends JFrame {
public static void main(String[] args) {
Trial tr = new Trial();
}
public Trial() {
this.setSize(new Dimension(600, 100));
String[] ColData = {"Index", "Field Name", "Value", "Range"};
Object[][] TrowData = {};
DefaultTableModel model = new DefaultTableModel(TrowData, ColData);
final List<TableCellEditor> editors = new ArrayList<TableCellEditor>();
model.addRow(new String[] {"cars", "books", "chicken", "soup"});
model.addRow(new String[] {"goats", "cats", "salads", "dogs"});
DefaultComboBoxModel model1 = new DefaultComboBoxModel();
model1.addElement("don");
model1.addElement("mump");
DefaultComboBoxModel model2 = new DefaultComboBoxModel();
model2.addElement("sop");
model2.addElement("act");
Map<Integer, ComboBoxModel<String>> models = new HashMap<>(2);
models.put(0, model1);
models.put(1, model2);
JTable table = new JTable(model);
table.setRowHeight(0, 30);
table.setRowHeight(1, 30);
table.setPreferredScrollableViewportSize(new Dimension(800, 150));
table.setFillsViewportHeight(true);
ComboBoxCellRendererEditor rendererEditor = new ComboBoxCellRendererEditor(models);
table.getColumnModel().getColumn(1).setCellRenderer(rendererEditor);
table.getColumnModel().getColumn(1).setCellEditor(rendererEditor);
this.add(table);
this.setVisible(true);
}
private static class ComboBoxCellRendererEditor extends AbstractCellEditor implements TableCellRenderer, TableCellEditor {
private JComboBox<String> comboBox;
private Map<Integer, ComboBoxModel<String>> models;
public ComboBoxCellRendererEditor(Map<Integer, ComboBoxModel<String>> models) {
comboBox = new JComboBox<>();
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
this.models = models;
}
protected void configure(Object value, int row) {
ComboBoxModel<String> model = models.get(row);
if (model == null) {
model = new DefaultComboBoxModel<>();
}
comboBox.setModel(model);
comboBox.setSelectedItem(value);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
configure(value, row);
return comboBox;
}
#Override
public Object getCellEditorValue() {
return comboBox.getSelectedItem();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
configure(value, row);
return comboBox;
}
}
}
adding this piece of code solved everything.
column.setCellRenderer(new TableCellRenderer() {
JComboBox box = new JComboBox();
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
box.removeAllItems();
box.addItem(value.toString());
return box;
}
});
Related
I've a problem with JComboBox custom ListCellRenderer. I want to create a combobox that let choose between 4 colors. I want the combobox shows the color by a "list" of JPanel with desired color a background. I manage to obtain quite what I want, the only problem is that when I click on item, this change color to grey not displaying anymore the original color.
Here the code:
package custom_renderer_combobox;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.JComboBox;
public class gui extends JFrame{
/**
*
*/
private static final long serialVersionUID = 1L;
private Color[] colors={Color.BLACK,Color.blue,Color.cyan,Color.GRAY,Color.green,Color.MAGENTA,Color.ORANGE,Color.RED};
gui(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setSize(new Dimension(400,400));
getContentPane().setLayout(null);
JComboBox<JPanel> comboBox = new JComboBox<JPanel>();
comboBox.setRenderer(new myRenderer());
comboBox.setBounds(36, 59, 211, 20);
getContentPane().add(comboBox);
for(int i=0;i<colors.length;i++){
JPanel temp=new JPanel();
temp.setOpaque(true);
temp.setBackground(colors[i]);
comboBox.addItem(temp);
}
comboBox.repaint();
}
class myRenderer implements ListCellRenderer{
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
return ((JPanel) value);
}
}
}
Here some pic:
image
I think that the problem is in the custom renderer, can someone tell me what would I had to do?
Here is an example for you, how to use renderers and combo boxes
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
/**
* <code>ColorTest</code>.
*/
public class ColorTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ColorTest();
}
});
}
/**
*
*/
public ColorTest() {
JFrame frm = new JFrame("Test");
final JComboBox<ColorData> cmb = new JComboBox<>(ColorData.values());
cmb.setRenderer(new ColorRenderer());
final JPanel p = new JPanel();
p.setOpaque(true);
p.setPreferredSize(new Dimension(200, 100));
ActionListener l = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ColorData cd = (ColorData) cmb.getSelectedItem();
if (cd != null) {
p.setBackground(cd.getColor());
}
}
};
cmb.addActionListener(l);
l.actionPerformed(null); // update current background
frm.add(cmb, BorderLayout.NORTH);
frm.add(p);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
private static class ColorRenderer 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 instanceof ColorData) {
BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.createGraphics();
g.setColor(((ColorData) value).getColor());
g.fillRect(0, 0, 15, 15);
g.dispose();
setIcon(new ImageIcon(img));
}
return this;
}
}
private static enum ColorData {
BLACK("Black", Color.BLACK),
BLUE("Blue", Color.BLUE),
GREEN("Green", Color.GREEN),
RED("Red", Color.RED);
private String name;
private Color color;
private ColorData(String aName, Color aColor) {
name = aName;
color = aColor;
}
public String getName() {
return name;
}
public Color getColor() {
return color;
}
#Override
public String toString() {
return getName();
}
}
}
To add some new colors, you need to add the appropriate constants to the ColorData enum.
to make it a little bit quicker you can create your own JPanel that will take background color in constructor, and will block changing background:
public class ColorPanel extends JPanel {
public ColorPanel(Color color) {
super.setBackground(color);
}
#Override
public void setBackground(Color bg) {
//blocked changing
}
}
and in your code you have to change
JPanel temp = new ColorPanel(colors[i]);
temp.setOpaque(true);
comboBox.addItem(temp);
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
class ComboTableCellRenderer implements ListCellRenderer, TableCellRenderer {
DefaultListCellRenderer listRenderer = new DefaultListCellRenderer();
DefaultTableCellRenderer tableRenderer = new DefaultTableCellRenderer();
private void configureRenderer(JLabel renderer, Object value) {
if ((value != null) && (value instanceof Color)) {
if (value.equals(Color.red)) {
renderer.setText("0");
} else if(value.equals(Color.orange)) {
renderer.setText("10");
}
else if(value.equals(Color.yellow)) {
renderer.setText("20");
}
else if(value.equals(Color.green)) {
renderer.setText("30");
}
else if(value.equals(Color.white)) {
renderer.setText("N/A");
}
renderer.setBackground((Color)value);
} else {
renderer.setText((String) value);
}
}
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
listRenderer = (DefaultListCellRenderer) listRenderer.getListCellRendererComponent(list, value,
index, isSelected, cellHasFocus);
configureRenderer(listRenderer, value);
return listRenderer;
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
tableRenderer = (DefaultTableCellRenderer) tableRenderer.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
configureRenderer(tableRenderer, value);
return tableRenderer;
}
}
class ColorTableModel extends AbstractTableModel {
Object rowData[][] = {
{ "1","","","", Color.red, "30" },
{ "2","","","", Color.red, "30" },
{ "3","","","", Color.red, "30" },
{ "4","","","", Color.red, "30" },
{ "5","","","", Color.red, "30" }, };
String columnNames[] = { "Index","Item","Reason","Image","Marks","Allocated Marks" };
public int getColumnCount() {
return columnNames.length;
}
public String getColumnName(int column) {
return columnNames[column];
}
public int getRowCount() {
return rowData.length;
}
public Object getValueAt(int row, int column) {
return rowData[row][column];
}
public Class getColumnClass(int column) {
return (getValueAt(0, column).getClass());
}
public void setValueAt(Object value, int row, int column) {
rowData[row][column] = value;
}
public boolean isCellEditable(int row, int column) {
return (column != 0);
}
}``
Main.java
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
public class Main {
public static void main(String[] args) {
// TODO code application logic here
Color choices[] = { Color.red, Color.yellow, Color.green, Color.white, Color.orange };
ComboTableCellRenderer renderer = new ComboTableCellRenderer();
JComboBox comboBox = new JComboBox(choices);
comboBox.setRenderer(renderer);
TableCellEditor editor = new DefaultCellEditor(comboBox);
JFrame frame = new JFrame("Editable Color Table");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableModel model = new ColorTableModel();
JTable table = new JTable(model);
TableColumn column = table.getColumnModel().getColumn(4);
column.setCellRenderer(renderer);
column.setCellEditor(editor);
JScrollPane scrollPane = new JScrollPane(table);
frame.add(scrollPane, BorderLayout.CENTER);
frame.setSize(400, 150);
frame.setVisible(true);
}
}
This code for jtable jcombobox color change according to value change.
This is working 100%
Hope it will work for you!
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;
}
}
I want to change the action of the button to delete. I have this code:
package buttonexample;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
public class ButtonExample {
public JTable table;
public static void main(String[] args) {
final ButtonExample example = new ButtonExample();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
example.createAndShowGUI();
}
});
}
private void createAndShowGUI() {
JFrame frame = new JFrame("Button Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table = new JTable(new JTableModel());
JScrollPane scrollPane = new JScrollPane(table);
table.setFillsViewportHeight(true);
TableCellRenderer buttonRenderer = new JTableButtonRenderer();
//table.getColumn("Button1").setCellRenderer(buttonRenderer);
table.getColumn("Button2").setCellRenderer(buttonRenderer);
table.addMouseListener(new JTableButtonMouseListener(table));
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.getContentPane().setPreferredSize(new Dimension(500, 200));
frame.pack();
frame.setVisible(true);
}
public static class JTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private static final String[] COLUMN_NAMES = new String[] {"Id", "Stuff", "Asdfsdf", "Button2"};
private static final Class<?>[] COLUMN_TYPES = new Class<?>[] {Integer.class, String.class, String.class, JButton.class};
#Override public int getColumnCount() {
return COLUMN_NAMES.length;
}
#Override public int getRowCount() {
return 4;
}
#Override public String getColumnName(int columnIndex) {
return COLUMN_NAMES[columnIndex];
}
#Override public Class<?> getColumnClass(int columnIndex) {
return COLUMN_TYPES[columnIndex];
}
#Override public Object getValueAt(final int rowIndex, final int columnIndex) {
switch (columnIndex) {
case 0: return rowIndex;
case 1: return "Text for "+rowIndex;
case 2: return "Column for "+rowIndex;
case 3: final JButton button = new JButton(COLUMN_NAMES[columnIndex]);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// When this is clicked the whole row will be deleted.
JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(button),
"Button clicked for row "+rowIndex);
}
});
return button;
default: return "Error";
}
}
}
private static class JTableButtonRenderer implements TableCellRenderer {
#Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JButton button = (JButton)value;
if (isSelected) {
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setForeground(table.getForeground());
button.setBackground(UIManager.getColor("Button.background"));
}
return button;
}
}
private static class JTableButtonMouseListener extends MouseAdapter {
private final JTable table;
public JTableButtonMouseListener(JTable table) {
this.table = table;
}
public void mouseClicked(MouseEvent e) {
int column = table.getColumnModel().getColumnIndexAtX(e.getX());
int row = e.getY()/table.getRowHeight();
if (row < table.getRowCount() && row >= 0 && column < table.getColumnCount() &&
column >= 0) {
Object value = table.getValueAt(row, column);
if (value instanceof JButton) {
((JButton)value).doClick();
}
}
}
}
}
But the (DefaultTableModel)someTable.getModel(); model.removeRow(row); I can't make it work because the table model does not have any name and I don't know what to name it. I have tried initializing a table model and I get error saying non-static variable model cannot be reference to a static context. Is there a way to delete the row in a static context?
The example by camickr is probably a more reusable solution, but for the sake of education...
Rendering of cells is the domain of the view
Model's should never contain components, especially if you're thinking about rendering them to the screen, this is simply the wrong approach to take...
You need to set up a TableCellEditor which will act as the means by which you can retrieve notification of the edit actions (mouse click or keypress)
This is a basic example, for simplicity, I've used a DefaultTableModel as it has a nice removeRow method, but conceivably, you could use any TableModel, so long as you provided the means to remove a row and modified by the editor to support it...
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.event.CellEditorListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
public class ButtonExample {
public JTable table;
public static void main(String[] args) {
final ButtonExample example = new ButtonExample();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
example.createAndShowGUI();
}
});
}
private void createAndShowGUI() {
JFrame frame = new JFrame("Button Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table = new JTable(new ExampleTableModel());
JScrollPane scrollPane = new JScrollPane(table);
table.setFillsViewportHeight(true);
table.getColumn("action").setCellRenderer(new ButtonCellRenderer());
table.getColumn("action").setCellEditor(new ButtonCellEditor());
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public static class ExampleTableModel extends DefaultTableModel {
public ExampleTableModel() {
super(new Object[]{"id", "stuff", "blah", "action"}, 0);
for (int index = 0; index < 10; index++) {
addRow(new Object[]{index, "Text for " + index, "Na na", index});
}
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 3;
}
}
public static class ButtonCellRenderer extends JButton implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value != null) {
setText("Delete row " + value.toString());
} else {
setText("Delete Me");
}
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(UIManager.getColor("Button.background"));
}
return this;
}
}
public static class ButtonCellEditor extends AbstractCellEditor implements TableCellEditor {
private JButton editor;
private Object value;
private int row;
private JTable table;
public ButtonCellEditor() {
editor = new JButton();
editor.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (table != null) {
fireEditingStopped();
TableModel model = table.getModel();
if (model instanceof DefaultTableModel) {
((DefaultTableModel) model).removeRow(row);
}
}
}
});
}
#Override
public boolean isCellEditable(EventObject e) {
return true;
}
#Override
public Object getCellEditorValue() {
return value;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
this.table = table;
this.row = row;
this.value = value;
if (value != null) {
editor.setText("Delete row " + value.toString());
} else {
editor.setText("Delete Me");
}
if (isSelected) {
editor.setForeground(table.getSelectionForeground());
editor.setBackground(table.getSelectionBackground());
} else {
editor.setForeground(table.getForeground());
editor.setBackground(UIManager.getColor("Button.background"));
}
return editor;
}
}
}
Take a closer look at How to Use Tables for more details
This is just a personal preference, but I prefer to use a toolbar or menu item and key bindings to provide this support. Buttons in a table just seem so...dated - IMHO
I created JTable that contains information about employees. In this JTable I added the column called "Qualifications". This column is represented by JComboBox (different content at each row). For instance:
Row 1 | JComboBox(){"Programmer","Web"}
Row 2 | JComboBox(){"Writer","Editor"}
The JComboBox content is taken from the List<String> employees[row].getQualification().
The problem is that the selected item in Row 1 and Row 2 is "Programmer", however "Programmer" should not appear in Row 2. Only when I click on JComboBox, the correct list appears, i.e. Row 2 - {"Writer","Editor"}.
TableColumn column = table.getColumnModel().getColumn(5);
column.setCellRenderer(getRenderer());
private TableCellRenderer getRenderer() {
return new TableCellRenderer() {
private JComboBox<String> box = new JComboBox<String>();
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
for (String q : employees[row].getQualification())
box.addItem(q);
box.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
box.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
return box;
}
};
}
Override the getCellEditor() method of the JTable. Something like:
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableComboBoxByRow extends JPanel
{
List<TableCellEditor> editors = new ArrayList<TableCellEditor>(3);
public TableComboBoxByRow()
{
setLayout( new BorderLayout() );
// Create the editors to be used for each row
String[] items1 = { "Red", "Blue", "Green" };
JComboBox<String> comboBox1 = new JComboBox<String>( items1 );
DefaultCellEditor dce1 = new DefaultCellEditor( comboBox1 );
editors.add( dce1 );
String[] items2 = { "Circle", "Square", "Triangle" };
JComboBox<String> comboBox2 = new JComboBox<String>( items2 );
DefaultCellEditor dce2 = new DefaultCellEditor( comboBox2 );
editors.add( dce2 );
String[] items3 = { "Apple", "Orange", "Banana" };
JComboBox<String> comboBox3 = new JComboBox<String>( items3 );
DefaultCellEditor dce3 = new DefaultCellEditor( comboBox3 );
editors.add( dce3 );
// Create the table with default data
Object[][] data =
{
{"Color", "Red"},
{"Shape", "Square"},
{"Fruit", "Banana"},
{"Plain", "Text"}
};
String[] columnNames = {"Type","Value"};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
JTable table = new JTable(model)
{
// Determine editor to be used by row
public TableCellEditor getCellEditor(int row, int column)
{
int modelColumn = convertColumnIndexToModel( column );
if (modelColumn == 1 && row < 3)
return editors.get(row);
else
return super.getCellEditor(row, column);
}
};
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("Table Combo Box by Row");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TableComboBoxByRow() );
frame.setSize(200, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
JComboBox-es appear only on a click
because you use them as CellEditor, which apper only when you edit cells. If you want to display your column cells as JComboBox everytime, you need to use TableCellRenderer, read about that. Here is simple example of JComboBox as renderer :
import java.awt.Component;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class TestFrame extends JFrame{
public TestFrame(){
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
private void init() {
JTable t = new JTable(3,3);
TableColumn column = t.getColumnModel().getColumn(2);
column.setCellRenderer(getRenderer());
add(new JScrollPane(t));
}
private TableCellRenderer getRenderer() {
return new TableCellRenderer() {
private JComboBox<String> box = new JComboBox<String>(new String[]{"1","2"});
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
box.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
box.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
return box;
}
};
}
public static void main(String... s){
new TestFrame();
}
}
Thanks to #alex2410, I cleaned up the code and wrapped it into a ComboTable class which should do the job for you. instantiate ComboTable class with a hashmap of each row values (the demo assumes 2 columns, but you can add more). Note MyMap.of is just a wrapper for java 9 Map.of since I was using Java 8 at that time. same for MyList.of
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.EventObject;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import rs.code.utils.MyList;
import rs.code.utils.MyMap;
public class Test extends JFrame
{
private static final long serialVersionUID = 1L;
public ComboTable table = new ComboTable(MyMap.of("Gender", MyList.of("male", "female"), "City", MyList.of("london", "bedord"), "orientation", MyList.of("left", "right")));
public Test()
{
super("EachRow Editor Example");
JScrollPane scroll = new JScrollPane(table);
getContentPane().add(scroll, BorderLayout.CENTER);
setPreferredSize(new Dimension(400, 120));
setLocation(150, 100);
pack();
setVisible(true);
}
public static void main(String[] args)
{
Test frame = new Test();
frame.addWindowListener(new WindowAdapter()
{
#Override
public void windowClosing(WindowEvent e)
{
System.out.println(frame.table.getSelectedValues().toString());
System.exit(0);
}
});
}
}
class ComboTable extends JTable
{
private static final long serialVersionUID = 1L;
protected Map<Integer, ComboCellEditor> editors = new LinkedHashMap<>();
public ComboTable(Map<String, List<String>> rows)
{
setModel(new DefaultTableModel(new String[] {"Attribute", "Value"}, rows.size()));
setRowHeight(20);
EachRowEditor rowEditor = new EachRowEditor(this);
int i = 0;
for(String key : rows.keySet())
{
getModel().setValueAt(key, i, 0);
editors.put(i++, new ComboCellEditor(createComboBox(rows.get(key))));
}
getColumn("Value").setCellEditor(rowEditor);
getColumn("Value").setCellRenderer(getRenderer());
}
public Map<Integer, ComboCellEditor> getEditors()
{
return editors;
}
public Map<String, String> getSelectedValues()
{
Map<String, String> values = new LinkedHashMap<>();
for(int i=0;i<getModel().getRowCount();i++)
{
values.put(getModel().getValueAt(i, 0).toString(), editors.get(i).getComboBox().getSelectedItem().toString());
}
return values;
}
private JComboBox<String> createComboBox(List<String> elements)
{
JComboBox<String> comboBox = new JComboBox<>();
for (String element : elements)
{
comboBox.addItem(element);
}
comboBox.setSelectedIndex(0);
comboBox.addComponentListener(new ComponentAdapter()
{
#Override
public void componentShown(ComponentEvent e)
{
final JComponent c = (JComponent) e.getSource();
SwingUtilities.invokeLater(new Runnable()
{
#SuppressWarnings("rawtypes")
#Override
public void run()
{
c.requestFocus();
System.out.println(c);
if (c instanceof JComboBox)
{
System.out.println(((JComboBox) c).getSelectedItem());
}
}
});
}
});
return comboBox;
}
private TableCellRenderer getRenderer()
{
return new TableCellRenderer()
{
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
editors.get(row).getComboBox().setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
editors.get(row).getComboBox().setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
return editors.get(row).getComboBox();
}
};
}
}
class ComboCellEditor extends DefaultCellEditor
{
private static final long serialVersionUID = 1L;
private final JComboBox<String> comboBox;
public ComboCellEditor(JComboBox<String> comboBox)
{
super(comboBox);
this.comboBox = comboBox;
}
public JComboBox<String> getComboBox()
{
return comboBox;
}
}
class EachRowEditor implements TableCellEditor
{
private TableCellEditor editor;
private final TableCellEditor defaultEditor;
private final ComboTable table;
public EachRowEditor(ComboTable table)
{
this.table = table;
defaultEditor = new DefaultCellEditor(new JTextField());
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
{
return editor.getTableCellEditorComponent(table, value, isSelected, row, column);
}
public Object getCellEditorValue()
{
return editor.getCellEditorValue();
}
public boolean stopCellEditing()
{
return editor.stopCellEditing();
}
public void cancelCellEditing()
{
editor.cancelCellEditing();
}
public boolean isCellEditable(EventObject anEvent)
{
selectEditor((MouseEvent) anEvent);
return editor.isCellEditable(anEvent);
}
public void addCellEditorListener(CellEditorListener l)
{
editor.addCellEditorListener(l);
}
public void removeCellEditorListener(CellEditorListener l)
{
editor.removeCellEditorListener(l);
}
public boolean shouldSelectCell(EventObject anEvent)
{
selectEditor((MouseEvent) anEvent);
return editor.shouldSelectCell(anEvent);
}
protected void selectEditor(MouseEvent e)
{
int row;
if (e == null)
{
row = table.getSelectionModel().getAnchorSelectionIndex();
}
else
{
row = table.rowAtPoint(e.getPoint());
}
editor = table.getEditors().get(row);
if (editor == null)
{
editor = defaultEditor;
}
}
}
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();
}
});
}
}