This is the first time I've ever tried using a Java Swing JTable, so I'm probably doing something silly.
I'm trying to dynamically update a JTable within a JFrame on a GUI, this is the code I've currently written:
private void updateGUI(String input, DefaultTableModel model, int elements) { //3 elements
try {
Object[] cellData = input.split("!\\*");
Iterator it = Arrays.asList(cellData).iterator();
int rowCount = cellData.length / numberOfElements;
model.setRowCount(rowCount);
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < numberOfElements; j++) {
model.setValueAt(it.next(), i, j);
}
}
} catch (Exception uhoh) {
System.out.println("Couldn't add new string to gui");
uhoh.printStackTrace();
}
}
Essentially, I pass the updateGUI function a String containing elements, separated by !*. At the moment the data looks like this:
firstName!*123456!*lastName
This then gets split up into the Object[], and I'm currently using an iterator to put it into the table cells.
However, I keep getting ArrayIndexOutOfBoundsException: 27 >=27 being thrown, so it looks I'm doing something wrong with the cell generation/population.
I'm sure there is a much better way of doing this, but after reading through a few examples, I'm still a bit puzzled.
Any suggestions or advice would be greatly appreciated.
Thanks!
The easiest way I found to do this is to write a custom TableModel. I've written many of them and they not that difficult when you get your head around them. Given the code you posted you've have this message.
Derive your TableModel class from AbstractTableModel. This will handle the registration of any model listeners (one of which will be your JTable). Then on insert you need to call fireXXX() to notify all the listeners that there is new data. From your example code where you are replacing all the data this would be fireTableDataChanged().
Have a look at the Glazedlists project: http://www.glazedlists.com/
It solves this and a lot more in a very easy to use way. Documentation on your specific case can be found at http://www.glazedlists.com/propaganda/features#TOC-Easy-TableModels
Related
I asked a question related to the issue I was having before, but a new one arose. Originally, I wanted the capability of highlighting a row in my table with a single click, and editing a cell with a double click. greg-449 gave me the solution to the problem (getting rid of the FocusCellManager and simply using EditingSupport along with the other classes I had, and setting the editorActivationStrategy to have the MOUSE_DOUBLE_CLICK_SELECTION bit. However, now when I type text into a cell, the text is not saved into my model. On the other hand, when I use the FocusCellManager, the text is indeed saved.
Now, I have to use CellEditors, as there is already a very long list of CellEditors set up for the specific columns. I am not sure if it is possible to use EditingSupport along with CellEditors, or if it necessary at all. I am attaching some snippets.
Relevant Section of DatumTableViewer.java:
FocusCellOwnerDrawHighlighter drawHighlighter = new FocusCellOwnerDrawHighlighter(this); //removed this to fix the highlighting issue
final TableViewerFocusCellManager mgr = new TableViewerFocusCellManager(this, drawHighlighter); //removed this to fix the highlighting issue.
final ColumnViewerEditorActivationStrategy editorActivationSupport = getEditorActivationStrategy();
int tableKeyboardTraversalFeature = getKeyboardTraversalFeature();
TableViewerEditor.create(this, mgr, editorActivationSupport, tableKeyboardActivationFeature);
DatumColumnEmnum[] tableColumnsAsArray = getTableColumnsAsArray();
createTable(this.getTable(), tableColumnsAsArray);
setColumnProperties(properties.getPresentedColumnNames); //properties is passed into constructor
setCellEditors(tableColumnsAsArray); //I think this doesn't work properly without FocusCellManager
DatumCellModifier modifier = new DatumCellModifier(this, properties, myExpressionDataProvider); // myExpressionDataProvider is passed into constructor)
setCellModifier(modifier);
setContentProvider(contentProvider);
setInput(_myDatumList); // myDatumList set before this snippet
}
setCellEditors:
private void setCellEditors(DatumColumnEnum[] columns)
{
cellEditor[] editors = new CellEditor[columns.length];
for(int i = 0; i < columns.length; i++){
DatumColumnEnum columnID = columns[i];
switch(columnID) // cases have been trimmed to shorten this snippet
{
case DATUM_ID_COLUMN:
case DATUM_NUMBER_COLUMN:
case DATUM_NAME_COLUMN:
editors[i] = new TextCellEditor(this.getTable());
((Text) editors[i].getControl()).setTextLimit(60);
break;
}
}
this.setCellEditors(editors);
}
I suspect these snippets contain the problem, but if not, then please let me know and I'll add the other functions as well.
I've created a JTable whose columns contain a variety of different components. The last five columns either contain nothing (a DefaultTableCellRenderer with no value) or a JRadioButton using a custom renderer and editor. The renderer creates and returns a new radioButton in the cells I need one, and I want to access these radio buttons from my panel class to add them to a ButtonGroup. I am using the following piece of code that I wrote:
protected void setButtonGroups() {
buttonGroups = new ArrayList<ButtonGroup>();
for (int i = 0; i < tableModel.getRowCount(); i++) {
ButtonGroup currentGroup = new ButtonGroup();
for (int j = 0; j < tableModel.getColumnCount(); j++) {
if (table.getComponentAt(i, j) != null) {
currentGroup.add((JRadioButton)table.getComponentAt(i, j));
}
}
}
buttonGroups.add(currentGroup);
}
}
getComponentAt() keeps returning null regardless of what is contained in the cell, whether it be a JCheckBox, JRadioButton, JComboBox... everything is returned as null.
Is there an alternative way to get the cell's component? Or is there a way for me to get this to work? Thank you!
If you have a tableModel from table.getModel(). Then you can call model.getValueAt(row,col)
I am not sure why you are putting Swing Components inside a JTable. Are you using it for formatting? If so look into LayoutManagers. If you want to edit values in a table, you might want to look into extending TableCellEditor. If you really want to put components in your table. Consider extending the DefaultTableCellRenderer to return your component. You will want to override getTableCellRendererComponent().
I'm trying to color the text of every row in a table depending on one of the columns in the table. I'm having trouble grasping the concept of renderers, and I've tried out several different renderers but don't seem to understand what they do.
I am trying to load the top ten racers from a certain API given to us by our lecturer into the table model, but colouring each row based on the gender of the racer (which is returned by the getCategory() method of a Finisher/Racer object).
FYI, DataTable is an object written by our lecturer. It's basically a 2D array object.
public void showRacers(DefaultTableModel tblModel,
#SuppressWarnings("rawtypes") JList listOfRaces) {
// Clear the model of any previous searches
tblModel.setRowCount(0);
// Initialize an object to the selected city
CityNameAndKey city = (CityNameAndKey) listOfRaces.getSelectedValue();
// Get the runners for this city
DataTable runners = this.getRunners(city);
// Set the column headers
this.setColumnHeaders(tblModel);
// Make an array list of object Finisher
ArrayList<Finisher> finisherList = new ArrayList<Finisher>();
// Make an array that holds the data of each finisher
Object[] finisherData = new Object[6];
// Make a finisher object
Finisher f;
for (int r = 0; r < 10; r++) {
// Assign the data to the finisher object
finisherList.add(f = new Finisher(runners.getCell(r, 0), runners
.getCell(r, 1), runners.getCell(r, 2), runners
.getCell(r, 3), runners.getCell(r, 4), runners
.getCell(r, 5)));
// Add the data into the array
finisherData[0] = f.getPosition();
finisherData[1] = f.getBibNo();
finisherData[2] = f.getTime();
finisherData[3] = f.getGender();
finisherData[4] = f.getCategory();
finisherData[5] = f.getRuns();
// Put it into the table model
tblModel.addRow(finisherData);
}
}
I would greatly appreciate an explanation, rather than just the answer to my question. Guidance to the answer would be great, and some code would be extremely helpful, but please no: "You should have written this: ten lines of code I don't get
Thank you very much! :)
Using a TableCellRenderer will only allow you to color one column. You would have to have one for each column. A much easier approach is to override prepareRenderer(...) in JTable to color an entire row.
See trashgod's answer here or camickr's answer here
I have populated a combobox B1 from database. When itemStateChanged event raises it should populate another combobox B2, but its not working.
ArrayList1 = //call method in database connection class()
for (int j = 0; j < ArrayList1.size(); j++)
{
if (j == 0)
{
combobox1.addItem("Select Any");
}
combobox1.addItem(ArrayList1.get(j));
}
combobox1.addItemListener(new ItemListener()
{
#Override
public void itemStateChanged(ItemEvent ie)
{
String catName = (String)combobox1.getSelectedItem();
if (!catName.equalsIgnoreCase("Select Any"))
{
ArrayList2=//call method in DB class with cat_name as argument
for(int i=0;i < ArrayList2.size();i++)
{
if (i == 0)
{
combobox2.addItem("Select Any");
}
combobox2.addItem(ArrayList2.get(i));
}
}
}
});
first combobox gets populated from database, but after selecting any item from it second combobox keeps empty.
and why debugging this my computer hangs on?
you have to implements ComboBoxModel and add/remove/change Items in the Model, not in the JComboBox, nor somewhere in the Array, List or Vector, sure is possible but you have to execute your code on EDT and always replace Array, List or Vector for concreted JComboBox, don't do it that this way :-)
maybe you have problem with Concurency in the Swing, maybe changes are done, but outside EDT, more about your issues pass events wrapped into invokeLater() and multiple-jcombobox
DefaultComboBoxModel model = new DefaultComboBoxModel(yourstringarray);
item_combobox.setModel( model );
n ma problem get solved....
You must read:
http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html
It will help you to deal with java comboboxes.
Seems you should use an ActionListener as event to populate second combobox.
For your debug problems you should check bug 6714678 from java bugtracker
-Dsun.awt.disablegrab=true
should solve your debug problem (since 2008)
See could not work for old jdks as on 2007 related bug 6517045 says:
after discussion we came to conclusion that this (debug on combobox events) is just one more place when it is not
wise to stop in debugger (the same is true for DnD, fullscreen).
I got a doubt regarding pre-selecting(setSelectedIndex(index)) an item in a ListBox, Im using Spring + GWT.
I got a dialog that contains a panel, this panel has a FlexPanel, in which I've put a couple ListBox, this are filled up with data from my database.
But this Panel is for updates of an entity in my database, thus I wanted it to pre-select the current properties for this items, allowing the user to change at will.
I do the filling up in the update method of the widget.
I tried setting the selectedItem in the update method, but it gives me an null error.
I've searched a few places and it seems that the ListBox are only filled at the exact moment of the display. Thus pre-selecting would be impossible.
I thought about some event, that is fired when the page is displayed.
onLoad() doesnt work..
Anyone have something to help me out in here?
I really think you can set the selection before it's attached and displayed, but you have to have added the data before you can select an index. If this is a single select box you could write something like this:
void updateListContent(MyDataObject selected, List<MyDataObject> list){
for (MyDataObject anObject : list) {
theListBox.addItem(anObject.getTextToDisplay(), anObject.getKeyValueForList());
}
theListBox.setSelectedIndex(list.indexOf(selected));
}
If this is a multiple select box something like this may work:
void updateListContent(List<MyDataObject> allSelected, List<MyDataObject> list){
for (MyDataObject anObject : list) {
theMultipleListBox.addItem(anObject.getTextToDisplay(), anObject.getKeyValueForList());
}
for (MyDataObject selected : allSelected) {
theMultipleListBox.setItemSelected(list.indexOf(selected), true);
}
}
(Note I haven't actually compiled this, so there might be typos. And this assumes that the selected element(s) is really present in the list of possible values, so if you cant be sure of this you'll need to add some bounds checking.)
I've been happily setting both the values and the selection index prior to attachment so as far as I'm aware it should work. There's a bug however when setting the selected index to -1 on IE, see http://code.google.com/p/google-web-toolkit/issues/detail?id=2689.
private void setSelectedValue(ListBox lBox, String str) {
String text = str;
int indexToFind = -1;
for (int i = 0; i < lBox.getItemCount(); i++) {
if (lBox.getValue(i).equals(text)) {
indexToFind = i;
break;
}
}
lBox.setSelectedIndex(indexToFind);
}
Pre-selection should work also with setValue()-function. Thus, no complicated code is needed.