JSpinner Update - java

I creates a dataTable and cellEditor form one column. This column is simple jSpinner. I have the following problem. When I enter some value in the spinner and select the another row, the value in the previous row won't be changed. If I press , it'll done. If I select or button, it will done too. But if I enter value and change selection, it won't be done. Help, please. Here is the CellEditor code.
public class DurationTableCellEditor extends AbstractCellEditor implements TableCellEditor{
final JSpinner spinner = new JSpinner();
// Initializes the spinner.
public DurationTableCellEditor() {
spinner.setModel(new SpinnerNumberModel(1,1,50000,1));
}
// Prepares the spinner component and returns it.
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
spinner.setValue(new Integer(value.toString()).intValue());
spinner.setCursor(null);
return spinner;
}
// Enables the editor only for double-clicks.
#Override
public boolean isCellEditable(EventObject evt) {
if (evt instanceof MouseEvent) {
return ((MouseEvent)evt).getClickCount() >= 1;
}
return true;
}
// Returns the spinners current value.
public Object getCellEditorValue() {
return spinner.getValue();
}
}

It's not clear how you're updating your data model, but one approach would be to implement ChangeListener in your CellEditor, much as this example implements ItemListener. For reference, see How to Use Tables: Using Other Editors. In particular, look at fireEditingStopped(). Finally, you'll need a corresponding TableCellRenderer.

do commitEdit()
// Returns the spinners current value.
public Object getCellEditorValue() {
spinner.commitEdit();
return spinner.getValue();
}

Related

Need to launch a new JPanel on click event in a JTable cell.

I want to create a JTable having the last column with advanced options icon. On clicking this last column in the JTable, I want a new JPanel to pop up allowing user to enter input for required 4 string input fields. This JPanel when dismissed, should return to the original JTable.
I am not sure where to save the data for 4 fields from the new JPanel. As their would be 4 string input fields per JTable row, just displayed in the JPanel.
Can my JTabel cell hold an object saving the data?
UseCase: I have a JTable with 10 columns. It is getting very cluttered so I want to move 5 columns to a new panel which will be launched on clicking an advanced options icon in the original JTable last column.
Sample code on how to associate the data from the JPanel with the row in JTable will be highly appreciated.
In order to show a pop-up when cell is clicked, you need a cell editor class. The main purpose of this class is to provide custom editors for cells, but you can use it to trigger some action when your cell is clicked:
public class InfoCellEditor extends AbstractCellEditor implements TableCellEditor {
#Override
public java.awt.Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
InfoObject info = (InfoObject) value;
editButton = new JButton(new InfoAction(info));
editButton.setText("INFO");
editButton.setEnabled(true);
}
private class InfoAction extends AbstractAction {
InfoObject info;
public InfoAction(InfoObject info) {
super();
this.info = info;
}
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, info.toString());
stopCellEditing();
}
}
}
Then, extend JTable class and implement getColumnClass and isCellEditable methods:
public class MyTable extends JTable {
public MyTable() {
super();
setDefaultEditor(InfoObject.class, new InfoCellEditor());
}
#Override
public Class getColumnClass(int columnIndex) {
if(columnIndex == 4)
return InfoObject.class;
else
return String.class;
}
#Override
public boolean isCellEditable(int row, int column) {
if(column == 4)
return true;
else
return false;
}
}
Lastly, you should make sure that InfoObject instances are inserted to 5th column. And you can also implement a TableCellRenderer for some custom visual representation of that column.
Object headers = new Object[COLUMN_COUNT];
Object cells[][] = new Object[ROW_COUNT][];
...
cells[0][4] = new InfoObject(data[0]);
cells[1][4] = new InfoObject(data[1]);
table.setModel(new DefaultTableModel(cells, headers));
table.getModel().fireTableDataChanged();
table.setVisible();

JTextField doesn't update on keypress

