Disable JComboBox inside JTable on click of JCheckBox - java

I have JTable and it has a JCheckBox and a JComoboBox in two different columns. When I select a JCheckBox that corresponds to that row, the JComboBox should be disable. Kindly help me.

Simply disable editing of the cell based on your model. In your TableModel, override/implement the isCellEditable() method to return the "value" of the checkbox.
Although the following example is not based on JComboBox, it illustrates how to disable edition of a cell based on the value of a checkbox at the beginning of the row:
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class TestTable {
public JFrame f;
private JTable table;
public class TestTableModel extends DefaultTableModel {
public TestTableModel() {
super(new String[] { "Editable", "DATA" }, 3);
for (int i = 0; i < 3; i++) {
setValueAt(Boolean.TRUE, i, 0);
setValueAt(Double.valueOf(i), i, 1);
}
}
#Override
public boolean isCellEditable(int row, int column) {
if (column == 1) {
return (Boolean) getValueAt(row, 0);
}
return super.isCellEditable(row, column);
}
#Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 0) {
return Boolean.class;
} else if (columnIndex == 1) {
return Double.class;
}
return super.getColumnClass(columnIndex);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestTable().initUI();
}
});
}
protected void initUI() {
table = new JTable(new TestTableModel());
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 300);
f.setLocationRelativeTo(null);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}

Related

remove a row from jtable with jbutton

