I am a French guy and not new to Java.
In French, Doubles have "," separator rather than ".". So I have a JTable Cell with column class = Double, when I enter e.g 2.4 it is Ok. But when I enter 2,4 it blocks.
I used Locale.setDefault(Locale.FRENCH); but I have the same result :
Number
And as you can see in the image below, my application started with French locale :
System Locale
Is there any way to enter 2,4 rather than 2.4 ?
Sincerely.
Is there any way to enter 2,4 rather than 2.4 ?
Well there are several issues.
the default renderer will display the "." not the ",".
the default editor will display the ".", not the ","
the default editor doesn't recognize the "," as a valid character for a Double when you attempt to save the value to the TableModel
When you leave a cell the entered String must be converted to a Double. However, the Double.parseDouble(...) method does not recognize the "," even when the French Locale is used.
The default cell editor realizes the String can't be converted properly so the cell is highlighted with the red border to indicate an invalid value.
The solution below uses a custom editor to internally handle the conversion of the "," to "." before the String is parsed as a Double. It will also convert the "." to a "," so the value is displayed properly in the editor.
import java.awt.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class LocaleEditor extends DefaultCellEditor
{
private Object value;
public LocaleEditor()
{
super( new JTextField() );
((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
}
#Override
public Object getCellEditorValue()
{
return value;
}
#Override
public boolean stopCellEditing()
{
try
{
String editingValue = (String)super.getCellEditorValue();
// Don't allow user to enter "."
if (editingValue.contains("."))
{
JTextField textField = (JTextField)getComponent();
textField.setBorder(new LineBorder(Color.red));
return false;
}
// Replace local specific character
int offset = editingValue.lastIndexOf(",");
if (offset != -1)
{
StringBuilder sb = new StringBuilder(editingValue);
sb.setCharAt(offset, '.');
editingValue = sb.toString();
}
value = Double.parseDouble( editingValue );
}
catch(NumberFormatException exception)
{
JTextField textField = (JTextField)getComponent();
textField.setBorder(new LineBorder(Color.red));
return false;
}
return super.stopCellEditing();
}
#Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{
Component c = super.getTableCellEditorComponent(table, value, isSelected, row, column);
JTextField textField = (JTextField)c;
textField.setBorder( new LineBorder(Color.BLACK) );
String text = textField.getText();
int offset = text.lastIndexOf(".");
// Display local specific character
if (offset != -1)
{
StringBuilder sb = new StringBuilder(text);
sb.setCharAt(offset, ',');
textField.setText( sb.toString() );
}
return c;
}
private static void createAndShowUI()
{
String[] columnNames = {"String", "Double", "Boolean"};
Object[][] data =
{
{"A", new Double(1), Boolean.TRUE },
{"B", new Double(2.25), Boolean.FALSE},
{"C", new Double(12.34), Boolean.TRUE },
{"D", new Double(1234.56), Boolean.FALSE}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames)
{
// Returning the Class of each column will allow different
// renderers and editors to be used based on Class
public Class getColumnClass(int column)
{
for (int row = 0; row < getRowCount(); row++)
{
Object o = getValueAt(row, column);
if (o != null)
return o.getClass();
}
return Object.class;
}
};
JTable table = new JTable(model);
table.setRowHeight(20);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
// Use a custom renderer and editor
NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
nf.setMinimumFractionDigits(2);
TableCellRenderer renderer = new NumberRenderer( nf );
table.setDefaultRenderer(Double.class, renderer);
TableCellEditor fce = new LocaleEditor();
table.setDefaultEditor(Double.class, fce);
JFrame frame = new JFrame("Table Five Character Editor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( scrollPane );
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
The above code also uses code found in Table Format Renderers, which allows you to easily create a custom renderer for a given Locale. Just comment out the code if you don't want to use the renderer, but then the "." will be displayed in the table.
I recommend you to implement a custom data model using AbstractTableModel, then inside the method getValueAt(int row, int col) use NumberFormat as follows:
NumberFormat.getInstance(Locale.FRENCH).format(2.4);
If your application is only going to be used by French users, you can hardcode the default locale to French.
Locale.setDefault( Locale.FRENCH );
Alternatively, as a workaround, just set all columns to String (thus, all input will be accepted), and in DefaultTableModel->TableModelListener->tableChanged() format your String as you wish and parse it to Double afterwards with setValueAt().
Related
when I Run the project the table rows are displayed correctly except the rank stars the show outside the table and inside the colonne a text appears as displayed in the image :
public ListTasksForm(Form previous) {
SpanLabel sp = new SpanLabel();
sp.setText(ServiceTask.getInstance().getAllArticles().toString());
ArrayList<Articles> articles = ServiceTask.getInstance().getAllArticles();
Object[][] rows = new Object[articles.size()][];
for (int iter = 0; iter < rows.length; iter++) {
rows[iter] = new Object[]{
articles.get(iter).getName(), articles.get(iter).getDescription(), articles.get(iter).getLabel(), articles.get(iter).getQuantity(),
articles.get(iter).getRating(), add(createStarRankSlider(articles.get(iter).getId_article()))
};
}
TableModel model = new DefaultTableModel(new String[]{"name", "description", "label", "quantity", "rating", "rate"}, rows);
Table table = new Table(model);
add(table);
getToolbar().addMaterialCommandToLeftBar("", FontImage.MATERIAL_ARROW_BACK, e -> previous.showBack());
}
});
and this is the function for the star rank creation
private Slider createStarRankSlider(int id) {
Slider starRank = new Slider();
starRank.setEditable(true);
starRank.setMinValue(0);
starRank.setMaxValue(10);
int fontSize = Display.getInstance().convertToPixels(3);
Font fnt = Font.createTrueTypeFont("Handlee", "Handlee-Regular.ttf").
derive(fontSize, Font.STYLE_PLAIN);
Style s = new Style(0xffff33, 0, fnt, (byte) 0);
Image fullStar = FontImage.createMaterial(FontImage.MATERIAL_STAR, s).toImage();
s.setOpacity(100);
s.setFgColor(0);
Image emptyStar = FontImage.createMaterial(FontImage.MATERIAL_STAR, s).toImage();
initStarRankStyle(starRank.getSliderEmptySelectedStyle(), emptyStar);
initStarRankStyle(starRank.getSliderEmptyUnselectedStyle(), emptyStar);
initStarRankStyle(starRank.getSliderFullSelectedStyle(), fullStar);
initStarRankStyle(starRank.getSliderFullUnselectedStyle(), fullStar);
starRank.setPreferredSize(new Dimension(fullStar.getWidth() * 5, fullStar.getHeight()));
starRank.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
ServiceTask.getInstance().UpdateRank(id,starRank.getIncrements());
}
});
return starRank;
}
You didn't include the code for the initStarRankStyle but it's pretty obvious what you did here. You just relied on the behavior of the container. Table derives Container so it includes all of its methods e.g. add(Component).
But these methods won't work correctly since a table fetches its data from the model and invokes add internally. So you're logic is conflicting with the table.
You need to derive table and define how you want that data to be rendered. You can do that by overriding the method protected Component createCell(Object value, int row, int column, boolean editable) as explained here.
I appreciate everyone stopping by to look at my question.
I am attempting to use the selection of a combo box that's within a JTable cell to dynamically select a combo box for the cell that is adjacent, in the next column. I have done quite a lot of reading and experimenting thus far, and have found that the answer most likely lies within overriding the DefaultCellEditor for said cells, but I have not found an example of this that makes sense in my case. Also, it seems as though it may be possible to manipulate the way JTables are handled, so that the configuration is primarily row-based. Again, I cannot interpret examples in such a way that makes sense to me or my application.
The app that I'm building allows a user to input a number of data tags that he or she prefers to work with, and then populates a three-columned JTable with as many rows as the data tag input. I do some XML parsing ahead of time and find a few values that are useful to my final goal but ultimately do not affect the creation and formatting of the JTable.
I build a set of combo boxes that correspond with specific data types within my XML file. The combo boxes have been tested on a different jPanel in my app, but they do not populate in the third column of my JTable when a value is selected in the corresponding cell in the second column. It also seems as though this functionality will require a Listener to interpret mouse interactions with the primary combo boxes, so that the code for creating the secondary (third-column) combo boxes only executes on a row-by-row basis. Is this correct, and if so: what means must I take to interpret and handle the mouse edits of the combo boxes?
My code and a screenshot of the app to follow:
This is the user-input form for my GUI. "Number of Tags" sets row count
package adduimdevsswing;
import java.lang.String;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import javax.xml.transform.OutputKeys;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class NewJFrame extends javax.swing.JFrame {
String testString = "";
String txt = "";
String ResultString1 = "";
String ResultString2 = "";
String[] ResultStringArray;
String[] DataTypes = {"Counter","Counter32","Counter64","INTEGER","Integer32",
"Unsigned32","Gauge","Gauge32","DisplayString","TruthValue","TimeTicks"};
int ElemLength = 0;
int NumOfVariables = 0;
String[] VariableUnitNames;
String[] TextFieldValues;
String[] ComboBoxValues;
JTextField[] TextFields;
int NumberOfTags = 0;
JPanel AddTagsPanel = new JPanel();
DefaultTableModel TableModel;
TableColumn DataTypeColumn;
JComboBox ComboBox = new JComboBox(DataTypes);
NodeList varGroup;
NodeList varName;
NodeList varDataType;
Node Node1;
Element Element1;
JComboBox CounterCombo;
JComboBox Counter32Combo;
JComboBox Counter64Combo;
JComboBox INTEGERCombo;
JComboBox Integer32Combo;
JComboBox Unsigned32Combo;
JComboBox GaugeCombo;
JComboBox Gauge32Combo;
JComboBox DisplayStringCombo;
JComboBox TruthValueCombo;
JComboBox TimeTicksCombo;
public NewJFrame()
{
initComponents();
jTable1.getColumnModel().getColumn(0).setHeaderValue("Tag Name"); //set first column to be "Tag Name" column
jTable1.getColumnModel().getColumn(1).setHeaderValue("Data Type"); //set second column to be "Data Type" column
jTable1.getColumnModel().getColumn(2).setHeaderValue("Tag Units"); //set third column to be "Tag Units" column
jTable1.setVisible(false); //aesthetically set jTable1 to not be visible until configured by user input
try
{
File MIBFILE = new File("/opt/ecoMeterMIB.xml"); //select the text MIB file to work with
/*create instance of documentBuilder*/
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(MIBFILE);
/*Find the latest instance of nmsElemTag within ecoMeterMIB.xml by checking the "length" (highest count) of nmsElemTag*/
ElemLength = doc.getElementsByTagName("nmsElemTag").getLength();
NumOfVariables = doc.getElementsByTagName("variableGroup").getLength();
varGroup = doc.getElementsByTagName("variableGroup");
jTextField3.setText(Integer.toString(NumOfVariables)); //display number of variables (nmsElemTag length)
String[] varNameStr = new String[NumOfVariables];
/*Define lists to be used as constructors for comboBoxes - Done here to be accessible elsewhere*/
String[] varDataTypeStr = new String[NumOfVariables];
List CounterType = new List();
List Counter32Type = new List();
List Counter64Type = new List();
List INTEGERType = new List();
List Integer32Type = new List();
List Unsigned32Type = new List();
List GaugeType = new List();
List Gauge32Type = new List();
List DisplayStringType = new List();
List TruthValueType = new List();
List TimeTicksType = new List();
/*Parse XML to find/sort all elements by name & data type*/
for(int a=0;a<NumOfVariables;a++)
{
Element1 = (Element) varGroup.item(a);
varName = Element1.getElementsByTagName("name");
varDataType = Element1.getElementsByTagName("dataType");
varNameStr[a] = varName.item(0).getTextContent();
varDataTypeStr[a] = varDataType.item(0).getTextContent();
switch (varDataTypeStr[a])
{
case "Counter":
CounterType.add(varNameStr[a]); //If dataType is "Counter", Add to Counter Type List
break;
case "Counter32":
Counter32Type.add(varNameStr[a]); //If dataType is "Counter32", Add to Counte32r Type List
break;
case "Counter64":
Counter64Type.add(varNameStr[a]); //If dataType is "Counter64", Add to Counter64 Type List
break;
case "INTEGER":
INTEGERType.add(varNameStr[a]); //If dataType is "INTEGER", Add to INTEGER Type List
break;
case "Integer32":
Integer32Type.add(varNameStr[a]); //If dataType is "Integer32", Add to Integer32 Type List
break;
case "Unsigned32":
Unsigned32Type.add(varNameStr[a]); //If dataType is "Unsigned32", Add to Unsigned32 Type List
break;
case "Gauge":
GaugeType.add(varNameStr[a]); //If dataType is "Gauge", Add to Gauge Type List
break;
case "Gauge32":
Gauge32Type.add(varNameStr[a]); //If dataType is "Gauge32", Add to Gauge32 Type List
break;
case "DisplayString":
DisplayStringType.add(varNameStr[a]); //If dataType is "DisplayString", Add to DisplayString Type List
break;
case "TruthValue":
TruthValueType.add(varNameStr[a]); //If dataType is "TruthValue", Add to TruthValue Type List
break;
case "TimeTicks":
TimeTicksType.add(varNameStr[a]); //If dataType is "TimeTicks", Add to TimeTicks Type List
break;
default:
break;
}
}
/*Create comboBoxes and populate them with the items from above corresponding lists*/
CounterCombo = new JComboBox(CounterType.getItems());
Counter32Combo = new JComboBox(Counter32Type.getItems());
Counter64Combo = new JComboBox(Counter64Type.getItems());
INTEGERCombo = new JComboBox(INTEGERType.getItems());
Integer32Combo = new JComboBox(Integer32Type.getItems());
Unsigned32Combo = new JComboBox(Unsigned32Type.getItems());
GaugeCombo = new JComboBox(GaugeType.getItems());
Gauge32Combo = new JComboBox(Gauge32Type.getItems());
DisplayStringCombo = new JComboBox(DisplayStringType.getItems());
TruthValueCombo = new JComboBox(TruthValueType.getItems());
TimeTicksCombo = new JComboBox(TimeTicksType.getItems());
}
catch(Exception e)
{
System.out.println(e);
}
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
/*Update button and tooltip text for reuse of form*/
jButton2.setText("Re-Create Form"); //Set Button Text to "Re-Create Form"
jButton2.setToolTipText("Click to Rebuild the Form for a New Number of Tags."); //Set Tooltip Text
NumberOfTags = Integer.parseUnsignedInt(jTextField1.getText()); //Set Number Of tags for new device to user's input
TableModel = new DefaultTableModel(NumberOfTags,3); //Create a table model with # of tags from input and three columns
jTable1.setModel(TableModel); //set jTable1 in GUI Designer to be rebuilt based on TableModel
jTable1.getColumnModel().getColumn(0).setHeaderValue("Tag Name"); //set first column to be "Tag Name" column
jTable1.getColumnModel().getColumn(1).setHeaderValue("Data Type"); //set second column to be "Data Type" column
jTable1.getColumnModel().getColumn(2).setHeaderValue("Tag Units"); //set third column to be "Tag Units" column
jTable1.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(ComboBox)); //second column's default editor is dataTypes comboBox
jTable1.setVisible(true); //Table is visible
jTable1.setFocusable(true); //Table can take focus
jComboBox1.setModel(INTEGERCombo.getModel()); //debugging to confirm comboBox objects receive appropriate values (device info tab of UI)
switch(jTable1.getCellEditor(jTable1.getSelectedRow(), 1).getCellEditorValue().toString())
{
case "Counter":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(CounterCombo));
break; //^if dataType is Counter, set cell editor to CounterCombo tag units combo box
case "Counter32":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(Counter32Combo));
break; //^if dataType is Counter32, set cell editor to Counter32Combo tag units combo box
case "Counter64":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(Counter64Combo));
break; //^if dataType is Counter64, set cell editor to Counter64Combo tag units combo box
case "INTEGER":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(INTEGERCombo));
break; //^if dataType is INTEGER, set cell editor to INTEGERCombo tag units combo box
case "Integer32":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(Integer32Combo));
break; //^if dataType is Integer32, set cell editor to Integer32Combo tag units combo box
case "Unsigned32":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(Unsigned32Combo));
break; //^if dataType is Unsigned32, set cell editor to Unsigned32Combo tag units combo box
case "Gauge":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(GaugeCombo));
break; //^if dataType is Gauge, set cell editor to GaugeCombo tag units combo box
case "Gauge32":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(Gauge32Combo));
break; //^if dataType is Gauge32, set cell editor to Gauge32Combo tag units combo box
case "DisplayString":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(DisplayStringCombo));
break; //^if dataType is DisplayString, set cell editor to DisplayStringCombo tag units combo box
case "TruthValue":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(TruthValueCombo));
break; //^if dataType is TruthValue, set cell editor to TruthValueCombo tag units combo box
case "TimeTicks":
jTable1.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(TimeTicksCombo));
break; //^if dataType is TimeTicks, set cell editor to TimeTicksCombo tag units combo box
default:
break;
}
You can dynamically change the items in the combo box by overriding the getCellEditor(...) method of the JTable.
The example below just changes the items based on the row:
import java.awt.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableComboBoxByRow extends JPanel
{
List<String[]> editorData = new ArrayList<String[]>(3);
public TableComboBoxByRow()
{
setLayout( new BorderLayout() );
// Create the editorData to be used for each row
editorData.add( new String[]{ "Red", "Blue", "Green" } );
editorData.add( new String[]{ "Circle", "Square", "Triangle" } );
editorData.add( new String[]{ "Apple", "Orange", "Banana" } );
// Create the table with default data
Object[][] data =
{
{"Color", "Red"},
{"Shape", "Square"},
{"Fruit", "Banana"},
{"Plain", "Text"}
};
String[] columnNames = {"Type","Value"};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
JTable table = new JTable(model)
{
// Determine editor to be used by row
public TableCellEditor getCellEditor(int row, int column)
{
int modelColumn = convertColumnIndexToModel( column );
if (modelColumn == 1 && row < 3)
{
JComboBox<String> comboBox1 = new JComboBox<String>( editorData.get(row));
return new DefaultCellEditor( comboBox1 );
}
else
return super.getCellEditor(row, column);
}
};
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
// table.getColumnModel().getColumn(1).setCellRenderer(new ComboBoxRenderer2() );
}
/*
class ComboBoxRenderer2 extends DefaultTableCellRenderer
{
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
label.setIcon(UIManager.getIcon("Table.descendingSortIcon"));
return label;
}
}
*/
private static void createAndShowUI()
{
JFrame frame = new JFrame("Table Combo Box by Row");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TableComboBoxByRow() );
frame.setSize(200, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
In your case the editor would be changed based on the data in the previous column, but the concept would be the same.
I'm subclassing JTable and using a DefaultTableModel to model my table data. The following class sets up the JTable, and adds one row to the model.
import java.io.File;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class SelectedFileTable extends JTable {
Vector<File> SelectedFiles = new Vector<File>();
DefaultTableModel Model = new DefaultTableModel();
TableColumn ColumnName = new TableColumn();
TableColumn ColumnSize = new TableColumn();
TableColumn ColumnRmIcon = new TableColumn();
ImageFilenameFilter Filter = new ImageFilenameFilter();
public SelectedFileTable() {
super();
this.setModel(Model);
ColumnName.setHeaderValue(new String("Name") );
ColumnName.setMinWidth(200);
ColumnSize.setHeaderValue(new String("Size") );
ColumnSize.setMinWidth(50);
ColumnSize.setMaxWidth(100);
ColumnRmIcon.setHeaderValue(new String("Remove?") );
ColumnRmIcon.setMaxWidth(100);
ColumnRmIcon.setResizable(false);
this.addColumn(ColumnName);
this.addColumn(ColumnSize);
this.addColumn(ColumnRmIcon);
this.setShowVerticalLines(false);
this.setShowHorizontalLines(true);
this.setAutoCreateColumnsFromModel(true);
this.addFile( new File("C:/temp/cfk.jpg") );
}
public void addFile(File file) {
System.out.println("FileTable adding: " + file.getName() );
if ( file.isDirectory() ) {
for ( File f : file.listFiles(Filter) ) {
this.addFile(f);
}
} else {
if ( Filter.accept(file) ) {
System.out.println("Accepting file; " + file.getName() );
SelectedFiles.add(file);
{
String name = file.getName();
Long size = new Long( file.length() );
String tempstr = new String("X");
System.out.println("RowItems before: " + Integer.toString(Model.getRowCount()) );
Model.addRow( new Object[] { name, size, tempstr } );
Model.fireTableDataChanged();
System.out.println("RowItems start : " + Integer.toString(Model.getRowCount()) );
}
System.out.println("Done Accepting file; " + file.getName() );
}
}
}
public Iterator<File> iterator() {
return SelectedFiles.iterator();
}
}
At display/visualization time, the following exception is thrown:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0
at java.util.Vector.elementAt(Vector.java:432)
at javax.swing.table.DefaultTableModel.getValueAt(DefaultTableModel.java:622)
at javax.swing.JTable.getValueAt(JTable.java:1903)
at javax.swing.JTable.prepareRenderer(JTable.java:3911)
at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2072)
at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:1974)
at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1897)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:142)
at javax.swing.JComponent.paintComponent(JComponent.java:743)
at javax.swing.JComponent.paint(JComponent.java:1006)
at javax.swing.JComponent.paintChildren(JComponent.java:843)
at javax.swing.JComponent.paint(JComponent.java:1015)
at javax.swing.JViewport.paint(JViewport.java:728)
at javax.swing.JComponent.paintChildren(JComponent.java:843)
at javax.swing.JComponent.paint(JComponent.java:1015)
at javax.swing.JComponent.paintChildren(JComponent.java:843)
at javax.swing.JComponent.paint(JComponent.java:1015)
at javax.swing.JComponent.paintChildren(JComponent.java:843)
at javax.swing.JComponent.paint(JComponent.java:1015)
at javax.swing.JComponent.paintChildren(JComponent.java:843)
at javax.swing.JComponent.paint(JComponent.java:1015)
at javax.swing.JComponent.paintChildren(JComponent.java:843)
at javax.swing.JComponent.paint(JComponent.java:1015)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:559)
at javax.swing.JComponent.paintChildren(JComponent.java:843)
at javax.swing.JComponent.paintWithOffscreenBuffer(JComponent.java:4979)
at javax.swing.JComponent.paintDoubleBuffered(JComponent.java:4925)
at javax.swing.JComponent.paint(JComponent.java:996)
at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:21)
at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:60)
at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:97)
at java.awt.Container.paint(Container.java:1709)
at sun.awt.RepaintArea.paintComponent(RepaintArea.java:248)
at sun.awt.RepaintArea.paint(RepaintArea.java:224)
at sun.awt.windows.WComponentPeer.handleEvent(WComponentPeer.java:254)
at java.awt.Component.dispatchEventImpl(Component.java:4060)
at java.awt.Container.dispatchEventImpl(Container.java:2024)
at java.awt.Window.dispatchEventImpl(Window.java:1791)
at java.awt.Component.dispatchEvent(Component.java:3819)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
I'm ripping my hair out - I haven't been able to find the root cause of this immensely simple use case.
I ran on this issue too (with a JList and a DefaultListModel).
Dmitry's answer is right.
However, there is another thing:
this exception can also be thrown if you don't modify the model in Swing's Event Dispatch Thread.
Doing the following can help you avoid this exception:
SwingUtilities.invokeLater(new Runnable(){public void run(){
//Update the model here
}});
http://www.javakb.com/Uwe/Forum.aspx/java-gui/3012/JList-JScrollPane-DefaultListModel-Updating
I think you need to add columns to your TableModel. Your code adds UI columns to the table but doesn't add them to the model
Dmitry is right. Replace
this.addColumn(ColumnName);
this.addColumn(ColumnSize);
this.addColumn(ColumnRmIcon);
with
Model.addColumn(ColumnName);
Model.addColumn(ColumnSize);
Model.addColumn(ColumnRmIcon);
and now the Model knows about the columsn and won't throw an Exception anymore when you try to add a row to a model which thinks it has 0 columns
From the JTable.setAutoCreateColumnsFromModel() API:
"This method calls createDefaultColumnsFromModel if autoCreateColumnsFromModel changes from false to true. "
Vector throws ArrayIndexOutOfBoundsException - if the index is out of range ( index < 0 || index >= size())
I guess the table model is missing the columns, as suggested by Dmitry
Replace your code with the following
Here you need to remove first row only that should be iterated for all the rows
private void refreshTable() {
int rowCount= model.getRowCount();
// System.out.println(rowCount);
for(int i=0;i<rowCount;i++ ){
model.removeRow(0);
//System.out.println(i);
}
}
replace
tabWindow.addTab(...);
with
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
tabWindow.addTab(...);
}
});
Such situation can hapen when you change tabbed pane in action listener.
Another issue might be related when you use RowSorter. When you edit the model RowSorter tries to re-sort the old model. It should be automatically re-created and re-run on each changes of table model.
You can fix it by
tableModel = new DefaultTableModel(data, columnNames);
jTableSentence.setModel(tableModel);
jTableSentence.setRowSorter(new TableRowSorter(tableModel));
jTableSentence.setAutoCreateRowSorter(true);
-Hayri
I was facing this problem because i was adding columns and rows to the JTable not to the model.
best way is this.
Object[][]rows = new Object[ ][ ] { {"a","b"} , {"c","d"} };
Object[]columns = new Object[] {"column1","column2"};
JTable table = new JTable();
table.setModel(new DefaultTableModel(rows,columns));
Dmitry is right, but you simply have to update your model.
To do this, add the following to your code:
DefaultTableModel dtm = (DefaultTableModel) table.getModel();
for (int c = 0; c < table.getColumnCount(); c++) {
dtm.addColumn(table.getColumnName(c));
}
It is necessary to add isCellEditable method to your table model class with return false.
#Override
public boolean isCellEditable(int row, int column)
{
return false;
}
I have a Requirement where I got a JTable Column defaulting with certain data on Load.
Now , I need a combobox on the same Column with that default value already selected in the combobox of that column in the Table +few other options to select or change the value of the cell of that column.
Here is the Sample Code:
public class Test extends JFrame {
public void init() {
JTable table = new JTable( new Object[][] { { "Paul J" , "20" }, { "Jerry M" , "30" }, { "Simon K" , "25" } },
new String[] { "Name" , "Age" } );
table.getColumnModel().getColumn(1).setCellEditor( new SampleCellEditor() );
getContentPane().add( new JScrollPane( table ));
setSize( 400, 200 );
setVisible(true);
}
// Sample Editor to Show Combobox with all sample values in that column
// also can edit the value to add new Value that is not in the column
public static class SampleCellEditor extends DefaultCellEditor {
public SampleCellEditor( ) {
super( new JComboBox() );
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected,
int row, int column) {
JComboBox combo = ( JComboBox ) editorComponent;
combo.setEditable(true); // make editable so that we can add new values
combo.removeAllItems(); // remove All pre-existing values.
Vector<Object> objectList = new Vector<Object>();
Object obj = null;
for( int i = 0; i < table.getRowCount(); i++ ) {
obj = table.getValueAt( i, column );
if( !objectList.contains( obj ) )
objectList.add( obj );
}
combo.setModel( new DefaultComboBoxModel(objectList) );
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Test t = new Test();
t.init();
}
}
I hope this will solve your problem.
Let me Explain clearly with the above Example.
JTable table = new JTable( new Object[][] { { "Paul J" , "20" }, { "Jerry M" , "30" }, { "Simon K" , "25" } },
new String[] { "Name" , "Age" } );
The above is the data that is going to be loaded in the Table Initially.
Where the Columns as Name and Age and values resp.
Now,I need is ' Age ' column will a combobox and For 'Paul J' in the Table populates the 'Age' as 20 by default and the comboBox should appear in this column and the User Now wants to change, the User now will have a option to select another value from the combobox to overwrite the default value.
Since the program is too large I'll just paste the important parts of code. Here's the problem:
I have two JTables. First one collects data from DB and displays the list of all invoices stored in DB. The purpose of the second table is when you click on one row from the table, event handler needs to collect integer from column ID. Using this ID the second table will then display all the contest of that invoice (all the products stored in it).
First and second table work perfectly. The problem is that I have no idea how can I collect certain data (I basically just need ID column) from a selected row and then through a method I already made update the second JTable with new info. Here's my code if it helps:
(PS: once I learn how to do that, will the list on the left change every time by default when I select different row, or do I need to use validate/revalidate methods?)
public JPanel tabInvoices() {
JPanel panel = new JPanel(new MigLayout("", "20 [grow, fill] 10 [grow, fill] 20", "20 [] 10 [] 20"));
/** Labels and buttons **/
JLabel labelInv = new JLabel("List of all invoices");
JLabel labelPro = new JLabel("List of all products in this invoice");
/** TABLE: Invoices **/
String[] tableInvTitle = new String[] {"ID", "Date"};
String[][] tableInvData = null;
DefaultTableModel model1 = new DefaultTableModel(tableInvData, tableInvTitle);
JTable tableInv = null;
/** Disable editing of the cell **/
tableInv = new JTable(model1){
public boolean isCellEditable(int r, int c) {
return false;
}
};
/** Load the invoices from DB **/
List<Invoice> listInv = is.getAllInvoices();
for (int i = 0; i < listInv.size(); i++) {
model1.insertRow(i, new Object[] {
listInv.get(i).getID(),
listInv.get(i).getDate()
});
}
/** TABLE: Invoice Info **/
String[] tableInfTitle = new String[] {"ID", "Name", "Type", "Price", "Quantity"};
String[][] tableInfData = null;
DefaultTableModel model2 = new DefaultTableModel(tableInfData, tableInfTitle);
JTable tableInf = null;
/** Disable editing of the cell **/
tableInf = new JTable(model2){
public boolean isCellEditable(int r, int c) {
return false;
}
};
/** Load the products from DB belonging to this invoice **/
List<Product> listPro = is.getInvoiceInfo(1); // Here's where I need the ID fetched from selected row. For now default is 1.
for (int i = 0; i < listPro.size(); i++) {
model2.insertRow(i, new Object[] {
listPro.get(i).getID(),
listPro.get(i).getName(),
listPro.get(i).getType(),
listPro.get(i).getPrice(),
listPro.get(i).getQuantity()
});
}
/** Scroll Panes **/
JScrollPane scrollInv = new JScrollPane(tableInv);
JScrollPane scrollPro = new JScrollPane(tableInf);
panel.add(labelInv);
panel.add(labelPro, "wrap");
panel.add(scrollInv);
panel.add(scrollPro);
return panel;
}
For now, the right table only displays content of the first invoice:
With the help of following code you can get the value of selected clicked cell, so you just have to click on ID cell value (the Invoicee ID whose Products you want to see in second table) and with the help of following event handler you will get the value and then you can get data based on that ID and set to second table. (In the code below, table is the object of your first table)
(Off-course you will have to apply some validation too, to check that the selected (and clicked) cell is ID not the DATE)
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int row = table.rowAtPoint(e.getPoint());
int col = table.columnAtPoint(e.getPoint());
Object selectedObj = table.getValueAt(row, col);
JOptionPane.showMessageDialog(null, "Selected ID is " + selectedObj);
}
});