Solved

JComboBox cell renderer/editor updates other JComboBox in same JTable

Posted on 2008-06-18
19
5,321 Views
Last Modified: 2013-12-14
I'm stuck. I have a JTable that holds a JComboBox which is populated depending on the value in another cell (plain) in the same row. Everything displays correctly, with the correct values in each combo box. The problem is when I make a selection on a combo box, any previous combo box selections revert to the default state. I know I'm stomping on either my combo box instance or the Vector I'm populating it with in either my cell editor or cell renderer class. I'm also fairly certain I'm implementing too many instances of JComboBox.

Thanks in advance....
import java.util.Vector;

import javax.swing.JTable;

import javax.swing.table.TableCellEditor;

import javax.swing.table.TableCellRenderer;

import javax.swing.table.TableColumnModel;

import javax.swing.table.TableModel;
 

public class ComboBoxTable extends JTable {

    

    public ComboBoxTable(TableModel tm) {

        super(tm);

        tableModel = (ComboBoxOutputTableModel)tm;

    }

    

    ComboBoxOutputTableModel tableModel;

    

    Vector valuesVector = null;

    

    

    public TableCellRenderer getCellRenderer(int row, int column){

        if(column == 1){

            setValuesVector(row,column);

            MyComboBoxRenderer renderer = new MyComboBoxRenderer(valuesVector);

            getColumnModel().getColumn(1).setCellRenderer(renderer);

            return renderer;

        }

        else return super.getCellRenderer(row, column);

    }
 

    public TableCellEditor getCellEditor(int row, int column)

    {       

        if (column == 1){           

            

            MyComboBoxEditor editor = new InegQueueComboBoxEditor(valuesVector);

            return editor;

        }

        else return super.getCellEditor(row, column);

    }

    

    /**

     * Gets the collection from the table model data for the current row and populates 

     * the Vector that will be set to a comboBox with it

     * tableModel.getData() returns Object[int][String[]]

     */

    public void setValuesVector(int row, int column){

        Object[] modelRow = tableModel.getData()[row];   

        this.valuesVector = new Vector((Vector)modelRow[column]);

    }
 

}
 

public class MyComboBoxRenderer implements TableCellRenderer {

   

    public MyComboBoxRenderer(Vector v){
 

    }
 

    public Component getTableCellRendererComponent(JTable table, Object value,

            boolean isSelected, boolean hasFocus, int row, int column) {

        JComboBox comboBox = null;

               

        if(value == null){

            comboBox = new JComboBox();

        }else{

            Vector vector = (value instanceof Vector)?(Vector)value:new Vector();

            comboBox = new EiiComboBox(vector);

            comboBox.setFont(LookAndFeelConstants.getLabelFont());

        }

        if (isSelected) {

            comboBox.setForeground(table.getSelectionForeground());

            comboBox.setBackground(table.getSelectionBackground());

            

        } else {

            comboBox.setForeground(table.getForeground());

            comboBox.setBackground(table.getBackground());

        }

        return comboBox;

    }

    

}
 
 

public class MyComboBoxEditor extends AbstractCellEditor implements TableCellEditor {
 

    private Component comp = null;

    private int r = 0;

    private int c = 0;

   

    public MyComboBoxEditor(Vector items) {

        super();

    }

    
 

    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {

        Component com = null;

        r = row;

        c = column;

        JComboBox comboBox;

        

        if(value == null || value.toString().length() == 0) com = new JTextField("");

        else if(value instanceof Vector){

            comboBox = new JComboBox();

              if(comboBox.getModel().getSize() > 0){

                    // clear it...

                  comboBox.removeAllItems();

              }

              comboBox.setModel(new DefaultComboBoxModel((Vector)value));

              

              comboBox.addItemListener(new ItemListener(){

                public void itemStateChanged(ItemEvent e) {

                

                	//nothing implemented here yet

                }                  

              });
 

              com = comboBox;

              

        }else {

        

            comboBox = new JComboBox();

              if(comboBox.getModel().getSize() > 0){

                    // clear it...

                  comboBox.removeAllItems();

              }

              comboBox.addItem(value);

              com = comboBox;

        }

        comp = com;

        return com;

    }
 

	//inherited

	

    public Object getCellEditorValue() {

        return null;

    }

}

Open in new window

0
Comment
Question by:jolly_rog
  • 11
  • 8
19 Comments
 

Author Comment

by:jolly_rog
ID: 21817794
Just to clarify, the value in the other column is a parameter for a sql query, hence the different values for each row's comboBox. It's also persisted in the data object retrieved from the tableModel, but the value is irrelevant to the current problem.
0
 
LVL 92

Expert Comment

by:objects
ID: 21818333
your renderer never sets the selected item, thus it will always be the default
Set the required value in getTableCellRendererComponent()
0
 

Author Comment