I have a JTable with JButton like this.
first pic
if I click the "+" button,the table is like this.
second pic
then, if I click the "-" button on the second line, it's ok.
now the table has only one row which was added by the "+" button.
so the question is that, I clicked the "-" button on the row,it throws an exception below:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1 >= 1
at java.util.Vector.elementAt(Vector.java:477)
at javax.swing.table.DefaultTableModel.setValueAt(DefaultTableModel.java:664)
what happened?
this is my code:
public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor{
/**
*
*/
private static final long serialVersionUID = 1L;
JButton button;
String label;
boolean isPushed;
Vector<Vector<String>> vPartsTypeData;
DefaultTableModel dtm;
JTable partsTypeValueTable;
public TableDeleteButtonEditor(Vector<Vector<String>> vPartsTypeData, DefaultTableModel dtm, JTable partsTypeValueTable) {
// TODO Auto-generated constructor stub
//this.setClickCountToStart(1);
this.vPartsTypeData = vPartsTypeData;
this.dtm = dtm;
this.partsTypeValueTable = partsTypeValueTable;
this.vPartsTypeData = vPartsTypeData;
button = new JButton();
int selectedRow = partsTypeValueTable.getSelectedRow();
System.out.println("selectedRow:"+selectedRow);
System.out.println("Count:"+vPartsTypeData.size());
button.addActionListener(new deleteButtonListener());
}
public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected,int row, int column) {
if (isSelected) {
button.setFont(new Font("Arial",Font.PLAIN,30));
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setFont(new Font("Arial",Font.PLAIN,30));
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
label = (value == null) ? "" : value.toString();
button.setText(label);
isPushed = true;
return button;
}
public Object getCellEditorValue() {
if (isPushed) {
}
isPushed = false;
return new String(label);
}
public boolean stopCellEditing() {
isPushed = false;
return super.stopCellEditing();
}
public class deleteButtonListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("-----");
int selectedRow = partsTypeValueTable.getSelectedRow();
//System.out.println("selectedRow:"+selectedRow);
//System.out.println("Count:"+vPartsTypeData.size());
dtm.removeRow(selectedRow-1);
//vPartsTypeData.remove(partsTypeValueTable.getSelectedRow());
System.out.println("tableCount:"+partsTypeValueTable.getRowCount());
//dtm.fireTableChanged(null);
partsTypeValueTable.setModel(dtm);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
partsTypeValueTable.repaint();
partsTypeValueTable.validate();
partsTypeValueTable.updateUI();
dtm.fireTableDataChanged();
}
});
}
}
}
So, a little bit of a look at the stack trace can lead us to a better understanding of what's going on...
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1 >= 1
at java.util.Vector.elementAt(Vector.java:477)
at javax.swing.table.DefaultTableModel.setValueAt(DefaultTableModel.java:664)
at javax.swing.JTable.setValueAt(JTable.java:2741)
at javax.swing.JTable.editingStopped(JTable.java:4723)
at javax.swing.AbstractCellEditor.fireEditingStopped(AbstractCellEditor.java:141)
at javax.swing.AbstractCellEditor.stopCellEditing(AbstractCellEditor.java:85)
So, basically stopCellEditing is triggering a call to setValueAt, passing in the editing row, column and the result of getCellEditorValue, but, since this occurs AFTER the ActionListener has removed the row from the TableModel, it breaks, as the row, which setValueAt is trying to update simply no longer exists (or worse is a different row altogether).
It's not the responsibility of the TableCellEditor to modify the TableModel, instead, it should be reporting back to the TableModel a state value which it can use to make decisions about what it should do.
A simplified version of the editor might look something like...
public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor {
/**
*
*/
private static final long serialVersionUID = 1L;
JButton button;
boolean isPushed;
public TableDeleteButtonEditor() {
button = new JButton();
button.addActionListener(new DeleteButtonListener());
}
public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, int row, int column) {
if (isSelected) {
button.setFont(new Font("Arial", Font.PLAIN, 30));
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setFont(new Font("Arial", Font.PLAIN, 30));
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
button.setText((value == null) ? "" : value.toString());
isPushed = false;
return button;
}
public Object getCellEditorValue() {
return isPushed;
}
public class DeleteButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
isPushed = true;
stopCellEditing();
}
}
}
The core functionality of the editor simply revolves around the state of the isPushed value.
The TableModel now needs to inspect this value when setValueAt is called and respond to it
#Override
public void setValueAt(Object aValue, int row, int column) {
if (column == 0 && (aValue instanceof Boolean)) {
boolean pushed = (boolean) aValue;
if (pushed) {
removeRow(row);
}
}
}
And viola, row is now deleted and everybody is happy.
Runnable example...
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
DefaultTableModel model = new DefaultTableModel(new String[]{"A"}, 0) {
#Override
public void setValueAt(Object aValue, int row, int column) {
if (column == 0 && (aValue instanceof Boolean)) {
boolean pushed = (boolean) aValue;
if (pushed) {
removeRow(row);
}
}
}
};
model.addRow(new Object[]{"-"});
model.addRow(new Object[]{"-"});
JTable table = new JTable(model);
TableColumn column = table.getColumnModel().getColumn(0);
column.setCellEditor(new TableDeleteButtonEditor());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor {
/**
*
*/
private static final long serialVersionUID = 1L;
JButton button;
boolean isPushed;
JTable partsTypeValueTable;
public TableDeleteButtonEditor() {
button = new JButton();
button.addActionListener(new DeleteButtonListener());
}
public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, int row, int column) {
partsTypeValueTable = table;
if (isSelected) {
button.setFont(new Font("Arial", Font.PLAIN, 30));
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setFont(new Font("Arial", Font.PLAIN, 30));
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
button.setText((value == null) ? "" : value.toString());
isPushed = false;
return button;
}
public Object getCellEditorValue() {
return isPushed;
}
public class DeleteButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
isPushed = true;
stopCellEditing();
}
}
}
}
As I said, I don't like this approach, it's a personally thing, but as a user, I find it frustrating and much prefer something more like this for example.
However, you might like to also have a look at Table Button Column for another approach

How to delete a row from jtable

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

How do I make it possible to select text in a JTable cell with editing disabled?

