This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
I have built a table where the user can enter data in either column 1 or column 2. When the user is entering data in column 1, the values in column 2 are updated automatically. When the user is entering data in column 2, the data in column 1 is updated automatically. But I have a problem with the current behavior-
Let's say the user enters '5' in column 1 and I use setValueAt() to put the value of 5/3 in column 2. That displays as 1.67 based on the format I specified for the column. But then I switch and allow the user to enter a value in column 2 instead of column 1. If I click on that cell to change 1.67 to something else, it displays as 1.6666666666666666666, which looks bad and is a bit hard to select and change. How do I get just 1.67 to remain displayed when the user clicks in the cell to change the value?
I'd also like to limit the total of the values in column 2 to 100, which I think the custom renderer can handle, I'm just not sure how to signal the user the value is not valid. If the value is not a double, the cell gets a red border and I can't leave it. This is a default action which I want to keep and I'm not sure how to request that behavior myself.
The whole class is about 500 lines. So I will try to give enough code so you can see the relevant parts.
Thanks for the reply. I looked at the link. I don't see how it even addresses the problem. I have no problem adding rows. My problem is that when I dynamically add a double to a cell and the user then clicks in that cell, the behavior I would like to see vis-a-vis editing that number is not the default behavior. There are two parts to the cell: displaying and editing. I can extend the DefaultTableCellRenderer and specify a number format so that the display looks nice and I don't have to reimplement the entire CellRenderer. The CellEditor has a lot of nice behavior when I set the column class to Double.class. If the number is not a double, then the cell gets a red border and you can't edit any other cells until you fix it. I don't want to lose that behavior. But I don't like that I add the value 5/3 to a cell, see it displayed as 1.67 (based on the NumberFormat I give the cell renderer), but then the user clicks in the cell to change it and what is displayed is 1.66666666666666666 which looks pretty ugly. I was looking at Google hits on CellRenderer and got a bit overwhelmed and also dismayed that it looked like a whole project in itself to make the simplest change. So I was hoping someone could either explain to me more clearly than what I found searching Google exactly what I need to do or make my day and give me a simple recipe I could use.
Then how about actually storing in the cell what you want the user to see? Instead of trying to get the renderer and the editor to work together and show something else?
Joined: Oct 10, 2011
These are numbers that will be used in calculations. So I think it looks better to display 1.67, especially when the program is writing into the table, but when it comes time for the calculations, I can't afford to lose the precision. Rendering seems to be made to address the situation of keeping underlying precision, but providing a readable display. It's easy to extend the CellRenderer. But I didn't realize until I started putting the table together that the editor would display the data differently. It does make sense when the user enters all the data. I was hoping there would be a way not much harder than what is done for the CellRenderer to set the format for the CellEditor. All I could find looked like I would have to reimplement all the behaviors the default cell editor provides and make my own complete cell editor starting with an abstract cell editor. I know there is rendering, because the cell editor knows the column is a double and if the user enter 5, it is displayed as 5.0. I am trying to figure out if there is a way to just tell the default cell editor here is how I want you to format the number do everything else you are already doing.
Jon Swanson wrote:These are numbers that will be used in calculations. So I think it looks better to display 1.67, especially when the program is writing into the table, but when it comes time for the calculations, I can't afford to lose the precision.
Okay. So let's suppose you got your wish and the cell editor showed "1.67" to the user. Then the user might just click the Enter key, thereby changing the contents of the cell from its original 5/3 approximation to 1.67... thereby losing the precision without the user's knowledge. So I suggest that showing the user the actual contents of the cell while editing is actually a feature, and not the bug you think it is.
Joined: Oct 10, 2011
Well, if I could at least get the value highlighted and justified so when the user saw the value they saw the 1.666 part of the number and not the 66666 part I would be much happier. Which would also involve the rendering of the value. So if there were a simple way to change the way the number is rendered in the cell editor, I could still see an advantage. Not sure if the value actually changes if the user leaves the cell without hitting enter. If not, I'd still like my original idea.
First, the solution to your problem:
the following editor works for most cases for you:
1) retains the validation part of having a red border for invalid values
2) when the user clicks in the cell to edit, sets the caret position to 0 so that the user can see the beginning of the value
(you can't select all as well as have the position as 0 - I don't know if textfield allows editing also from right).
3) Also, display the value in the textfield as you had wanted to - I have not tested this well, so, I have commented this out in line no.11 - I am not sure how this works out for null or empty values - nf is the NumberFormat you used...
Wanted to make few more points on what you said:
1) I agree with Paul that this is actually a feature and not a bug.
2) The cell editor doesn't have any 'renderer' as you think. To the question of how value of 5 is displayed as '5.0' - this is done by just calling toString() on the object - in this case, your Double object. So, you will have to check the documentation of how toString is implemented for java.lang.Double.
3) The tab out red border can be found in the JTable source - JTable internally creates this editor, but this editor class is implemented as a package-private static inner class, so, we can't just re-use it... I took this code from there and only added a FocusListener...
4) The value changes when the user presses the 'enter' key or tabs out by pressing 'tab' key or clicks elsewhere with mouse. Only case where the value is retained is when the user presses 'esc' key - this works when the user enters an invalid entry and wants to retain the old value.
Joined: Oct 10, 2011
Thanks, that was helpful. I decided to fire up Excel and see what it did. With Excel, the width of the cell is expanded to accomodate the size of the number, a JTable cell does not expand. In Excel it is clear to the user what the number is. I can't of course "just store what I want the user to see." It's not even just a matter of numerical accuracy, floating point numbers do not have an exact representation, a column of Double.class cannot guarantee a number will be displayed with two digits, unless it is converted to a String. That of course, is what the cell renderer is for. If I used a String column, I'd have to reimplement the type checking that is done by default with a column of type double. It looks to me like the code that you supplied would help with that as well. Also, I think it might address my other question, which was how to prevent entry of a number which would make the sum of the column exceed a defined value.
BTW the first mention of the word 'bug' was by Paul. What I said was that if a number 1.666666666 is stored in a cell (displayed as 1.67) and the user clicks in the cell to edit it and sees 666667 that it would be confusing. I was hoping I could modify the way the cell editor rendered the number. Though I think now it is better simply to get the number left-justified. I was 'triple-clicking' which selects the number. That is when it right-justifies. Now I have something concrete, I can try getting some of the other behavior I am supposed to implement. So thanks again.