validation data in jtable - java

I have a JTable, and I want validate data in the first column. When the user type the entry in any cell in the first column and click in another cell (focus lost), I want show message that the entry is false, and focus again in the cell until the entry is valid.
First I thought that the cell is like the JTextFiled, so I have tried the method addFocusListener(...) but it doesn't work!
table.getValueAt(0, 0).addFocusListener(
new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
for (int n = 0; n <= table.getValueAt(0, 0).toString().length(); n++) {
if (Character.isDigit(table.getValueAt(0, 0).toString().charAt(n)) == false) {
JOptionPane.showMessageDialog(null,
"Error: code is a number !", "Error Message",
JOptionPane.ERROR_MESSAGE);
break;
} else
break;
}
}
}
}
});
creation of JTable:
String [][]data={ {"-","-","0","-"},
{"-","-","0","-"},
{"-","-","0","-"},
{"-","-","0","-"},
{"-","-","0","-"},
{"-","-","0","-"},
{"-","-","0","-"},
{"-","-","0","-"} };
String[] header = {"Code Projet", "Description", "Duree", "Taches anterieurs"};
table = new JTable(data, header);

The TableCellEditor that is added to a JTable will do any validation on the values that are entered into a JTable.
From the Java Table Tutorial:
The automatic checking of user-entered strings occurs when the default
editor attempts to create a new instance of the class associated with
the cell's column. The default editor creates this instance using a
constructor that takes a String as an argument. For example, in a
column whose cells have type Integer, when the user types in "123" the
default editor creates the corresponding Integer using code equivalent
to new Integer("123"). If the constructor throws an exception, the
cell's outline turns red and refuses to let focus move out of the
cell. If you implement a class used as a column data type, you can use
the default editor if your class supplies a constructor that takes a
single argument of type String.
So, if you want to just make sure the user enters in an Integer (which is what it looks like from your code), you can set the column type to a type of Integer .
table.setDefaultEditor(Integer.class,
new IntegerEditor(0, 100));
Now the DefaultCellEditor will do the checking for you, and throw an exception if the type is not correct. You will just have to make sure you catch the exception and deal with it properly.
I think tutorial I linked above on creating tables would be very helpful for you, especially the part I linked to which talks about validating user text.

Related

javafx choice box is empty on setValue()

In my project I have a table. When the user double clicks on the row, an editing dialog opens. On the opening this dialog I set values to fields, few of which are ChoiceBoxes. The type of ChoiceBox's field is a custom object, not a string.
The code that creates the ChoiceBox follows:
trade_point.setConverter(new TradePointConverter());
trade_point.setItems(FXCollections.observableArrayList(tradePointsService.getTradePoints()));
TradePoint currentTradePoint = tradePointsService.getTradePoint(typeOfPriceByTradePoint.getTradePoint());
trade_point.setValue(currentTradePoint);
Where trade_point is a choice box of TradePoint type. currentTradePoint is not null, when I look at trade_point's value equals currentTradePoint's value but in the dialog I see no value. Items are set correctly. in other case with same choice box filling everything is correct and here is not.
UPD: TradePointConverter class:
class TradePointConverter extends StringConverter<TradePoint>{
public TradePoint fromString(String name){
try {
List<TradePoint> tradePoints = tradePointsService.getTradePoints();
for (TradePoint tradePoint1: tradePoints){
if (tradePoint1.getName().equals(name)){
return tradePoint1;
}
}
}catch (SQLException e){
}
return null;
}
public String toString(TradePoint tradePoint1){
return tradePoint1.getName();
}
}
I am not sure if this converter is correct as far as converting from string by name is totally incorrect. I do not understand how to make it correctly visible to the user (to see the name of an object) and how to store its id to get the definite object at the same time. I can convert to string by getting an id but in this case user won't understand which object to choose.
trade_point is a ChoiceBox:
private ChoiceBox<TradePoint> trade_point = new ChoiceBox<TradePoint>();

Manipulate combobox using dictionary in java