Imagine I'm building an IRC client with Java and I'd like rich text in the chat view to show IRC colors and colored nicks. I'd like to build this with a JTable. I can do that, but the text is then not selectable. Making the table editable doesn't make sense.
I've also investigated:
TextArea - no rich text formatting
JEditPane - can't append, only replace which is bad performance wise
JList - can't select text
So I got a table working I just need the text to be selectable without making it editable. I'd also would only like the text contents, and none of the HTML to be copied into the clipboard upon copying the text selection.
I have tried various iterations of setRowSelectionAllowed(), setColumnSelectionEnabled() and setCellSelectionEnabled() and setSelectionMode the table model returns false for isCellEditable(). Nothing has made the text selectable.
EDIT: as per answer 1 I was wrong about text editor panes so I'm trying those solutions.
I don't know why you don't want to use a JTextPane or JEditorPane. You insert text by its document. Examples here --> How to use Editor Panes and Text Panes.
But for your purpose you can for example do something like this. I override changeSelection to selectAll text when is clicking, the cells are editable but its cellEditors are not editable.
public class JTableTest {
private final DefaultCellEditor cellEditor;
private final JTextField textfield;
private JPanel panel;
private MyTableModel tableModel = new MyTableModel();
private JTable table = new JTable() {
#Override
public TableCellEditor getCellEditor(int row, int column) {
return JTableTest.this.cellEditor;
}
#Override
public void changeSelection(
final int row, final int column, final boolean toggle, final boolean extend) {
super.changeSelection(row, column, toggle, extend);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if ((getCellEditor(row, column) != null && !editCellAt(row, column))) {
JTextField textfield=(JTextField)JTableTest.this.cellEditor.getComponent();
textfield.selectAll();
}
}
});
}
};
public JTableTest() {
JScrollPane scroll = new JScrollPane(table);
table.setModel(tableModel);
panel = new JPanel(new BorderLayout());
panel.add(scroll, BorderLayout.CENTER);
textfield = new JTextField();
textfield.setEditable(Boolean.FALSE);
textfield.setBorder(null);
cellEditor = new DefaultCellEditor(textfield);
tableModel.insertValue(new ItemRow("nonEditable", "Editable"));
}
private class ItemRow {
private String column1;
private String column2;
public ItemRow(String column1, String column2) {
this.column1 = column1;
this.column2 = column2;
}
public String getColumn1() {
return column1;
}
public void setColumn1(String column1) {
this.column1 = column1;
}
public String getColumn2() {
return column2;
}
public void setColumn2(String column2) {
this.column2 = column2;
}
}
private class MyTableModel extends AbstractTableModel {
public static final int COLUMN1_INDEX = 0;
public static final int COLUMN2_INDEX = 1;
private final List<ItemRow> data = new ArrayList<>();
private final String[] columnsNames = {
"Column1",
"Column2",};
private final Class<?>[] columnsTypes = {
String.class,
String.class
};
public MyTableModel() {
super();
}
#Override
public Object getValueAt(int inRow, int inCol) {
ItemRow row = data.get(inRow);
Object outReturn = null;
switch (inCol) {
case COLUMN1_INDEX:
outReturn = row.getColumn1();
break;
case COLUMN2_INDEX:
outReturn = row.getColumn2();
break;
default:
throw new RuntimeException("invalid column");
}
return outReturn;
}
#Override
public void setValueAt(Object inValue, int inRow, int inCol) {
System.out.println("Gets called ");
if (inRow < 0 || inCol < 0 || inRow >= data.size()) {
return;
}
ItemRow row = data.get(inRow);
switch (inCol) {
case COLUMN1_INDEX:
row.setColumn1(inValue.toString());
break;
case COLUMN2_INDEX:
row.setColumn2(inValue.toString());
break;
}
fireTableCellUpdated(inRow, inCol);
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return columnsTypes.length;
}
#Override
public String getColumnName(int inCol) {
return this.columnsNames[inCol];
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return this.columnsTypes[columnIndex];
}
/**
*
* #param row
*/
public void insertValue(ItemRow row) {
data.add(row);
fireTableRowsInserted(data.size() - 1, data.size() - 1);
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
}
private static void createAndShowGUI(final Container container, final String title) {
//Create and set up the window.
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(Boolean.TRUE);
frame.add(container);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI(new JTableTest().panel, "Test");
}
});
}
}
I accomplished this by enabling the editing and then making the component responsible for the edition ignore any changes. For this I created a TableCellEditor and intercepted the key types to the JTextField, the component used for editing.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
public class TableCellSelectionTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
new TableCellSelectionTest().initUI();
}
});
}
public void initUI()
{
JFrame frame = new JFrame();
int N = 5;
int M = 3;
Object[][] data = new Object[N][M];
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
data[i][j] = "This is the cell (" + i + ", " + j +")";
}
}
String[] columnNames = { "Column 1", "Column 2", "Column 3" };
DefaultTableModel model = new DefaultTableModel(data, columnNames);
final MyTableCellEditor editor = new MyTableCellEditor();
JTable table = new JTable(model) {
#Override
public TableCellEditor getCellEditor(int row, int column)
{
return editor;
}
};
frame.add(new JScrollPane(table), BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class MyTableCellEditor extends AbstractCellEditor implements
TableCellEditor
{
Object _value;
#Override
public Object getCellEditorValue()
{
return _value;
}
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column)
{
_value = value;
JTextField textField = new JTextField(_value.toString());
textField.addKeyListener(new KeyAdapter()
{
public void keyTyped(KeyEvent e) {
e.consume(); //ignores the key
}
#Override
public void keyPressed(KeyEvent e)
{
e.consume();
}});
textField.setEditable(false); //this is functionally irrelevent, makes slight visual changes
return textField;
}
}
}
I tried both the answers here... but one problem at least is that you can tell when you've entered the "editing" mode.
This might be of interest... uses a combination of Editor magic and cheeky rendering to make it look like no editing is going on: editor's click-count-to-start is set to 1, and the component (JTextPane) delivered by the editor's method does setEditable( false ).
If this tickles your fancy, you might be interested at looking at my implementation of a JTable which adjusts (perfectly, harnessing the JTextPane's powerful wrapping power) the row height to the text, for individual rows, including when you change the columns: How to wrap lines in a jtable cell?
public class SelectableNonEditableTableTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame main_frame = new JFrame();
main_frame.setPreferredSize(new Dimension(1200, 300));
main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ArrayList<String> nonsense = new ArrayList<String>(
Arrays.asList(
"Lorem ipsum dolor sit amet, sed dolore vivendum ut",
"pri an soleat causae doctus.",
"Alienum abhorreant mea ea",
"cum malorum diceret ei. Pri oratio invidunt consequat ne.",
"Ius tritani detraxit scribentur et",
"has detraxit legendos intellegat at",
"quo oporteat constituam ex"));
JTable example_table = new JTable(10, 4);
example_table.setRowHeight( example_table.getRowHeight() * 2 );
DefaultCellEditor cell_editor = new SelectableNonEditableCellEditor(
new JTextField());
cell_editor.setClickCountToStart(1);
example_table.setDefaultEditor(Object.class, cell_editor);
TableCellRenderer renderer = new SelectableNonEditableTableRenderer();
example_table.setDefaultRenderer(Object.class, renderer);
for (int i = 0; i < 10; i++) {
example_table.setValueAt(nonsense.get(i % nonsense.size()),
i, i % 4);
}
main_frame.getContentPane().add(new JScrollPane(example_table));
main_frame.pack();
main_frame.setVisible(true);
}
});
}
}
class SelectableNonEditableCellEditor extends DefaultCellEditor {
public SelectableNonEditableCellEditor(JTextField textField) {
super(textField);
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int col) {
Component comp = super.getTableCellEditorComponent(table, value,
isSelected, row, col);
if (value instanceof java.lang.String) {
DefaultStyledDocument sty_doc = new DefaultStyledDocument();
try {
sty_doc.insertString(0, (String) value, null);
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JTextPane jtp_comp = new JTextPane(sty_doc);
jtp_comp.setEditable(false);
return jtp_comp;
}
return comp;
}
}
class SelectableNonEditableTableRenderer extends JTextPane implements
TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof DefaultStyledDocument) {
setDocument((DefaultStyledDocument) value);
} else {
setText((String) value);
}
return this;
}
}
Maybe you can implement your own TableCellRenderer that extends JTextField in your table.

