I have set a cell editor for one of the columns to be a JSpinner and it works, but when the data in the data model changes the editor i enabled before is still enabled nad it shows the value form the old row (it does not exist or it is in a different place in the changed data).
How can i make the editor for the selected cell disappear saving the entered value when the data changes?
this one could be good code for your SSCCE
import java.awt.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class SpinnerColumn extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
private static final long serialVersionUID = 1L;
private JSpinner editSpinner, renderSpinner;
private JTable table;
private String[] list;
private Border originalBorder;
public SpinnerColumn(JTable table, int column) {
editSpinner = new JSpinner();
renderSpinner = new JSpinner();
originalBorder = editSpinner.getBorder();
editSpinner.setBorder(new LineBorder(Color.BLUE));
this.table = table;
table.getColumnModel().getColumn(column).setCellEditor(this);
}
public SpinnerColumn(String[] list, JTable table, int column) {
editSpinner = new JSpinner();
editSpinner.setModel(new SpinnerListModel(list));
renderSpinner = new JSpinner();
originalBorder = editSpinner.getBorder();
editSpinner.setBorder(new LineBorder(Color.BLUE));
this.list = list;
this.table = table;
table.getColumnModel().getColumn(column).setCellEditor(this);
}
#Override
public Object getCellEditorValue() {
return editSpinner.getValue();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column) {
if (list != null) {
editSpinner.setValue(list[0]);
} else {
editSpinner.setValue(0);
}
if (value != null) {
editSpinner.setValue(value);
}
return editSpinner;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
if (hasFocus) {
renderSpinner.setBorder(new LineBorder(Color.BLUE));
} else {
renderSpinner.setBorder(originalBorder);
}// *** here's where we set the spinner's value
if (value == null) {
renderSpinner.setValue(0);
} else {
int intValue = ((Integer) value).intValue();
renderSpinner.setValue(intValue);
}
return renderSpinner;
}
#Override
public boolean isCellEditable(EventObject evt) {
return true;
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("SpinnerColumn");
JPanel panel = new JPanel(new GridLayout(1, 1));
JTable table = new JTable(5, 1);
SpinnerColumn spinnerColumn = new SpinnerColumn(table, 0);
table.setDefaultRenderer(Object.class, spinnerColumn);
panel.add(table);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
}
Related
When I click on a table cell, and then click on a second table cell, a number of mouse and focus events occur that I do not understand. For example, clicking of cell (1, 0) and then on cell (2, 1) and then the Done button to display the sequence of events causes the following events:
1) Mouse Pressed on cell (1,0)
2) Focus Gained on cell (1,0)
3) Mouse Pressed on cell (1,0) - why(?)
4) Mouse Pressed on cell (2,1)
5) Focus Lost on cell (1,0) - why(?)
6) Focus Lost on cell (2,1)
7) Focus Gained on cell (1,0) - why(?)
8) Focus Gained on cell (2,1) - why(?)
9) Focus Lost on cell (1,0) - why(?)
10) Focus lost on cell (2,1) - why(?)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.*;
import static javax.swing.SwingConstants.CENTER;
import static javax.swing.SwingConstants.LEFT;
import javax.swing.SwingUtilities;
import javax.swing.table.*;
public class TestFocus {
public ArrayList<String> mylog;
public int number = 0;
public TestFocus() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = createPanel();
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public JPanel createPanel() {
mylog = new ArrayList<>();
JPanel panel = new JPanel();
TestTableModel tm = new TestTableModel();
JLabel title = new JLabel("Test Table");
JTable table = new JTable(tm);
TableColumnModel tcm = table.getColumnModel();
TestTableCellEditor editor = new TestTableCellEditor();
TestTableCellRenderer renderer = new TestTableCellRenderer();
for (int i = 0; i < tm.getColumnCount(); i++) {
TableColumn column = tcm.getColumn(i);
column.setCellEditor(editor);
column.setCellRenderer(renderer);
}
JScrollPane jsp = new JScrollPane(table);
JButton btn = new JButton("Done");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
for (String s : mylog) {
System.out.println(s);
}
}
});
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
panel.add(jsp);
panel.add(btn);
return panel;
}
class TestTableModel extends AbstractTableModel {
private String[] columnNames = { "Firstname", "Lastname", "Age" };
private Object[][] data = {
{ "John", "Smith", 29},
{ "Mary", "Thomas", 63},
{ "Peter", "Jones", 48} };
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
public String getColumnClassName(int col) {
if (col == 2) {
return "Integer";
} else {
return "String";
}
}
public boolean isCellEditable(int row, int col) {
return true;
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
public class TestTableCellEditor extends AbstractCellEditor
implements TableCellEditor {
JComponent component = new JTextField();
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
((JTextField)component).addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent me) {
mylog.add(++number + ") Mouse pressed: " +
value.toString() + ": r/c ("+row+"/"+column+")");
}
});
((JTextField)component).addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent fe) {
mylog.add(++number + ") Focus gained: " +
value.toString() + ": r/c ("+row+"/"+column+")");
}
#Override
public void focusLost(FocusEvent fe) {
mylog.add(++number + ") FocusLost: " +
value.toString() + ": r/c ("+row+"/"+column+")");
}
});
if (value != null) {
((JTextField)component).setText(value.toString());
} else {
((JTextField)component).setText("");
}
return (JTextField)component;
}
#Override
public Object getCellEditorValue() {
return ((JTextField)component).getText();
}
}
public class TestTableCellRenderer extends JLabel implements
TableCellRenderer {
public TestTableCellRenderer() {
this.setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, final int row, int column) {
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
Component c = renderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
if (hasFocus) {
c.setBackground(Color.yellow);
}
TestTableModel tm = (TestTableModel)table.getModel();
int col = table.convertColumnIndexToModel(column);
String colname = tm.getColumnName(col);
String type = tm.getColumnClassName(col);
if (type.equals("Integer") || type.equals("Int")) {
((JLabel)c).setHorizontalAlignment(CENTER);
} else { // add padding
((JLabel)c).setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
((JLabel)c).setHorizontalAlignment(LEFT);
}
if (type.equals("String")) {
String text = ((JLabel)c).getText();
((JLabel)c).setToolTipText(text);
}
return c;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestFocus();
}
});
}
}
getTableCellEditorComponent method will be called very time the JTable gets rendered - a lot of times. Inside it you textfield.addMouseListener(). That means the listener will be added a lot of times. That's why you get many events instead of one (all these listeners are notified). In order to solve it, add the listeners only one time. You can add the listeners in constructor of this class.
For example:
public class TestTableCellEditor extends AbstractCellEditor implements TableCellEditor {
private JTextField component;
public TestTableCellEditor() {
component = new JTextField();
component.addMouseListener(mouseListener);
component.addFocusListener(focusListener)
}
#Override
public Object getCellEditorValue() {
return component.getText();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
component.setText(value == null ? "" : String.valueOf(value));
return component;
}
}
I tried to find here for a long time answer for my question but without the exact result i expected.
I have JTable which every time i am changing values in entire column (only in one column every time).
I want to listen to a table changes and when data changes in the column, the color in the column will be changed too and all other columns will be in the default color.
This is the code for the table listener:
Class CustomCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component rendererComp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
table.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
if(***here i want to know which column changed or something like that***){
rendererComp.setBackground(Color.CYAN);
}
}
});
return rendererComp ;
}
}
and this is the code for the table creation:
private void createTable() {
tablePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
DefaultTableModel tableModel = new DefaultTableModel(){
#Override
public boolean isCellEditable(int row, int column) {
//all cells false
return false;
}
};
contentTable = new JTable(tableModel);
contentTable.setGridColor(Color.LIGHT_GRAY);
for(int i=0; i<columnSize; i++) {
tableModel.addColumn("0");
}
for(int i=0; i<rawSize; i++) {
tableModel.addRow(new Object[] { "" });
}
for(int i=0; i<rawSize; i++) {
for(int j=0; j<tableModel.getRowCount(); j++) {
tableModel.setValueAt("0", j, i);
}
}
for(int i=0; i<ramSize; i++) {
contentTable.getColumnModel().getColumn(i).setCellRenderer(new CustomCellRenderer());
}
JScrollPane scrollPane = new JScrollPane(contentTable);
scrollPane.setPreferredSize(new Dimension(400, 150));
tablePanel.add(scrollPane);
}
Store the desired state in the TableModel; let the TableCellRenderer use the state to condition the view accordingly. In the example below, as soon as setValueAt() updates any cell, edited is marked true. The render, which is applied to column zero, changes the display accordingly. Note how clearEdited() invokes fireTableDataChanged() to force the table to render all cells when called in the Clear handler.
Addendum: The update below shows one approach to handling multiple columns independently. The CustomModel now contains a Map<Integer, Boolean> to store the edited state for each column to which the CustomRenderer is applied. As an aside, the CustomRenderer now invokes convertColumnIndexToModel() and sets the selection color correctly.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
/**
* #see http://stackoverflow.com/a/37439731/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CustomModel model = new CustomModel();
model.setColumnIdentifiers(new String[]{"A", "B"});
for (int i = 0; i < 16; i++) {
model.addRow(new String[]{"A:" + i, "B:" + i});
}
JTable table = new JTable(model) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(100, getRowHeight() * getRowCount() / 2);
}
};
table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer(model));
table.getColumnModel().getColumn(1).setCellRenderer(new CustomRenderer(model));
f.add(new JScrollPane(table));
JPanel p = new JPanel();
p.add(new JButton(new UpdateAction("Update A", model, 0)));
p.add(new JButton(new UpdateAction("Update B", model, 1)));
p.add(new JButton(new AbstractAction("Clear") {
#Override
public void actionPerformed(ActionEvent e) {
model.clearEdited(0);
model.clearEdited(1);
}
}));
f.add(p, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class CustomModel extends DefaultTableModel {
private final Map<Integer, Boolean> edited = new HashMap<>();
public boolean isEdited(int column) {
return edited.get(column) != null && edited.get(column);
}
public void clearEdited(int column) {
edited.put(column, false);
fireTableDataChanged();
}
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
#Override
public void setValueAt(Object aValue, int row, int column) {
super.setValueAt(aValue, row, column);
edited.put(column, true);
}
}
private static class CustomRenderer extends DefaultTableCellRenderer {
private final CustomModel model;
public CustomRenderer(CustomModel model) {
this.model = model;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
Component c = super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, col);
if (model.isEdited(table.convertColumnIndexToModel(col))) {
c.setBackground(Color.cyan);
} else if (isSelected) {
c.setBackground(table.getSelectionBackground());
} else {
c.setBackground(table.getBackground());
}
return c;
}
}
private static class UpdateAction extends AbstractAction {
private final CustomModel model;
private final int column;
public UpdateAction(String name, CustomModel model, int column) {
super(name);
this.model = model;
this.column = column;
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < model.getRowCount(); i++) {
model.setValueAt(model.getValueAt(i, column), i, column);
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Test()::display);
}
}
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.
I have a GUI designed as a Form in Netbeans 7.2. I have a JTable with the troublesome behavior. The table model is designed with Right-Click -> Properties -> Model and setting up 1 row and 12 columns with types Long and Double for editable number fields.
Now if I navigate to such a cell which contain e.g. "0.0" and just start typing "123" I get "0.0123" instead of "123". I would like it to work that if you just start typing you start with a blank value - and if the entry is "clicked" then you start editing the cell and whatever you type is inserted at the cursor location.
Can this be done easily?
I found https://stackoverflow.com/a/8493016/53897 to work.
The way to add the code, is to right-click the JTable in the Navigator, and choose "Code Customizer". In the line for new javax.swing.JTable() change the drop down box to "custom creation" and you can now edit that snippet including adding the {...#Override public void changeSelection(...)...} needed for this.
whats wrong with standard Swing JTable and DefaultTableModel
sure there are missing some ideas for productions code (make the things better)..., selectAll for Editor, cell alingment, background, foreground, stripping, font, Look and Feels etc... (most of custom Look and Feels doesn't works correctly with built-in Components pallette in Netbeans Swing Framework),
SwingX have got Components pallette for Netbeans, better and safest way, maybe you have look at ...
import java.awt.*;
import java.awt.event.*;
import java.text.NumberFormat;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.table.*;
public class EditorTest {
private JScrollPane getTableComponent() {
String[] colNames = {"Stock", "Price", "Shares", "Quantity", "Action", "Action", "Holder"
};
final Object[][] data = {{"MSFT", Double.valueOf(12.21), Integer.valueOf(10),
Integer.valueOf(0), "Buy", "Sell", "Bill"}, {"IBM", Double.valueOf(13.21), Integer.valueOf(12),
Integer.valueOf(0), "Buy", "Sell", "Tim"}, {"ORACLE", Double.valueOf(21.22), Integer.valueOf(11),
Integer.valueOf(0), "Buy", "Sell", "Tom"}
};
DefaultTableModel model = new DefaultTableModel(data, colNames) {
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int col) {
return data[0][col].getClass();
}
};
JTable table = new JTable(model);
TableColumnModel colModel = table.getColumnModel();
colModel.getColumn(1).setCellRenderer(new DoubleRenderer());
colModel.getColumn(3).setCellRenderer(new SpinnerRenderer());
colModel.getColumn(4).setCellRenderer(new ButtonRenderer());
colModel.getColumn(5).setCellRenderer(new ButtonRenderer());
colModel.getColumn(3).setCellEditor(new SpinnerEditor());
colModel.getColumn(4).setCellEditor(new ButtonEditorA(table));
colModel.getColumn(5).setCellEditor(new ButtonEditorA(table));
table.setCellSelectionEnabled(true);
Dimension d = table.getPreferredSize();
table.setPreferredScrollableViewportSize(d);
return new JScrollPane(table);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new EditorTest().getTableComponent());
f.pack();
f.setLocation(100, 100);
f.setVisible(true);
}
}
class SpinnerEditor extends AbstractCellEditor implements TableCellEditor {
private static final long serialVersionUID = 1L;
private SpinnerNumberModel model = new SpinnerNumberModel(0, 0, null, 1);
private JSpinner spinner = new JSpinner(model);
private int clickCountToStart = 1;
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
spinner.setValue(((Integer) value).intValue());
return spinner;
}
public Object getCellEditorValue() {
return (Integer) spinner.getValue();
}
#Override
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent) anEvent).getClickCount() >= clickCountToStart;
}
return true;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override
public boolean stopCellEditing() {
return super.stopCellEditing();
}
#Override
public void cancelCellEditing() {
super.cancelCellEditing();
}
}
class ButtonEditorA extends AbstractCellEditor implements TableCellEditor, ActionListener {
private static final long serialVersionUID = 1L;
private JTable table;
private JButton button = new JButton();
private NumberFormat nf = NumberFormat.getCurrencyInstance();
private int clickCountToStart = 1;
public ButtonEditorA(JTable table) {
this.table = table;
button.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
StringBuilder sb = new StringBuilder();
int row = table.getEditingRow();
int col = table.getEditingColumn();
//System.out.printf("row = %d col = %d%n", row, col);
sb.append((String) table.getValueAt(row, 6));
sb.append(" has ");
sb.append(((col == 4) ? "bought " : "sold "));
sb.append(((Integer) table.getValueAt(row, 3)).toString());
sb.append(" shares of " + (String) table.getValueAt(row, 0));
sb.append(" at " + nf.format(((Double) table.getValueAt(row, 1)).doubleValue()));
stopCellEditing();
System.out.println(sb.toString());
}
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int row, int column) {
button.setText(value.toString());
return button;
}
public Object getCellEditorValue() {
return button.getText();
}
#Override
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent) anEvent).getClickCount() >= clickCountToStart;
}
return true;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override
public boolean stopCellEditing() {
return super.stopCellEditing();
}
#Override
public void cancelCellEditing() {
super.cancelCellEditing();
}
}
class SpinnerRenderer implements TableCellRenderer {
private SpinnerNumberModel model = new SpinnerNumberModel(0, 0, null, 1);
private JSpinner spinner = new JSpinner(model);
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row, int column) {
spinner.setValue(((Integer) value).intValue());
return spinner;
}
}
class ButtonRendererA implements TableCellRenderer {
private JButton button = new JButton();
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
button.setText(value.toString());
return button;
}
}
class DoubleRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
private NumberFormat nf = NumberFormat.getCurrencyInstance();
public DoubleRenderer() {
setHorizontalAlignment(RIGHT);
}
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setText(nf.format(((Double) value).doubleValue()));
return this;
}
}
Since JTable could be sorted.
How do I set it auto select the last inserted row whenever a row is inserted?
Thanks
your TableModel can retun number of rows, and new/added could be last by using convertRowIndexToView you can get row in TableView, then pass to the changeSelection
public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)
EDIT: example (for enjoy harcoded numbersOfRows - 3 instead of correct numbersOfRows - 1):
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.event.*;
import javax.swing.table.*;
public class TestTableRowTable {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if (info.getName().equals("Nimbus")) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
final JTable table = new JTable(10, 6);
for (int i = 0; i < table.getRowCount(); i++) {
table.setValueAt(i, i, 0);
}
final TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(table.getModel());
table.setRowSorter(sorter);
final AbstractTableModel model = new AbstractTableModel() {
private static final long serialVersionUID = 1L;
#Override
public int getColumnCount() {
return 1;
}
#Override
public Object getValueAt(int row, int column) {
return table.convertRowIndexToModel(row);
}
#Override
public int getRowCount() {
return table.getRowCount();
}
};
JTable headerTable = new JTable(model);
headerTable.setShowGrid(false);
headerTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
headerTable.setPreferredScrollableViewportSize(new Dimension(30, 0));
headerTable.getColumnModel().getColumn(0).setPreferredWidth(30);
headerTable.getColumnModel().getColumn(0).setCellRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable x, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
boolean selected = table.getSelectionModel().isSelectedIndex(row);
Component component = table.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, value, false, false, -1, -2);
((JLabel) component).setHorizontalAlignment(JLabel.CENTER);
if (selected) {
component.setFont(component.getFont().deriveFont(Font.BOLD));
} else {
component.setFont(component.getFont().deriveFont(Font.PLAIN));
}
return component;
}
});
table.getRowSorter().addRowSorterListener(
new RowSorterListener() {
#Override
public void sorterChanged(RowSorterEvent e) {
model.fireTableDataChanged();
}
});
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
model.fireTableRowsUpdated(0, model.getRowCount() - 1);
}
});
JScrollPane pane = new JScrollPane(table);
pane.setRowHeaderView(headerTable);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(pane);
frame.getContentPane().add(new JButton(new AbstractAction("Toggle filter") {
private static final long serialVersionUID = 1L;
private RowFilter<TableModel, Object> filter = new RowFilter<TableModel, Object>() {
#Override
public boolean include(javax.swing.RowFilter.Entry<? extends TableModel, ? extends Object> entry) {
return ((Number) entry.getValue(0)).intValue() % 2 == 0;
//return ((String) entry.getValue(0)).length()>0 ;
//return ((Date) entry.getValue(0)).getTime()< ;
}
};
#Override
public void actionPerformed(ActionEvent e) {
if (sorter.getRowFilter() != null) {
sorter.setRowFilter(null);
TableModel tblModel = table.getModel();
int numbersOfRows = 0;
numbersOfRows = tblModel.getRowCount();
int lastRow = 0;
lastRow = table.convertRowIndexToView(numbersOfRows - 3);
table.changeSelection(lastRow, 0, false, false);
} else {
sorter.setRowFilter(filter);
}
}
}), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private TestTableRowTable() {
}
}
It is hard to answer,because you haven't provided any code, but, if you use some model of JTable you can write some adapter for method insert, I mean for public void insertRow(int row, Vector rowData). Here is present number of row, using this number you can select row. Do you know how to select row ?