Search code examples
javaswingjtablejcomboboxtablecelleditor

Adding JCombobox in Jtable and Getting that Row and Column in Swing java


I have One Jtable in which i have added JComobox like this.

TableColumn sportColumn = jTable1.getColumnModel().getColumn(2);
        comboBox = new JComboBox();
        comboBox.addItem("Snowboarding");
        comboBox.addItem("Rowing");
        comboBox.addItem("Chasing toddlers");
        comboBox.addItem("Speed reading");
        comboBox.addItem("Teaching high school");
        comboBox.addItem("None");
        sportColumn.setCellEditor(new DefaultCellEditor(comboBox));

and i have added one mouse event of jtable like this.

private void jTable1MouseClicked(java.awt.event.MouseEvent evt) {                                     
        // TODO add your handling code here:
        try {
            int row = jTable1.rowAtPoint(evt.getPoint());
            int col = jTable1.columnAtPoint(evt.getPoint());

            System.out.println("Row" + row + "Column" + col);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

and i am getting proper out put of row and column.enter image description here

but when i click on the cell where i added Jcombobox that time its not giving out put of that row and column. still i have called clickevent of table in combobox click event but its giving all time row 0 and even column 0 here screen shot.

enter image description here

so how do i solved it so i can have that row and column?


Solution

  • As I see it, you have three basic options...

    You Could...

    Attach a CellEditorListener to the DefaultCellEditor and monitor for editingStopped events...

    editor.addCellEditorListener(new CellEditorListener() {
        @Override
        public void editingStopped(ChangeEvent e) {
            System.out.println("Editing stopped");
            TableCellEditor editor = (TableCellEditor) e.getSource();
            Object value = editor.getCellEditorValue();
            System.out.println("Selected value = " + value);
        }
    
        @Override
        public void editingCanceled(ChangeEvent e) {
        }
    });
    

    The problem with this, is it's not possible to actually determine the cell that's been edited. Even with a reference to the JTable, by the time you receive this event, the table is no longer in edit mode...So all you know is the value of the editor...

    You Could...

    Attach a TableModelListener to the TableModel...

    model.addTableModelListener(new TableModelListener() {
        @Override
        public void tableChanged(TableModelEvent e) {
            int type = e.getType();
            switch (type) {
                case TableModelEvent.UPDATE:
                    if (e.getFirstRow() - e.getLastRow() == 0) {
                        TableModel model = (TableModel) e.getSource();
                        int row = e.getFirstRow();
                        int col = e.getColumn();
                        System.out.println("Update " + row + "x" + col + " = " + model.getValueAt(row, col));
                    }
                    break;
            }
        }
    });
    

    This will let you know when the value of a cell has changed (and a lot of other things, but this is what we're interested), what it won't tell you, is why it changed.

    This approach is good, because it provides all the information you need to know in order to find the value and the cell.

    You Could...

    Simply override the TableModel's setValueAt method and provide some sort of notification of your own...

    While this is kind of duplicating the functionality of the TableModelListener you could devise the event information so that it provides more relevant information as the TableModelEvent covers a lot of user cases...

    Example

    Below is an example taken TableRenderDemo and modified to to demonstrate the first two concepts

    import java.awt.BorderLayout;
    import javax.swing.DefaultCellEditor;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.table.AbstractTableModel;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.TableCellRenderer;
    import javax.swing.table.TableColumn;
    import java.awt.Component;
    import java.awt.Dimension;
    import javax.swing.event.CellEditorListener;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.TableModelEvent;
    import javax.swing.event.TableModelListener;
    import javax.swing.table.TableCellEditor;
    import javax.swing.table.TableModel;
    
    /**
     * TableRenderDemo is just like TableDemo, except that it explicitly initializes
     * column sizes and it uses a combo box as an editor for the Sport column.
     */
    public class TableRenderDemo extends JPanel {
    
        public TableRenderDemo() {
            super(new BorderLayout());
    
            JTable table = new JTable(new MyTableModel());
            table.setPreferredScrollableViewportSize(new Dimension(500, 70));
            table.setFillsViewportHeight(true);
    
            //Create the scroll pane and add the table to it.
            JScrollPane scrollPane = new JScrollPane(table);
    
            //Set up column sizes.
            initColumnSizes(table);
    
            //Fiddle with the Sport column's cell editors/renderers.
            setUpSportColumn(table, table.getColumnModel().getColumn(2));
    
            //Add the scroll pane to this panel.
            add(scrollPane);
        }
    
        /*
         * This method picks good column sizes.
         * If all column heads are wider than the column's cells'
         * contents, then you can just use column.sizeWidthToFit().
         */
        private void initColumnSizes(JTable table) {
            MyTableModel model = (MyTableModel) table.getModel();
            model.addTableModelListener(new TableModelListener() {
                @Override
                public void tableChanged(TableModelEvent e) {
                    int type = e.getType();
                    switch (type) {
                        case TableModelEvent.UPDATE:
                            if (e.getFirstRow() - e.getLastRow() == 0) {
                                TableModel model = (TableModel) e.getSource();
                                int row = e.getFirstRow();
                                int col = e.getColumn();
                                System.out.println("Update " + row + "x" + col + " = " + model.getValueAt(row, col));
                            }
                            break;
                    }
                }
            });
            TableColumn column = null;
            Component comp = null;
            int headerWidth = 0;
            int cellWidth = 0;
            Object[] longValues = model.longValues;
            TableCellRenderer headerRenderer
                            = table.getTableHeader().getDefaultRenderer();
    
            for (int i = 0; i < 5; i++) {
                column = table.getColumnModel().getColumn(i);
    
                comp = headerRenderer.getTableCellRendererComponent(
                                null, column.getHeaderValue(),
                                false, false, 0, 0);
                headerWidth = comp.getPreferredSize().width;
    
                comp = table.getDefaultRenderer(model.getColumnClass(i)).
                                getTableCellRendererComponent(
                                                table, longValues[i],
                                                false, false, 0, i);
                cellWidth = comp.getPreferredSize().width;
    
                column.setPreferredWidth(Math.max(headerWidth, cellWidth));
            }
        }
    
        public void setUpSportColumn(final JTable table,
                        TableColumn sportColumn) {
            //Set up the editor for the sport cells.
            JComboBox comboBox = new JComboBox();
            comboBox.addItem("Snowboarding");
            comboBox.addItem("Rowing");
            comboBox.addItem("Knitting");
            comboBox.addItem("Speed reading");
            comboBox.addItem("Pool");
            comboBox.addItem("None of the above");
            TableCellEditor editor = new DefaultCellEditor(comboBox);
            editor.addCellEditorListener(new CellEditorListener() {
    
                @Override
                public void editingStopped(ChangeEvent e) {
                    System.out.println("Editing stopped");
                    TableCellEditor editor = (TableCellEditor) e.getSource();
                    Object value = editor.getCellEditorValue();
                    System.out.println("Selected value = " + value);
                }
    
                @Override
                public void editingCanceled(ChangeEvent e) {
                }
            });
            sportColumn.setCellEditor(editor);
    
            //Set up tool tips for the sport cells.
            DefaultTableCellRenderer renderer
                            = new DefaultTableCellRenderer();
            renderer.setToolTipText("Click for combo box");
            sportColumn.setCellRenderer(renderer);
        }
    
        class MyTableModel extends AbstractTableModel {
    
            private String[] columnNames = {"First Name",
                "Last Name",
                "Sport",
                "# of Years",
                "Vegetarian"};
            private Object[][] data = {
                {"Kathy", "Smith",
                    "Snowboarding", new Integer(5), new Boolean(false)},
                {"John", "Doe",
                    "Rowing", new Integer(3), new Boolean(true)},
                {"Sue", "Black",
                    "Knitting", new Integer(2), new Boolean(false)},
                {"Jane", "White",
                    "Speed reading", new Integer(20), new Boolean(true)},
                {"Joe", "Brown",
                    "Pool", new Integer(10), new Boolean(false)}
            };
    
            public final Object[] longValues = {"Jane", "Kathy",
                "None of the above",
                new Integer(20), Boolean.TRUE};
    
            @Override
            public int getColumnCount() {
                return columnNames.length;
            }
    
            @Override
            public int getRowCount() {
                return data.length;
            }
    
            @Override
            public String getColumnName(int col) {
                return columnNames[col];
            }
    
            @Override
            public Object getValueAt(int row, int col) {
                return data[row][col];
            }
    
            /*
             * JTable uses this method to determine the default renderer/
             * editor for each cell.  If we didn't implement this method,
             * then the last column would contain text ("true"/"false"),
             * rather than a check box.
             */
            @Override
            public Class getColumnClass(int c) {
                return getValueAt(0, c).getClass();
            }
    
            /*
             * Don't need to implement this method unless your table's
             * editable.
             */
            @Override
            public boolean isCellEditable(int row, int col) {
                //Note that the data/cell address is constant,
                //no matter where the cell appears onscreen.
                if (col < 2) {
                    return false;
                } else {
                    return true;
                }
            }
    
            /*
             * Don't need to implement this method unless your table's
             * data can change.
             */
            @Override
            public void setValueAt(Object value, int row, int col) {
                data[row][col] = value;
                fireTableCellUpdated(row, col);
            }
        }
    
        /**
         * Create the GUI and show it. For thread safety, this method should be
         * invoked from the event-dispatching thread.
         */
        private static void createAndShowGUI() {
            //Create and set up the window.
            JFrame frame = new JFrame("TableRenderDemo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            //Create and set up the content pane.
            TableRenderDemo newContentPane = new TableRenderDemo();
            newContentPane.setOpaque(true); //content panes must be opaque
            frame.setContentPane(newContentPane);
    
            //Display the window.
            frame.pack();
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            //Schedule a job for the event-dispatching thread:
            //creating and showing this application's GUI.
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI();
                }
            });
        }
    }