Multiplication between two cells of a JTable in Java

When I enter values in the cells of the 1st row of columns "Units" and "Price" , column "Amount"; the columns cell value should be set to the product of unit and amount . Which listener should I use? Please help as I'm new to Java.
CODE:
JTable jTable1;
DefaultTableModel mod=new DefaultTableModel();
mod.addColumn("No");
mod.addColumn("Item ID");
mod.addColumn("Units");
mod.addColumn("Amount");
mod.addColumn("UOM");
mod.addColumn("Delivery Date");
mod.addColumn("Total Amount");
mod.addColumn("Notes");
mod.addColumn("Received");
mod.addRow(new Object [][] {
{1, null, null, null, null, null, null, null, null}
});
jTable1.setModel(mod);
jTable1.setColumnSelectionAllowed(true);
The idea is to implement a TableModel so that it automatically returns the result of the product of unit and amount. Here is a small demonstration of what I mean (to add a new row, simply double click below the table):
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class TestTable3 {
protected void initUI() {
final DefaultTableModel model = new DefaultTableModel() {
#Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return Integer.class;
case 1:
case 2:
return Double.class;
}
return super.getColumnClass(columnIndex);
}
#Override
public Object getValueAt(int row, int column) {
if (column == 2) {
Integer i = (Integer) getValueAt(row, 0);
Double d = (Double) getValueAt(row, 1);
if (i != null && d != null) {
return i * d;
} else {
return 0.0;
}
}
return super.getValueAt(row, column);
}
#Override
public boolean isCellEditable(int row, int column) {
return column == 0 || column == 1;
}
#Override
public void setValueAt(Object aValue, int row, int column) {
super.setValueAt(aValue, row, column);
fireTableCellUpdated(row, 2);
}
#Override
public String getColumnName(int column) {
switch (column) {
case 0:
return "Quantity";
case 1:
return "Price";
case 2:
return "Total";
}
return super.getColumnName(column);
}
#Override
public int getColumnCount() {
return 3;
}
};
final JTable table = new JTable(model);
table.setFillsViewportHeight(true);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
if (table.rowAtPoint(e.getPoint()) < 0) {
model.addRow(new Vector());
}
}
}
});
model.addRow(new Vector());
JFrame frame = new JFrame(TestTable3.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollpane = new JScrollPane(table);
frame.add(scrollpane, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestTable3().initUI();
}
});
}
}
And the result:
When I enter values in the cells of the 1st row of columns "Units" and
"Price" , column "Amount"; the columns cell value should be set to the
product of unit and amount
have look at TableModelListener
have to read the Oracle JTable tutorial