I have a JTable that uses a custom TableModel. I extended the AbstractCellEditor class and the cell correctly displays the text typed in to the textfield when I double-click the textfield. but when I just single-click select the cell in the table and start typing, the textfield receives the text but when I press enter, it doesn't update the text field. I attached a focus listener to the textfield to troubleshoot and found that it only gains and loses focus when I double click on the field. With a single-click it doesn't gain focus (even though it allows me to edit it). This boggles my mind! I've tried textField.grabFocus(), textField.requestFocusInWindow(), and all sorts of other things. Any suggestions? Thanks!
public class IndexerCellEditor extends AbstractCellEditor implements
TableCellEditor {
private JTextField textField;
private RecordValue currentValue;
public IndexerCellEditor(){
textField = new JTextField();
}
#Override
public boolean isCellEditable(EventObject e){
if(e instanceof MouseEvent){
return ((MouseEvent)e).getClickCount() >= 2;
}
return true;
}
#Override
public Object getCellEditorValue() {
return currentValue;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
textField.setBorder(BorderFactory.createLineBorder(Color.black, 1));
currentValue = (RecordValue) value;
textField.setText(currentValue.getValue());
textField.addFocusListener(new FocusListener(){
#Override
public void focusGained(FocusEvent e) {
System.out.println("focus gained");
}
#Override
public void focusLost(FocusEvent e) {
System.out.println("focus lost");
}
});
textField.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
currentValue.setValue(((JTextField)e.getSource()).getText());
fireEditingStopped();
}
});
return textField;
}
}
OK so after about 8 more hours of banging my head against the wall, I found out 2 things:
I don't need an action listener on the jtextfield because the JTable takes care of that for me. When I hit enter after double clicking + typing OR single-click + typing, JTable automatically calls stopCellEditing(), which brings me to
I need to override stopCellEditing() in my IndexerCellEditor class to save the JTextField text before passing it up to the parent. The code I was missing:
#Override
public boolean stopCellEditing(){
currentValue = textField.getText();
return super.stopCellEditing();
}
Hope this helps anyone with the same problem.
EDIT
This works in my case because I also extended DefaultTableModel, which takes care of notifying the listeners with the method:
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
cells[rowIndex][columnIndex] = (String) aValue;
fireTableCellUpdated(rowIndex, columnIndex);
}
I tested this some more by building two different tables with the same extended DefaultTableModel. Placing them side-by-side in a JPanel, I could edit one cell in one table and upon pressing enter, it would update both the edited cell and its counterpart cell in the other table. In short, the listeners DO need to be notified with a fire... method call somewhere in the project.

JDateChooser inside JTable cell enter key does not always work

I'm using slightly modified JDateChooserCellEditor class which allows me to put jDateChooser inside my jTable cell. Here is the code of class:
public class JDateChooserCellEditor extends AbstractCellEditor implements
TableCellEditor {
private JDateChooser dateChooser = new JDateChooser();
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
Date date = null;
if (value instanceof Date) {
date = (Date) value;
}
dateChooser.setDateFormatString("dd-MM-yyyy");
dateChooser.setDate(date);
return dateChooser;
}
public Object getCellEditorValue() {
dateChooser.setDateFormatString("dd-MM-yyyy");
return dateChooser.getDate();
}
One thing does not work and I cannot find a solution. When I click for the first time on a cell that has jDateChooser inside, select date and hit enter key - nothing happens. The component maintains its focus but never confirms data. But if I after that select different cell the enter key magically works and date is saved to my jTable. After another try it does not work.. Next try - it works. It is so confusing. Thank you all for any help.
Your TableCellEditor is incorrect. Assuming that your Table model stores instances of Date, invoke setDefaultEditor() as shown with DemoTableModel, which is found in the class com.toedter.calendar.demo.DemoTable and illustrated here.
table.setDefaultEditor(Date.class, new JDateChooserCellEditor());
Addendum: Don't set the date format in the cell editor; specify it in the JDateChooser constructor or using setDateFormatString().
Well, I have found solution for my problem. I think its not the best way but it works and I have lost too much time trying to fix this. Adding listener to jDateChooser component and notifying to stop editing on property change as user kleopatra stated seems to solve the problem.
dateChooser.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("date")) {
stopCellEditing();
}
}
});
Thank you all for help.
A variation of your answer worked for me
private AbstractTableModel model;
.....
... in method getTableCellEditorComponent(JTable table, Object value, boolean isSelected, final int row, final int column) .....
try{
model = (AbstractTableModel) table.getModel();
} catch( Exception e){};
dateChooser.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String pname = evt.getPropertyName();
if ( "date".equals( pname)) {
try{
model.fireTableCellUpdated( row, column);
} catch( Exception e){};
}
}
});
Super side effect - if you make your table smaller, with your mouse, and the JDateChooser exits the window table (margins are outside the table) while editing, then everything works perfect - no workaround necessary - It is a Swing bug that the refresh is done only when you have to take care of other windows outside you (probably an auto refresh all is called - that's why this bug was not discovered yet)
******
yourtable.getColumnModel().getColumn(7).setCellEditor(getDateChooserCellEditor());
or
yourtable.setDefaultEditor(java.util.Date.class, getDateChooserCellEditor());
******
public JDateChooserCellEditor getDateChooserCellEditor() {
JDateChooserCellEditor cellEditor = new JDateChooserCellEditor(){
#Override
public Component getTableCellEditorComponent(JTable jtable, Object o, boolean bln, int i, int i1) {
java.awt.event.ActionListener l = getStopCellEditorActionListener(jtable);
Component component = super.getTableCellEditorComponent(jtable, o, bln, i, i1);
JDateChooser dateChooser = (JDateChooser) component;
JTextField dateEditor = (JTextField) dateChooser.getDateEditor().getUiComponent();
try {
dateEditor.removeActionListener(l);
dateEditor.addActionListener(l);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage());
}
return component;
}
};
return cellEditor;
}
private java.awt.event.ActionListener getStopCellEditorActionListener(JTable table) {
return new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
table.editingStopped(new ChangeEvent(table.getCellEditor()));
}
};
}

