JTable Row selection background problem. - java

I have a JTable and to set a picture as background in JTable and other properties i used this code.
tblMainView= new JTable(dtModel){
public Component prepareRenderer(TableCellRenderer renderer, int row,
int column)
{
Component c = super.prepareRenderer( renderer, row, column);
// We want renderer component to be transparent so background image
// is visible
if( c instanceof JComponent )
((JComponent)c).setOpaque(false);
return c;
}
ImageIcon image = new ImageIcon( "images/watermark.png" );
public void paint( Graphics g )
{
// First draw the background image - tiled
Dimension d = getSize();
for( int x = 0; x < d.width; x += image.getIconWidth() )
for( int y = 0; y < d.height; y += image.getIconHeight() )
g.drawImage( image.getImage(), x, y, null, null );
// Now let the regular paint code do it's work
super.paint(g);
}
public boolean isCellEditable(int rowIndex, int colIndex) {
return false;
}
public Class getColumnClass(int col){
if (col == 0)
{
return Icon.class;
}else if(col==7){
return String.class;
} else
return String.class;
}
public boolean getScrollableTracksViewportWidth() {
if (autoResizeMode != AUTO_RESIZE_OFF) {
if (getParent() instanceof JViewport) {
return (((JViewport)getParent()).getWidth() > getPreferredSize().width);
}
}
return false;
}
};
tblMainView.setOpaque(false);
Every thing is working correctly. But when i select a row, the row data hides.it shows my row like
i want the result same like this,
dtModel is the deafultTableModel for my JTable named tblMainView

Overriding prepareRenderer() is a recommended way to do custom rendering for an entire table row, but you can't make it do everything. In particular, the default renderer for Icon should do what you want, and there's no reason to override paint(), at all.
Addendum: Looking closer, your selected field appears empty because setOpaque(false) interferes with the optimization mentioned in the DefaultTableCellRenderer API. The example you copied won't work.
For reference, the example below overrides the getColumnClass() of DefaultTableModel to obtain the default renderer for types Icon and Date.
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.util.Calendar;
import java.util.Date;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
/** #see https://stackoverflow.com/questions/6873665 */
public class JavaGUI extends JPanel {
private static final int ICON_COL = 0;
private static final int DATE_COL = 1;
private static final Icon icon = UIManager.getIcon("Tree.closedIcon");
private final Calendar calendar = Calendar.getInstance();
public JavaGUI() {
CustomModel model = new CustomModel();
JTable table = new JTable(model) {
#Override
public Component prepareRenderer(
TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
if (isRowSelected(row)) {
c.setBackground(Color.blue);
} else {
c.setBackground(Color.white);
}
return c;
}
};
for (int i = 1; i <= 16; i++) {
model.addRow(newRow(i));
}
this.add(table);
}
private Object[] newRow(int i) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
return new Object[]{icon, calendar.getTime()};
}
private static class CustomModel extends DefaultTableModel {
private final String[] columnNames = {"Icon", "Date"};
#Override
public Class<?> getColumnClass(int col) {
if (col == ICON_COL) {
return Icon.class;
} else if (col == DATE_COL) {
return Date.class;
}
return super.getColumnClass(col);
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public String getColumnName(int col) {
return columnNames[col];
}
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
}
private void display() {
JFrame f = new JFrame("JavaGUI");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new JavaGUI().display();
}
});
}
}

Related

How to change the color of JTable cell after button click?

