1

I am trying to write a TableCellEditor that verifies the input for a JTable cell. I have it working except that the error message is being displayed twice. Here is my tester class:

import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

public class Tester {
    public static void main(String[] args) {
        JFrame frame=new JFrame();
        frame.setPreferredSize(new Dimension(500,100));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        DefaultTableModel model=new DefaultTableModel(null,new String[] {"Col 1","Col 2"});
        JTable table=new JTable(model);
        table.getColumnModel().getColumn(0).setCellEditor(new decimalCellEditor());
        model.insertRow(0,new Object[] {null,null});
        JScrollPane scroller=new JScrollPane(table);
        frame.add(scroller);
        frame.setVisible(true);
        frame.pack();
     }
}

This is the editor:

 import java.awt.Component;

import javax.swing.AbstractCellEditor;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.TableCellEditor;


public class DecimalCellEditor extends AbstractCellEditor implements TableCellEditor {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private JTextField number=null;

    public DecimalCellEditor() {
        number=new JTextField();
    }

    @Override
    public Object getCellEditorValue() {
        String s=number.getText();
        if (s.equals("")) {
            return(s);
        }
        double x=0.;
        try {
            x=Double.parseDouble(s);
        } catch (NumberFormatException e) {
            JOptionPane.showMessageDialog(null,"Value must be numeric",null, JOptionPane.ERROR_MESSAGE, null);
            return("");
        }
        return(Double.toString(x));
    }

    @Override
    public Component getTableCellEditorComponent(JTable table_, Object value_, boolean isSelected_, int row_, int column_) {
        number.setText(String.valueOf(value_));
        return(number);
    }

    @Override
    public boolean stopCellEditing() {
        String s=(String) getCellEditorValue();
        if (s.equals("")) {
            return(super.stopCellEditing());
        }
        try {
            Double.parseDouble(s);
        } catch (NumberFormatException e) {
            fireEditingCanceled();
            return(false);
        }
        return(super.stopCellEditing());
    }
}

The objective is to assure the user enters a numeric value or no value at all (""). What is causing the error to be displayed and dismissed twice when it is non-numeric and how can I stop it? TIA.

Implementing camickr's suggestion

Assuming I understood the suggestion, I don't need the editor?

import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;

public class Tester {
    public static void main(String[] args) {
        JFrame frame=new JFrame();
        frame.setPreferredSize(new Dimension(500,100));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MyTableModel model=new MyTableModel(null,new String[] {"Col 1","Col 2"});
        JTable table=new JTable(model);
        model.insertRow(0,new Object[] {"",""});
        JScrollPane scroller=new JScrollPane(table);
        frame.add(scroller);
        frame.setVisible(true);
        frame.pack();
    }
}

Overriding getColumnClass:

import javax.swing.table.DefaultTableModel;

public class MyTableModel extends DefaultTableModel {

/**
 * 
 */
private static final long serialVersionUID = 1L;

    public MyTableModel(Object[][] data_,String[] columnNames_) {
        super(data_,columnNames_);
    }

    @Override
    public Class<?> getColumnClass(int column_) {
        if (column_==0) {
            return(Double.class);
        }
        return(getValueAt(0,column_).getClass());
    }
}

I obviously didn't do this right as I get exceptions from an unknown source saying:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Cannot format given Object as a Number

I'm guessing there is a problem with my constructor.

Wt Riker
  • 514
  • 12
  • 24
  • probably `getCellEditorValue` is being called more than once... like in `stopCellEditing()` and from maybe the `JTable`. I would try to not use it in `stopCellEditing()`, just get the text directly from the text field (as done in `getCellEditorValue()`) – user85421 Jan 22 '18 at 16:34
  • Thanks but that didn't work. It did not display the error at all which implies `getCellEditorValue` was not called. – Wt Riker Jan 22 '18 at 16:46
  • `The objective is to assure the user enters a numeric value or no value at all ("").` - just override the `getColumnClass(...)` method of the TableModel to return `Double.class` for the column and the JTable will use an appropriate editor. A red border will be placed around the cell and you won't be able to save the data until you fix the problem. Also, class names should start with an upper case character. Follow Java conventions! – camickr Jan 22 '18 at 17:05
  • Also, why would you set the renderer for the column to be a new DefaultCellRenderer? Do the tutorials ever do that? No need to implement the entire editor interface. Start with the DefaultCellEditor and customize some of the methods. Check out: https://stackoverflow.com/questions/20390445/swing-catching-exceptions-from-tablemodel/20390486#20390486 for an example of a custom editor that displays an error message when the data is incorrect. – camickr Jan 22 '18 at 17:18
  • I don't think I fully understood the suggestion. I updated the OP with my new code. – Wt Riker Jan 22 '18 at 19:30
  • Well at least your `MCVE's` are getting better. Know if you could only include the code in a single class so we only need to copy/paste a single source file. You can easily embed the custom TableModel in the Tester source by using "static class". See the edit of my answer. – camickr Jan 22 '18 at 20:35
  • My IDE won't let me put 2 classes in the same file so it is harder to combine them here. Pasting copied code into this forum does not work well for me. I always have to manually edit it after the paste. – Wt Riker Jan 23 '18 at 18:26