Java, change a cell content as a function of another cell in the same row

I need some help for my problem. I have a table with e.g. a double column and a string column. If the value in the double column is negativ, the string should be "negativ". And the other way if the value is positiv, the string should be "positiv".
The problem is now if I edit the double value in the jTable, the string should also be updated.
Update to my question, the actual code look like this:
But it doesn't work, because the string in the second column wont be updated after I edit the first column value. It only works when I start the program the first time.
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
public class ExampleRemoveAddRows extends JFrame {
private Object[] columnNames = {"Double", "positiv / negativ"};
private Object[][] data = {
{new Double(10.0), "positiv"},
{new Double(-10.0), "negativ"},
{new Double(20.0), "positiv"},
{new Double(-30.0), "negativ"}
};
private JTable table;
private DefaultTableModel model;
public ExampleRemoveAddRows() {
model = new DefaultTableModel(data, columnNames) {
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
#Override
public Object getValueAt(int row, int column) {
if (column == 1) {
double number = Double.parseDouble(this.getValueAt(row, 0).toString());
System.out.println(number);
System.out.println("good");
System.out.println((number < 0) ? "negativ" : "positiv");
return "C: "+ this.getValueAt(row, 0);//((number < 0) ? "negativ" : "positiv");
} else {
return super.getValueAt(row, column);
}
}
};
table = new JTable(model);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ExampleRemoveAddRows frame = new ExampleRemoveAddRows();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Thanks for your help.
Sam
I've revised your sscce to show the alternate approach suggested here. Note the alternate ways to get a Double constant. I've also re-factored the String constrants.
Addendum: In helpful comments, #kleopatra observes that querying the model directly will always produce the correct result, but a TableModelListener will only see changes to column 0, not column 1. The simple expedient is to make column 1 non-editable, as its value depends completely on column 0.
#Override
public boolean isCellEditable(int row, int col) {
return col == 0;
}
The first example below uses DefaultTableModel:
import javax.swing.*;
import javax.swing.table.*;
/** #see https://stackoverflow.com/a/13628183/230513 */
public class ExampleRemoveAddRows extends JFrame {
public static final String NEGATIVE = "negativ";
public static final String POSITIVE = "positiv";
private Object[] columnNames = {"Double", POSITIVE + " / " + NEGATIVE};
private Object[][] data = {
{10d, null},
{-10.0, null},
{Double.valueOf(30), null},
{Double.valueOf("-30"), null}
};
private JTable table;
private DefaultTableModel model;
public ExampleRemoveAddRows() {
model = new DefaultTableModel(data, columnNames) {
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
return col == 0;
}
#Override
public Object getValueAt(int row, int col) {
if (col == 1) {
double number = (Double) this.getValueAt(row, 0);
return (number < 0) ? NEGATIVE : POSITIVE;
} else {
return super.getValueAt(row, col);
}
}
#Override
public void setValueAt(Object aValue, int row, int col) {
super.setValueAt(aValue, row, col);
fireTableCellUpdated(row, 1); // may have changed
}
};
table = new JTable(model);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ExampleRemoveAddRows frame = new ExampleRemoveAddRows();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
This variation extends AbstractTableModel:
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;
/**
* #see https://stackoverflow.com/a/13628183/230513
*/
public class ExampleRemoveAddRows extends JFrame {
public static final String NEGATIVE = "negativ";
public static final String POSITIVE = "positiv";
public ExampleRemoveAddRows() {
DoubleModel model = new DoubleModel();
model.add(10.1);
model.add(-10.2);
model.add(Double.valueOf(30.1));
model.add(Double.valueOf("-30.2"));
JTable table = new JTable(model);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ExampleRemoveAddRows frame = new ExampleRemoveAddRows();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private class DoubleModel extends AbstractTableModel {
List<Double> data = new ArrayList<Double>();
public void add(Double d) {
data.add(d);
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public String getColumnName(int col) {
if (col == 0) {
return "Double";
} else {
return POSITIVE + " / " + NEGATIVE;
}
}
#Override
public Class<?> getColumnClass(int col) {
if (col == 0) {
return Double.class;
} else {
return String.class;
}
}
#Override
public boolean isCellEditable(int row, int col) {
return col == 0;
}
#Override
public Object getValueAt(int row, int col) {
if (col == 0) {
return data.get(row);
} else {
double number = (Double) this.getValueAt(row, 0);
return (number < 0) ? NEGATIVE : POSITIVE;
}
}
#Override
public void setValueAt(Object aValue, int row, int col) {
if (col == 0) {
data.set(row, (Double) aValue);
fireTableRowsUpdated(row, row);
}
}
}
}
You do indeed have access to the TableModel, if I'm not mistaken, through TableModelEvent.getSource().
Just to provide a basic example (mostly because the one sentance answer hardly seems like much of an answer):
TableModel model = (TableModel)te.getSource();
Double number = model.getValueAt(te.firstRow, 0);
model.setValueAt(((number < 0) ? "negativ":"positiv"), te.firstRow, 1);

Categories