by:jolly_rog
ID: 21818468
In getTableCellRendererComponent()  I have:

if(value == null){
            comboBox = new JComboBox();
        }else{
            Vector vector = (value instanceof Vector)?(Vector)value:new Vector();
            comboBox = new JComboBox(vector);
        }
}

so should I change that to :
int x = the seleceted index; //dig this value out of the ItemEvent?
new JComboBox(vector.elementAt(x));

?
0
 
LVL 92

Expert Comment

by:objects
ID: 21818482
no you need something like:

comboBox.setSelectedItem(value);

or

comboBox.setSelectedIndex(indexOfValueInVector);

0
 

Author Comment

by:jolly_rog
ID: 21822788
I tried that and when I make a selection on another row's comboBox, the one I just selected goes back to the default. Same problem.
0
 

Author Comment

by:jolly_rog
ID: 21823300
I thought maybe my problem is that in my table, I'm sending the renderer the Vector associated with the row I've clicked on, so it overwrites what was populating the comboBox in the previously selected row?
So I made this change:

    public Vector getValuesVector(int row, int column){
        Object[] modelRow = tableModel.getData()[row];  
        return new Vector((Vector)modelRow[column]);
   }
///////
MyComboBoxRenderer renderer = new MyComboBoxRenderer( getValuesVector(int row, int column));

But the values are different in the new Vector(which is the only value the renderer knows),so  the selected item doesn't exist the next time the renderer gets called, right?

 So, how do I fix THAT?

0
 
LVL 92

Expert Comment

by:objects
ID: 21827291
You need to actually set the value to something that is in the combos list, it doesn't make sense to set it to something thats not in there.

0
 

Author Comment

by:jolly_rog
ID: 21827981
That's what I figured.

One idea I have is to create a data structure that I populate with my result set data and then iterate through it and create a new JComboBox for each set, and just pass them into my renderer and editor.

Or, just use the data structure to hold reference to each collection for the comboBoxes.
0
 
LVL 92

Expert Comment

by:objects
ID: 21828033
How does the value get set to something that is not in the combo?

0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:jolly_rog
ID: 21830520
I'm going to have to come up with a way to iterate through the "master" data from my result and create a new comboBox for each set of data on the fly, then pass them to my renderer and editor. Each combo has it's own value set at that point.
0
 
LVL 92

Expert Comment

by:objects
ID: 21835147
so soes every combo have a different list of options? where are the options coming from?

0
 

Author Comment

by:jolly_rog
ID: 21835994
Yeah they're all different, because the value in the other column (which comes from another -simpler- query) is a parameter in the query that produces the values for the combo. By the nature of the schema, they all come out with different value sets. Of course, we're talking 1 - n combos with 0-n items in each one.

I'm still trying to come up with a way to persist the different value sets, but it's tough when it's unkonwn how many there might be.

As I think about it, maybe some factory could pop out the vectors that would all be unique instances, but for the renderer to hold reference to the right one is a challenge.

I'm sure the project architect thought this looked real cool when he did it in vizio.
0
 
LVL 92

Accepted Solution

by:
objects earned 500 total points
ID: 21839242
The available values could be stored in the table model. The renderer could then pull all the required values and setup the combo accordingly.

0
 

Author Comment

by:jolly_rog
ID: 21839583
So you agree with my idea, that the table model could have a factory method to generate the value objects for the renderer?
0
 
LVL 92

Expert Comment

by:objects
ID: 21842640
sounds ok as long as it doesn't take too long to generate them everytime.

0
 

Author Comment

by:jolly_rog
ID: 21868812
My next cut is going to try to create an editor model that builds a map of editors keyed by the string value of the first column. We'll see how that goes.
0
 
LVL 92

Expert Comment

by:objects
ID: 21870276
sounds like an overkill (and you'll need renerers as well as editors)
all you need is the combo models.

0
 

Author Comment

by:jolly_rog
ID: 21902741
I gave up. I just changed the design to iterate my data and set a new row with a label and combo for each iteration. Works great, I can persist the selections and it took 30 minutes.

Thanks for your help, anyway.
0
 

Author Closing Comment

by:jolly_rog
ID: 31468603
This is a really complex task, and tough, if not impossible to implement, so I'm awarding the points based on the help and accuracy as far as it got me before I went with a different design.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

In our object-oriented world the class is a minimal unit, a brick for constructing our applications. It is an abstraction and we know well how to use it. In well-designed software we are not usually interested in knowing how objects look in memory. …
Here is a helpful source code for C++ Builder programmers that allows you to manage and manipulate HTML content from C++ code, while also handling HTML events like onclick, onmouseover, ... Some objects defined and used in this source include: …
The viewer will learn how to synchronize PHP projects with a remote server in NetBeans IDE 8.0 for Windows.
The viewer will learn how to use and create new code templates in NetBeans IDE 8.0 for Windows.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now