I am consuming a web service which is returning me result of type "ArrayOfKeyValueOfintstring"
I am confused how to add this data to my combo box in java.
Here is my code
org.tempuri.ThirdPartyService service = new org.tempuri.ThirdPartyService();
org.tempuri.IThirdPartyService port = service.getBasicHttpBindingIThirdPartyService();
// TODO initialize WS operation arguments here
java.lang.String key = line.trim();
// TODO process result here
String>)port.getTests(key).getKeyValueOfintstring();
com.microsoft.schemas._2003._10.serialization.arrays.ArrayOfKeyValueOfintstring result = port.getVulnerabilities(key);
EDIT
for(int i=0;i<=result.getKeyValueOfintstring().size();i++)
{
result.getKeyValueOfintstring().get(i).getKey();
result.getKeyValueOfintstring().get(i).getValue();
JOptionPane.showMessageDialog(null, "key is"+result.getKeyValueOfintstring().get(i).getKey());
JOptionPane.showMessageDialog(null, "Value is"+result.getKeyValueOfintstring().get(i).getValue());
model.addElement(new Item(key, value));
}
I have tried to get the key pair in dialog box and i got it correctly. But now i am not getting how to add them to my ComboBox. I have created table "Vector model = new Vector();" and adding it to the combo box like this "cbTestName = new JComboBox(model);"
Is it the correct way or do i need to apply anything else to add the key value pair to my combo box.
If you'll go to declaration of
port.getTests(key).getKeyValueOfintstring(),
you'll probably find its implemented as
List<KeyValuePairOfintstring>
and KeyValuePairOfintstring is looks like
...
protected Integer key;
...
protected String value;
So one of the ways you can do - is run over port.getTests(key).getKeyValueOfintstring() in the loop, and build your map with your java business objects, you want to display in Combo Box.
You can override your object's toString method as a simplest way to control how will they look in the ComboBox.

ArrayIndexOutOfBoundsException when making recursive call to a JTable