This code creates a table with cells as ImageIcon.class. By clicking the button I want be able to change the color of ImageIcon in a corresponding cell. The code sets background of the whole cell if I delete "c instanceof Icon". Otherwise, the color is not changed at all. I want to change exactly the color of 16x16 icon as specified in a renderer.
public class Test {
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("CheckTable");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTable tableCabin = new JTable(new CabinTableModel(nrows,ncols));
TableCellRenderer defaultRenderer = tableCabin.getDefaultRenderer(ImageIcon.class);
tableCabin.setDefaultRenderer(ImageIcon.class, new CabinColumnRenderer(defaultRenderer)
{
#Override
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);
if (c instanceof Icon)
{
if (row == selectedRow && column == 1)
{
c.setForeground(Color.black);
c.setBackground(Color.red);
}
else
{
c.setForeground(Color.black);
c.setBackground(null);
}
}
return c;
}
});
JTextField textfield = new JTextField(10);
textfield.setText("5");
JButton but = new JButton("Set");
but.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
selectedRow = Integer.parseInt(textfield.getText().toString());
table.repaint();
}
});
f.add(table);
f.add(textfield);
f.add(but);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
import java.awt.Color;
import java.awt.Component;
import javax.swing.Icon;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
public class CabinColumnRenderer implements TableCellRenderer
{
private TableCellRenderer delegate;
public CabinColumnRenderer(TableCellRenderer defaultRenderer)
{
this.delegate = defaultRenderer;
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
Component c = delegate.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, column);
if (c instanceof Icon)
{
c.setBackground(Color.red);
}
return c;
}
}
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.util.ArrayList;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.table.AbstractTableModel;
#SuppressWarnings("serial")
public class CabinTableModel extends AbstractTableModel
{
private String columnNames[];
private Class<?>[] columns;
private int rows;
private int cols;
private ArrayList<Object[]> data;
public CabinTableModel(int rows, int cols)
{
this.rows = rows;
this.cols = cols;
columnNames = new String[cols];
columns = new Class<?>[cols];
for (int i=0; i<cols; i++)
{
columns[i] = ImageIcon.class;
columnNames[i] = "A"+i;
}
this.data = new ArrayList<Object[]>();
for (int i = 0; i < rows; i++)
{
Object[] row = new Object[this.cols];
this.data.add(row);
for (int j=1; j<cols; j++)
row[j] = createIcon();
}
}
private Icon createIcon()
{
return new Icon()
{
private Color color = Color.green;
public int getIconHeight()
{
return 16;
}
public int getIconWidth()
{
return 16;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
g.setColor(color);
g.fillRect(x, y, getIconWidth(), getIconHeight());
}
};
}
#Override
public Class<?> getColumnClass(int columnIndex)
{
return this.columns[columnIndex];
}
public int getColumnCount()
{
return cols;
}
public int getRowCount()
{
return rows;
}
public Object getValueAt(int row, int col)
{
return data.get(row)[col];
}
#Override
public String getColumnName(int col)
{
return columnNames[col];
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return false;
}
#Override
public void setValueAt(Object value, int row, int col)
{
data.get(row)[col] = value;
fireTableCellUpdated(row, col);
}
public void deleteRows(int startIndex, int count)
{
int index = startIndex + count - 1;
while (index >= startIndex)
{
data.remove(index);
index--;
}
fireTableRowsDeleted(startIndex, startIndex + count - 1);
}
}

How to color rows of JTable according to particular value of attribute