How can I make a JTable cell do different things on single-click than on double-click?

I am using an editable JTable that contains a column named Subject. When the first row is empty and the user clicks on a subject cell to add new task, by default, the user has to click twice to make the cell editable. I want to make it editable on single-click and have it open another form on double-click. I have tried MouseListener but have not been able to solve it. Is there a way to solve this problem? If so, what is it?
My code:
class mouseRenderer extends DefaultTableCellRenderer {
JLabel lblcell = new JLabel();
public Component getTableCellRendererComponent(JTable table, Object obj, boolean isSelected, boolean hasFocus, int row,
int column) {
ttable.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
selrow = ttable.getSelectedRow();
selcol = ttable.getSelectedColumn();
if(e.getClickCount() == 1) {
if(selrow == 0) {
lblcell.setText("");
}
}
}
});
return lblcell;
}
}
For the one-click to edit, you could try the 'setClickCountToStart()' method of the celleditor used in your jtable.
You can try to create a custom CellEditor like this one and set it with setCellEditor()
public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {
public boolean isCellEditable(EventObject evt) {
if (evt instanceof MouseEvent) {
int clickCount;
// For single-click activation
clickCount = 1;
// For double-click activation
clickCount = 2;
// For triple-click activation
clickCount = 3;
return ((MouseEvent)evt).getClickCount() >= clickCount;
}
return true;
}
}
The MouseListener is the way to go for capturing double clicks on a row. It should work fine.
As far as one-click to edit, you might want to select rows using a MouseMotionListener and let the JTable take the single-click to edit. Another option might be to use a MouseListener to detect the cell that was clicked, but that is getting a little messy.

How to use JLists in JTable cells?

I would like a simple way to put a JList in a column of a JTable. I already have the JLists and the table, but when put in the table, the Jlists are displayed as Strings, which is normal, because I use DefaultTableModel. I have overriden the getColumnClass() as:
public Class<? extends Object> getColumnClass(int c)
{
return getValueAt(0, c).getClass();
}
but this just formats the integer and float values.
I suppose that setValueAt() and getValueAt() should also be overriden, in order to return am array of Strings when I call JList.getSelectedValues(), but I can't figure out how.
I also want the cells to be editable, so the users can choose one or more option from the JList. After editing a row, I use a Save button to save the changes in a database, so I don't think I need a ListSelectionListener, JList.getSelectedValues() works just fine.
I know this is a common question, but I couldn't find an answer here. If this is a duplicate, please let me know and I will delete it.
I've done it. For everyone who needs the same thing, here is what I've done:
1)I have created a JScrollTableRenderer, and set the column I needed to show the JList to use this renderer
table.getColumnModel().getColumn(5).setCellRenderer(new JScrollTableRenderer());
The JScrollTableRenderer class content:
public class JScrollTableRenderer extends DefaultTableCellRenderer {
JScrollPane pane = new JScrollPane();
public JScrollTableRenderer()
{
super();
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column)
{
pane = (JScrollPane) value;
return pane;
}
}
2)I have created a JScrollTableEditor, and set the column I needed to show the JList to use this editor
table.getColumnModel().getColumn(5).setCellEditor(new JScrollTableEditor());
The JScrollTableEditor class content:
public class JScrollTableEditor extends AbstractCellEditor implements TableCellEditor {
JScrollPane component = new JScrollPane();
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int rowIndex, int vColIndex)
{
component = ((JScrollPane) value);
return ((JScrollPane) value);
}
public Object getCellEditorValue()
{
return component;
}
}
3)I added this method in the JTable model:
public Class<? extends Object> getColumnClass(int c)
{
if(c == 5) return JScrollPane.class;
else return getValueAt(0, c).getClass();
}

Categories