I apologise in advance for the length of this post but I have provided a rather in depth description of the design and implementation of my program.
Background
I am currently doing a group (there are 2 of us) programming project for a third year computer science course at university.
The goal of this program is to essentially use a spreadsheet program to represent XML file data where each XML file is a historical record.
Design:
Each record(row) in the spreadsheet corresponds to a single XML file and the columns of the record correspond to the elements in the XML file. We deal with repeated elements (i.e. elements with the same tag) by setting the cell component to a button that, when clicked, opens up another spreadsheet which contains a list of all elements with repeated names (for the corresponding file). Child elements are dealt with in a similar manner whereby if an element ha child elements then the corresponding cell in the XML file contains a button which, when clicked, opens up a spreadsheet containing all the child elements of that element.
Implementation:
The implementation of our system is written in Java. Our main class (name SpreadSheetGUI) extends JFrame to which we add a JTable (using the default table model). We have three different cell renderers: one for when a cell just has text, one for when a cell has a button and one for when we have text and a button in a cell. When a button is clicked to open up a new spreadsheet (for either child elements or repeated element names) we make a recursive call to our spreadsheet constructor which will then create our sub-spreadsheet. The renderers are added in the following order: if the cell corresponds to an element with a tag that is used more than once a button is added to the cell, otherwise if the cell corresponds to an element with child nodes we add both text and a button to the cell and if the cell just has text we add the text to that cell.
The constructor for the GUI is as such
/**
* Parameterised constructor
* #param dataVector - Vector of vectors of objects that represent the cell values
* #param columnNames - The vector of objects that represent the column names
*/
#SuppressWarnings("unchecked")
public SpreadSheetGUI(Vector<Vector<LevelElementT>> dataVector, Vector<String> columnNames, boolean hasRepeatedColumns, boolean initialFrame)
{
this.hasRepeatedColumns = hasRepeatedColumns;
this.initialFrame = initialFrame;
if (initialFrame)
populateTable(dataVector, columnNames);
else if (!hasRepeatedColumns)
populateTable((Vector<Vector<LevelElementT>>)findRepeatedColumns(dataVector).get(0),
(Vector<String>)findRepeatedColumns(dataVector).get(1));
else
populateTable(dataVector, columnNames);
//Get repeated column names and add to repeated column hashmap
//parseElements(dataVector);
}
where the populateTable method initialises the table model.
And as I stated earlier we have three different renderers and editors for our cells and two
of the renderers have buttons in them that, when clicked, create a new spreadsheet (i.e. we make a call to our spreadsheet constructor), for example in our one cell editor has the following code
public Object getCellEditorValue()
{
if (isPushed)
{
//will have the child elements of the current cell element
Vector<Vector<LevelElementT>> children = new Vector<Vector<LevelElementT>>();
children.add(new Vector<LevelElementT>());
List<Element> tempChildren = elements.get(row).get(column).getChildren();
for (Element child : tempChildren)
children.get(0).add(new LevelElementT(child));
//creates our subspreadsheet
new Thread(new SpreadSheetGUI(children, new Vector<String>(), false, false)).start();
}
isPushed = false;
return new String(bLabel);
}
LevelElementT is just a class we made that extends Element (found in the JDOM2 package) that overrides the toString method.
The Problem:
As I mentioned before we have created a set of renderers to handle the adding of buttons to cells but it seems that when a "child" spreadsheet is created the renderers are trying to render cells that are out of bounds in accordance with the child spreadsheets number of rows and columns and throw an array index out of bounds exception.
More specifically the errors are thrown in the following piece of code taken from the populateTable() method. I initialises the JTable with an instance of the defaultTableModel and sets up the methods to determine the renderer of each component
table = new JTable(tableModel)
{
private static final long serialVersionUID = 1L;
public TableCellRenderer getCellRenderer(int row, int column)
{
//System.out.println(elements.get(row).get(column).getChildren().size());
if (column == 0)
{
Class<? extends Object> cellClass = getValueAt(row, column).getClass();
return getDefaultRenderer(cellClass);
}
else if(repeatedColumns.containsKey(table.getColumnModel().getColumn(column).getIdentifier() + " " + elements.get(row).get(0).getText()))
return getDefaultRenderer(JButton.class);
else if(!elements.get(row).get(column).getChildren().isEmpty())
return getDefaultRenderer(JPanel.class);
else
return getDefaultRenderer(JTextArea.class);
}
public TableCellEditor getCellEditor(int row, int column)
{
if (column == 0)
{
Class<? extends Object> cellClass = getValueAt(row, column).getClass();
return getDefaultEditor(cellClass);
}
else if(repeatedColumns.containsKey(table.getColumnModel().getColumn(column).getIdentifier() + " " + elements.get(row).get(0).getText()))
return getDefaultEditor(JButton.class);
else if(!elements.get(row).get(column).getChildren().isEmpty())
return getDefaultEditor(JPanel.class);
else
return getDefaultEditor(JTextArea.class);
}
};
The errors are thrown at the if statements (depending on the button you clicked) and it is definitely not because of elements (a two dimensional vector of levelElements) or repeatedColumns(a hashtable of with a string as the key and a vector of elements as the value).
I'm guessing the problem extends from the fact that we are making a recursive call to our spreadsheet constructor. A friend also suggested that this problem might be caused by the default table model, should I consider creating a custom table model?
I haven't included my code because it is rather lengthy (Around 2000 lines in total) but I am willing to give it on request. I have been wracking my brains with this one and I have been completely unsuccessful in finding any threads related to this problem.
Since no code is provided, I'm just guessing:
the recursive call can cause this if it does not return correctly. We don't know what you do exactly...
this phenomena can also be caused by accidentally passing the parent table's cells to the renderer, not the child one's.
I'd debug for these. But again, without code snippets, it is really hard to answer, I would say.
Hope that this helps. :)
new SpreadSheetGUI(children, new Vector<String>(), false, false) is suspect (guess only) as afterwards the new Vector is not accessible normally.
There is no provision with .get(row).get(column) for index checks. Especially whether every row has sufficient strings.
The DefaultTableModel is sufficient.
Vector, though thread safe, is quite old; makes a better impression to use List / ArrayList, with concurrency: CopyOnWriteArrayList.
There already exist XML table models and tree table models. I do not know about your requirements with respect to programming.
A stack trace, break points, debugging, IDE, should have helped. NetBeans IDE is easy, eclipse IDE more wide spread.