I have JTable, and I want the result in the table to have rows colored according to particular value of attribute; comp is null here:
private JNI18NTable _issueIncidentTable = new JNI18NTable(I18N_ID, COLUMNS, "issue.table.") {
public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
Component comp = super.prepareRenderer(renderer, row, col);
int RangeIndex = Utilities.rowIndexToRangeIndex(_resultIter, row);
Row theRow = _resultIter.getRowAtRangeIndex(RangeIndex);
System.out.println("the row is" + theRow.getAttribute("Type"));
boolean markRow = theRow != null && theRow.getAttribute("Type").toString().equals("c");
boolean isSelected = isRowSelected(row);
System.out.println("the comp" + comp);
if (markRow) {
comp.setForeground(Color.white);
comp.setBackground(isRowSelected(row) ? Color.red.darker() : Color.red);
} else {
comp.setForeground(isSelected ? getSelectionForeground() : getForeground());
comp.setBackground(isSelected ? getSelectionBackground() : getBackground());
}
return comp;
}
};
Extrapolating an sscce, your implementation of prepareRenderer() seems to work as shown below. You might look elsewhere in your code for the presumed problem. In particular, the implementation of Utilities.rowIndexToRangeIndex() should probably use the table's own convert method. Moreover, use the value of isSelected consistently.
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
/**
* #see http://stackoverflow.com/a/20684058/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
JTable table = new JTable(new DefaultTableModel(10, 1) {
#Override
public Object getValueAt(int row, int col) {
return "Row " + row;
}
}) {
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
Component comp = super.prepareRenderer(renderer, row, col);
boolean isSelected = isRowSelected(row);
if (row % 2 == 0) {
comp.setForeground(Color.white);
comp.setBackground(isSelected ? Color.red.darker() : Color.red);
} else {
comp.setForeground(isSelected ? getSelectionForeground() : getForeground());
comp.setBackground(isSelected ? getSelectionBackground() : getBackground());
}
return comp;
}
};
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(table));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}

JTable valuechanged then change cell color

I have here a JTable with two(2) columns. The right column is an editable one while the other is not.
So, what my problem is that whenever the user changed the value of a cell, that specific cell will changed its cell color.
I wanna do this because I want to let the user know that he/she made some changes in the table.
I found this somewhere and it somehow solved my problem but 1 thing that didn't come up with my expectation is that after changing the value and clicked another cell, the color changes back to its original color. I want to let it stay until it is saved.
#Override
public Component prepareEditor(TableCellEditor editor, int data, int columns) {
Component c = super.prepareEditor(editor, data, columns);
c.setBackground(Color.RED);
return c;
}
Is it possible? If yes, please show some example.
UPDATE:
String[] columnname = {"Student Name", "Grade"};
Object[][] data = {};
gradetable = new JTable(data, columnname){
private Object[][] rowData;
public boolean isCellEditable(int data, int columns){
return columns == 1;
}
public Component prepareRenderer(TableCellRenderer r, int data, int columns){
final Component c = super.prepareRenderer(r, data, columns);
if (data % 2 == 0){
c.setBackground(Color.LIGHT_GRAY);
}
else{
c.setBackground(Color.WHITE);
}
if (isCellSelected(data, columns)){
c.setBackground(Color.ORANGE);
}
return c;
}
#Override
public Component prepareEditor(TableCellEditor editor, int data, int columns) {
Component c = super.prepareEditor(editor, data, columns);
c.setBackground(Color.RED);
return c;
}
};
gradetable.setModel(new DefaultTableModel(data, columnname));
gradetable.setPreferredScrollableViewportSize(new Dimension (350, 130));
gradetable.setFillsViewportHeight(true);
gradetable.getTableHeader().setReorderingAllowed(false);
gradetable.setGridColor(new Color(128,128,128,128));
JScrollPane jsp = new JScrollPane(gradetable);
panel3.add(jsp);
Tables use a TableCellRenderer to paint values on the screen. The editors and renderers don't actually have anything to do with each other (from a painting point of view).
So once the editor has been dismissed (accepted or cancelled), the cell is repainted using the assigned TableCellRenderer
You need to supply, in your table model, some way to determine which rows have been updated and change the state of the renderer to match.
FYI- The DefaultTableCellRenderer uses a JLabel as it's base renderer, so it is transparent by default; you will need to make it opaque to make it render properly.
Check out Using custom renderers for more details
Update with example
This is nothing more then a proof of concept. It will not meet your absolute requirements and you should take a serious look at the tutorial linked above.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
public class TableEdit {
public static void main(String[] args) {
new TableEdit();
}
public TableEdit() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JTable table = new JTable(new MyTableModel());
table.setSurrendersFocusOnKeystroke(true);
TableColumnModel model = table.getColumnModel();
model.getColumn(1).setCellRenderer(new MyTableCellRenderer());
add(new JScrollPane(table));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class MyData {
private String key;
private String value;
private boolean changed;
public MyData(String key, String value) {
this.key = key;
this.value = value;
this.changed = false;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
public void setValue(String newValue) {
if (value == null ? newValue != null : !value.equals(newValue)) {
value = newValue;
changed = true;
}
}
public boolean hasChanged() {
return changed;
}
}
public class MyTableModel extends AbstractTableModel {
private List<MyData> data;
public MyTableModel() {
data = new ArrayList<>(25);
for (int index = 0; index < 5; index++) {
data.add(new MyData("A" + (index + 1), "B" + (index + 1)));
}
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
MyData myData = data.get(rowIndex);
Object value = null;
switch (columnIndex) {
case 0:
value = myData.getKey();
break;
case 1:
value = myData.getValue();
break;
}
return value;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 1;
}
public boolean hasChanged(int rowIndex) {
MyData myData = data.get(rowIndex);
return myData.hasChanged();
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
MyData myData = data.get(rowIndex);
myData.setValue(aValue == null ? null : aValue.toString());
}
}
public 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);
setOpaque(isSelected);
TableModel model = table.getModel();
if (model instanceof MyTableModel) {
MyTableModel myModel = (MyTableModel) model;
if (myModel.hasChanged(row)) {
if (!isSelected) {
setBackground(Color.RED);
setOpaque(true);
}
}
}
return this;
}
}
}

JTable cell renderer skips Boolean column

Below is a picture of my JTable. My problem is that the blue background every other row isn't present in the 4th column. My table model and cell renderer are also below.
Table model:
public class MyTableModel extends DefaultTableModel {
public int getColumnCount() {
return columnNames.length;
}
public String getColumnName(int column) {
return columnNames[column];
}
public int getRowCount() {
return data.length;
}
public Object getValueAt(int row, int column) {
return data[row][column];
}
public Class getColumnClass(int column) {
return (getValueAt(0, column).getClass());
}
public void setValueAt(Object value, int row, int column) {
data[row][column] = value;
}
public boolean isCellEditable(int row, int column) {
return (column == 3);
}
}
Cell Renderer:
private class CalendarRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) {
super.getTableCellRendererComponent(table, value, selected, focused, row, column);
setBackground(new Color(0xFFFFFF));
if (row % 2 == 1) {
setBackground(new Color(0xE8F2FE)); //light blue
}
setBorder(null);
setForeground(Color.black);
return this;
}
}
The "default" cell renderer for Boolean is a check box. If you want to change the way that this cell gets rendered, you're going to have to supply your own TableCellRenderer that implements your own logic.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
public class TestTableCellRenderer {
public static void main(String[] args) {
new TestTableCellRenderer();
}
public TestTableCellRenderer() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JTable table = new JTable();
table.setModel(new TableModel());
table.setDefaultRenderer(Boolean.class, new BooleanCellRenderer());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TableModel extends AbstractTableModel {
private List<Boolean> values = new ArrayList<>(25);
public TableModel() {
for (int index = 0; index < 25; index++) {
values.add((((int) Math.round(Math.random() * 1)) == 0 ? false : true));
}
}
#Override
public int getRowCount() {
return values.size();
}
#Override
public int getColumnCount() {
return 1;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return values.get(rowIndex);
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return Boolean.class;
}
}
public static class BooleanCellRenderer extends JCheckBox implements TableCellRenderer {
private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public BooleanCellRenderer() {
setLayout(new GridBagLayout());
setMargin(new Insets(0, 0, 0, 0));
setHorizontalAlignment(JLabel.CENTER);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof Boolean) {
setSelected((Boolean) value);
}
if (!isSelected) {
setBackground(new Color(0xFFFFFF));
if (row % 2 == 1) {
setBackground(new Color(0xE8F2FE)); //light blue
}
setForeground(Color.black);
} else {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
}
if (hasFocus) {
setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
} else {
setBorder(noFocusBorder);
}
return this;
}
}
}
See Table Row Rendering for a solution that doesn't require you to keep creating custom renderers every time you have columns with different data.
JTable table = new JTable( model )
{
public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
{
Component c = super.prepareRenderer(renderer, row, column);
// Alternate row color
if (!isRowSelected(row))
c.setBackground(row % 2 == 0 ? getBackground() : Color.LIGHT_GRAY);
return c;
}
};

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