Greg2Duo
Greg2Duo

Reputation: 11

Overriding Cell Editor for Individual JTable Cells that have been Dynamically Created

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;
                }

Upvotes: 1

Views: 1219

Answers (1)

camickr
camickr

Reputation: 324098

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.

Upvotes: 2

Related Questions