CheckboxCellEditor shows text and not a check box

I'm using the following
org.eclipse.jface.viewers.CheckboxCellEditor.CheckboxCellEditor(Composite parent)
I'm creating a table viewer with cellEditors and doing the following
CellEditor[] editors = new CellEditor[columnNames.length];
editors[7] = new CheckboxCellEditor(table);
I have a CellModifier that has the following
public Object getValue(Object element, String property) {
Object result = null;
...
result = Boolean.valueOf(task.isDfRequested());
return result;
}
public void modify(Object element, String property, Object value) {
item.isSelected(((Boolean)value).booleanValue());
}
Finally I have a LabelProvider that has the following
public String getColumnText(Object element, int columnIndex) {
String result = "";
try {
result = Boolean.toString(item.isSelected());
} catch (Exception ex) { }
break;
However, in my UI instead of having a check box I have the word true or false && clicking it results in switching state to false or true. Any ideas on why I don't have a checkbox??
I've searched in the source code of CheckboxCellEditor class and in the constructor the control associated to the CellEditor is created in the createControl(Composite parent) method. This method is abstract in CellEditor class and it's implemented like this in CheckboxCellEditor:
protected Control createControl(Composite parent) {
return null;
}
So a control is not created, that's why you don't see the checkbox. In the documentation of the Class you can read:
Note that this implementation simply
fakes it and does does not create any
new controls. The mere activation of
this editor means that the value of
the check box is being toggled by the
end users; the listener method
applyEditorValue is immediately called
to signal the change.
I solved this using a ComboBoxCellEditor with yes and no items.
Regards.
Well, I have no idea how SWT works or what component you are even talking about.
But I do know that when using Swing you can have custom editors for a column in a JTable. If you don't tell the table the class of data for the column then the toString() method of the data is invoked. But if you tell the table that Boolean data is displayed in the column then the table will use the check box editor.
Sounds like a similiar symptom, but I don't know your particular solution.
What I've decided to do is to just implement a dirty hack others have been using.
Create two images of check boxes, one checked the other not checked. Switch the state between the two based on the boolean.
It's not perfect, but for now it gets the job done

Can a Jtable save data whenever a cell loses focus?

The high level: I have a JTable that the user can use to edit data.
Whenever the user presses Enter or Tab to finish editing, the data is saved (I'm asusming that "saved" really means "the TableModel's setValueAt() method is called".)
If the user leaves the cell in any other way after making an edit, the new data is not saved and the value stays the way it was. So, for example, if the user changes a value and then clicks on some other widget on the screen, the change doesn't "stick."
I believe that this is the default behavior for a JTable full of Strings, yes?
For a variety of reasons, the desired behavior is for the cell to save any and all edits whenever the user leaves the cell. What's the best/right way to get Swing to do this?
Table Stop Editing explains whats happening and gives a couple simple solutions.
One of the simple solutions proposed
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
is good only for String columns. The problem is if I have, for example, Float type of the column being edited, enter an empty string in corresponding cell and then click on any other control of the window – Java throws NullPointerException in CellEditorRemover.propertyChange() method of JTable.java. It uses getCellEditor() call to stop or cancel editing but it returns null in this case. If the value entered is not empty or if I remove terminateEditOnFocusLost flag everything is fine. Probably, the situation described is a bug.
I hope I can provide a solution based on one of the previous posts. It’s not so trivial as I supposed before but seems to me it works.
I had to inherit my own cell editor from default cell editor and my own text field from JTextField which has FocusListener. This focus listener works fine when editing cell loses a focus, and a focus gained by another control of the window. But in the case of cell selection changes focus listener is “deaf”. That’s why I also have to remember previously valid value before editing start to restore it if the entered value will be invalid.
See the code below. Tested with Double, Float and Integer, but I hope this will also work with Byte and String.
Text field with focus listener:
public class TextFieldCell extends JTextField {
public TextFieldCell(JTable cellTable) {
super(); // calling parent constructor
final JTable table = cellTable; // this one is required to get cell editor and stop editing
this.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
// this function successfully provides cell editing stop
// on cell losts focus (but another cell doesn't gain focus)
public void focusLost(FocusEvent e) {
CellEditor cellEditor = table.getCellEditor();
if (cellEditor != null)
if (cellEditor.getCellEditorValue() != null)
cellEditor.stopCellEditing();
else
cellEditor.cancelCellEditing();
}
});
}
}
Default cell editor class:
class TextFieldCellEditor extends DefaultCellEditor {
TextFieldCell textField; // an instance of edit field
Class<?> columnClass; // specifies cell type class
Object valueObject; // for storing correct value before editing
public TextFieldCellEditor(TextFieldCell tf, Class<?> cc) {
super(tf);
textField = tf;
columnClass = cc;
valueObject = null;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
TextFieldCell tf = (TextFieldCell)super.getTableCellEditorComponent(table, value, isSelected, row, column);
if (value != null) {
tf.setText(value.toString());
}
// we have to save current value to restore it on another cell selection
// if edited value couldn't be parsed to this cell's type
valueObject = value;
return tf;
}
#Override
public Object getCellEditorValue() {
try {
// converting edited value to specified cell's type
if (columnClass.equals(Double.class))
return Double.parseDouble(textField.getText());
else if (columnClass.equals(Float.class))
return Float.parseFloat(textField.getText());
else if (columnClass.equals(Integer.class))
return Integer.parseInt(textField.getText());
else if (columnClass.equals(Byte.class))
return Byte.parseByte(textField.getText());
else if (columnClass.equals(String.class))
return textField.getText();
}
catch (NumberFormatException ex) {
}
// this handles restoring cell's value on jumping to another cell
if (valueObject != null) {
if (valueObject instanceof Double)
return ((Double)valueObject).doubleValue();
else if (valueObject instanceof Float)
return ((Float)valueObject).floatValue();
else if (valueObject instanceof Integer)
return ((Integer)valueObject).intValue();
else if (valueObject instanceof Byte)
return ((Byte)valueObject).byteValue();
else if (valueObject instanceof String)
return (String)valueObject;
}
return null;
}
It the code of table initialization you have to add the following:
myTable.setDefaultEditor(Float.class, new TextFieldCellEditor(new TextFieldCell(myTable), Float.class));
myTable.setDefaultEditor(Double.class, new TextFieldCellEditor(new TextFieldCell(myTable), Double.class));
myTable.setDefaultEditor(Integer.class, new TextFieldCellEditor(new TextFieldCell(myTable), Integer.class));
Hope, this will help somebody who have the same problem.
You need to add a focus listener. Given that JTable is basically a container of its cell components, you actually want the focus listener for every cell in your table that needs to behave in the way you indicated.
To do this, you will need to create custom cell editor, which wraps the cell component that has a registered focus listener. And when you get the callback for the loss of focus event, you do the data save, as you require.
This pretty much details most of what you need to do. The details of implementing the focus listener is not there, but that is fairly straightforward.
Lets say you do use a JTextComponent as your cell component. Then:
public void focusLost(FocusEvent e) {
JTextComponent cell = (JTextComponent) e.getSource();
String data = cell.getText();
// TODO: save the data for this cell
}
[p.s. edit]:
The thread that is calling you with this event is the dispatch thread. Do NOT use it for actions with high latency. But if you are just flipping bits in the heap, it should be ok.

Categories

Resources