1 Answers1

1

First of all class names should start with an upper case character. You have been given links to the Swing tutorials that provide demo code. I'm sure you have access to the Java API. The API and examples all follow the same convention. Learn by example and follow Java conventions!

The objective is to assure the user enters a numeric value or no value at all ("").

Just override the getColumnClass(...) method of the TableModel to return Double.class for the column and the JTable will use an appropriate editor and renderer.

A red border will be placed around the cell and you won't be able to save the data until you fix the problem.

Cannot format given Object as a Number

Edit:

Take the time to think about the change you just made. Take the time to read the error message. Your change just stated the column should contain Double data. So why are you adding an "empty" String in the first column. How can the renderer convert a String to a Double?

Again, if you read the code in the Java tutorials you will see how numeric data is add to the TableModel. I gave you a link to that tutorial long ago because it contains many basics.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • I said the data should contain numeric OR an empty string or no entry or whatever you want to call it. That is part of the question. How to do that and I thought your suggestion took that into account. I can't pass null as that blows up too. Nothing in the tutorials even mentioned that so they are useless in this case. As for upper case, that was a typo I just didn't correct it in the OP. My IDE warned me about that originally. – Wt Riker Jan 23 '18 at 13:33
  • `I said the data should contain numeric OR an empty string` - so then the question should be I know how to initialize a row with a number but I don't know how to do it with an empty string. Don't make us guess what your real problem is. `I can't pass null` - works fine for me. But once again you haven't posted an `MCVE` showing what you tried. ` My IDE warned me about that originally` - and once again you don't listen to advice given. Seems to be a common theme with all your questions. – camickr Jan 23 '18 at 15:49
  • `Nothing in the tutorials even mentioned that so they are useless in this case` - no they show how to add numeric data which is the first step. Then you ask a follow up question. Provide us will all the information you have discovered during your testing, not just a question that says "whats wrong". Make an effort!!! – camickr Jan 23 '18 at 15:51
  • You are becoming exasperating.The updated OP IS an MVCE. Did you even try it? As I also said in the OP the objective is to allow only numeric or an empty string in that cell. I don't know what you want from me. – Wt Riker Jan 23 '18 at 16:17
  • Actually, you are the frustrating person, I'm the one who is trying to help. You are the one that apparently doesn't listen to what I, (or the tutorial) says since it always needs to be repeated a second time. I would expect you pay attention, when people try to help??? I gave you credit for the MCVE (with suggestions on how it can even be better).. You then said is blows up when you pass null., Well, where is your MCVE that validates or demonstrates this statement??? Because yes I tested it, which is how I know it works when you specify a null for the numeric value. – camickr Jan 23 '18 at 17:20
  • OK, I'll accept that as I did not understand to what you were referring. I did not update `{"",""}` to `{null,null}` in the OP because I didn't think you would want to copy the whole thing again. I have updated it. So it works for you and not for me. Where do we go now? I'm running Windows 7 Home Premium SP1 with JDK 8.0.730.2 and JRE 8.0.1610.12 with Eclipse Oxygen.A1 as my IDE. – Wt Riker Jan 23 '18 at 18:25
  • `So it works for you and not for me.` - 1) My comments are about my suggestion, not your original approach. Why would you think I give an alternative approach, and then comment about the original code? 2) The error message is that you can't convert an Object to a Number. You only have one column that you want to be a Double, so why are both values null? Again, my comments directly relate to the stated problem. In a proper MCVE you would have a single column table with the Double so you don't get distracted with the other data. You have problems debugging because you can't simplify the problem. – camickr Jan 23 '18 at 18:34
  • Using my solution you would have a problem with (null, null) because of your implementation in the getColumnClass(...) method. You don't check if the data in the row contains null. – camickr Jan 23 '18 at 18:38
  • My update (implementing your suggestion) is what I thought we were talking about. The reason for using only the first column is to simplify the code. I added the 2nd column just to make it look like a real table and treat both the same input verify wise. Does it matter? In any case, if I add a check for a null entry, what should getColumnClass return, assuming that is where the exception occurs? – Wt Riker Jan 23 '18 at 18:55
  • Never mind. My IDE did an update which failed. There was a glitch somewhere so I needed to do a reinstall of some libraries to get over it. I suspect something became corrupt but it is working now. – Wt Riker Jan 23 '18 at 19:04