nick
nick

Reputation: 51

Jtable jcombobox and cell editing

I would like to have a jtable with 4 columns. One column must be a combobox. Other columns are strings.

When i click one time on a cell, i would like the cell become editable with blinking caret/cursor.Also, if i click on the combobox i would like the combox set popup visble.

I have read and tested tutorial "How to Use Tables", and if i make just one click on combobox in the cell, it opens. My first problem is that i don't understand why the code in the tutorial works when we implement abstract table model and not working DefaultTableModel.

My code is :

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

public class JtabletestOK {

    public static void main(String[] args) {

        JtabletestOK test = new JtabletestOK();
        test.go();
    }

    public void go() {

        //create the frame
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);



        //create a table and add it to a scroll pane in a new tab
        JTable jTable1 = new JTable()
        {
            //  Place cell in edit mode when it 'gains focus'

            public void changeSelection(
                    int row, int column, boolean toggle, boolean extend)
            {
                super.changeSelection(row, column, toggle, extend);

                if (editCellAt(row, column))
                {
                    Component editor = getEditorComponent();
                    editor.requestFocusInWindow();
                    // System.out.println("ffin focus gagne");
                    if (editor instanceof JTextField) {

                        JTextField jf = (JTextField) editor;
                        jf.select(0, jf.toString().length());
                    }}
            }
        };


        jTable1.setPreferredScrollableViewportSize(new Dimension(800,100));
        jTable1.setFillsViewportHeight(true);

        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(jTable1);

        Object columnNames[] = { "DataCombo", "Data 2", "Data 3", "Data 4"  };
        DefaultTableModel model = new DefaultTableModel(columnNames, 0);

        Object rowData[] = { "", "Row1-Column2", "Row1-Column3", "Row1-Column3" };
        model.addRow(rowData);
        jTable1.setModel(model);


        String[] comboBoxArray = {"proem1","veitem2","atem3"};
        JComboBox jcb = new JComboBox(comboBoxArray);
        jcb.setEditable(true);


        TableColumn colCombo = jTable1.getColumnModel().getColumn(0);
        colCombo.setCellEditor(new DefaultCellEditor(jcb));

        jcb.setEditable(true);



        frame.getContentPane().add(scrollPane);
        frame.pack();
        frame.setVisible(true);

    }

The source with abstract model is here : http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableRenderDemoProject/src/components/TableRenderDemo.java

Just find the problem : When commenting the statement jcb.setEditable(true); , if i do a single click on the comboxcell it opens the cell. But i don't know why it works better. Also, i would like the combox editable.

How i can have the same behavior for others cells.

Hello again, i have updated the code in order to have - cells become editable if i click one time on the cell by overriding the method - combobox become editable if i click one time on the cell by overriding the method

I put my new code here, it may help other :

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;

public class JtabletestOK {

    public static void main(String[] args) {

        JtabletestOK test = new JtabletestOK();
        test.go();
    }

    public void go() {

        //create the frame
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);



        //create a table and add it to a scroll pane in a new tab
        JTable jTable1 = new JTable()

        {
            //  Place cell in edit mode when it 'gains focus'

            public void changeSelection(
                    int row, int column, boolean toggle, boolean extend)
            {
                super.changeSelection(row, column, toggle, extend);

                if (column > 0)
                {

                    if (editCellAt(row, column))
                    {
                        Component editor = getEditorComponent();
                        editor.requestFocusInWindow();
                        // System.out.println("ffin focus gagne");
                        if (editor instanceof JTextField) {

                            JTextField jf = (JTextField) editor;
                            jf.select(0, jf.toString().length());
                        }}
                }
            }
        };



        jTable1.setPreferredScrollableViewportSize(new Dimension(800,100));
        jTable1.setFillsViewportHeight(true);
        replaceTabByEnter(jTable1);

        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(jTable1);

        Object columnNames[] = { "DataCombo", "Data 2", "Data 3", "Data 4"  };
        DefaultTableModel model = new DefaultTableModel(columnNames, 0);

        Object rowData[] = { "", "Row1-Column2", "Row1-Column3", "Row1-Column3" };
        model.addRow(rowData);
        jTable1.setModel(model);


        String[] comboBoxArray = {"proem1","veitem2","atem3"};
        JComboBox jca = new JComboBox(comboBoxArray);
        jca.setSelectedItem("");
        JTextComponent editor = (JTextComponent) jca.getEditor().getEditorComponent();

        jca.addPopupMenuListener(new PopupMenuListener() {

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                JComponent ja = (JComponent) e.getSource();
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                JComponent ja = (JComponent) e.getSource();
                JTable jtb = (JTable) ja.getParent();
                jtb.changeSelection(0,1,false,false);
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
            }
        });



        editor.addMouseListener(new MouseListener() {

            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("Not mouseClicked yet.");
            }

            @Override
            public void mousePressed(MouseEvent e) {
                System.out.println("Not mousePressed yet.");
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                JComponent ja = (JComponent) e.getSource();
                JComponent jcbloc = (JComponent) ja.getParent();
                JComboBox jcb = (JComboBox) jcbloc;
                jcb.setPopupVisible(true);
                System.out.println("Not mouseReleased yet.");

            }

            @Override
            public void mouseEntered(MouseEvent e) {
                System.out.println("Not mouseEntered yet.");
            }

            @Override
            public void mouseExited(MouseEvent e) {
                System.out.println("Not mouseExited yet.");
            }
        });

        autocompletecombo jcb =new autocompletecombo(jca);
        TableColumn colCombo = jTable1.getColumnModel().getColumn(0);
        jca.setEditable(true);
        comboboxEditor cbe = new comboboxEditor(jca);
        colCombo.setCellEditor(cbe);

        frame.getContentPane().add(scrollPane);
        frame.pack();
        frame.setVisible(true);

    }


    public void replaceTabByEnter(JTable  jtane) {

        KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
        KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
        InputMap im = jtane.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        im.put(enter, im.get(tab));
    }


    class comboboxEditor extends AbstractCellEditor implements TableCellEditor{

        JComboBox comboBox;
        JTextField jtf;

        S11InitialSelection sjcb;
        @Override
        public Object getCellEditorValue() {
            return comboBox.getSelectedItem();
        }

        public comboboxEditor(JComboBox jcb) {

            comboBox = jcb;
            jtf.selectAll();
        }

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

            comboBox.setSelectedItem(value);
            return comboBox;
        }

        public boolean stopCellEditing() {


            fireEditingStopped();
            //     jt.EditNextCell();
            return true;

        }


    }










}

I have find a solution for that :

            public void mouseReleased(MouseEvent e) {
                JComponent ja = (JComponent) e.getSource();
                JComponent jcbloc = (JComponent) ja.getParent();
                JComboBox jcb = (JComboBox) jcbloc;
                jcb.setPopupVisible(true);
                JTextComponent editor = (JTextComponent) jcb.getEditor().getEditorComponent();
                editor.setSelectionStart(0);
                editor.setSelectionEnd(editor.getText().length());
                System.out.println("Not mouseReleased yet.");

            }

Thanks for your help.

Upvotes: 3

Views: 3786

Answers (3)

nick
nick

Reputation: 51

I have finally find how to solve all my problems. I post all the code. I hope it will help others. If you find better way to adress the problem, i'm open.

It remains two strange thing but it work as i want, so if somenone as an idea :

  • If i move the code

            if(e.getKeyChar() == KeyEvent.VK_ENTER){
                JComponent ja = (JComponent) e.getSource();
                JComboBox jcbloc = (JComboBox) ja.getParent();
                JTable jtb = (JTable) jcbloc.getParent();
                jtb.changeSelection(0,1,false,false);
            }
    

in keyReleased instead of keyPressed, it doesn't work.

  • When i press enter on basic cell text, the program go to next cell alone. I don't understand how it goes alone to next cell on enter key.

All the code here :

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.basic.BasicTextUI;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;


public class JtabletestOKStackOver {

public static void main(String[] args) {

    JtabletestOKStackOver test = new JtabletestOKStackOver();
    test.go();
}

public void go() {

    //create the frame
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //create a table and add it to a scroll pane in a new tab
    JTable jTable1 = new JTable()

    {
        //  Place cell in edit mode when it 'gains focus'

        public void changeSelection(
                int row, int column, boolean toggle, boolean extend)
        {
            super.changeSelection(row, column, toggle, extend);


            if (column > -1)
            {

                if (editCellAt(row, column))
                {
                    Component editor = getEditorComponent();
                    editor.requestFocusInWindow();
                    if (editor instanceof JTextField) {

                        JTextField jf = (JTextField) editor;
                        jf.select(0, jf.toString().length());
                    }
                    if (editor instanceof JComboBox) {
                        JComboBox jcb = (JComboBox) editor;
                        jcb.setPopupVisible(true);
                        JTextComponent editorCombo = (JTextComponent) jcb.getEditor().getEditorComponent();
                        editorCombo.setSelectionStart(0);
                        editorCombo.setSelectionEnd(editorCombo.getText().length());
                    }



                }
            }
        }
    };





    jTable1.setPreferredScrollableViewportSize(new Dimension(800,100));
    jTable1.setFillsViewportHeight(true);
    jTable1.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

    //Create the scroll pane and add the table to it.
    JScrollPane scrollPane = new JScrollPane(jTable1);

    Object columnNames[] = { "DataCombo", "Data 2", "Data 3", "Data 4"  };
    DefaultTableModel model = new DefaultTableModel(columnNames, 0);

    Object rowData[] = { "", "Row1-Column2", "Row1-Column3", "Row1-Column3" };
    model.addRow(rowData);
    jTable1.setModel(model);


    String[] comboBoxArray = {"proem1","veitem2","atem3"};
    JComboBox jca = new JComboBox(comboBoxArray);
    jca.setSelectedItem("");
    JTextComponent editor = (JTextComponent) jca.getEditor().getEditorComponent();

    editor.addKeyListener(new KeyListener() {

        @Override
        public void keyTyped(KeyEvent e) {
        }

        @Override
        public void keyPressed(KeyEvent e) {
            if(e.getKeyChar() == KeyEvent.VK_ENTER){
                JComponent ja = (JComponent) e.getSource();
                JComboBox jcbloc = (JComboBox) ja.getParent();
                JTable jtb = (JTable) jcbloc.getParent();
                jtb.changeSelection(0,1,false,false);
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {

        }
    });


    editor.addFocusListener(new FocusListener() {

        @Override
        public void focusGained(FocusEvent e) {
            JComponent ja = (JComponent) e.getSource();
            JComponent jcbloc = (JComponent) ja.getParent();
            JComboBox jcb = (JComboBox) jcbloc;
            jcb.setPopupVisible(true);
            JTextComponent editor = (JTextComponent) jcb.getEditor().getEditorComponent();
            editor.setSelectionStart(0);
            editor.setSelectionEnd(editor.getText().length());
        }

        @Override
        public void focusLost(FocusEvent e) {
        }
    });





    TableColumn colCombo = jTable1.getColumnModel().getColumn(0);
    jca.setEditable(true);
    comboboxEditor cbe = new comboboxEditor(jca);
    colCombo.setCellEditor(cbe);


    TableColumn colAutre = jTable1.getColumnModel().getColumn(1);
    TableColumn colAutre2 = jTable1.getColumnModel().getColumn(2);
    TableColumn colAutre3 = jTable1.getColumnModel().getColumn(3);
    textCellEditor dce = new textCellEditor(new JTextField());

    colAutre.setCellEditor(dce);
    colAutre2.setCellEditor(dce);
    colAutre3.setCellEditor(dce);



    frame.getContentPane().add(scrollPane);
    frame.pack();
    frame.setVisible(true);

}







class comboboxEditor extends AbstractCellEditor implements TableCellEditor{

    JComboBox comboBox;



    public comboboxEditor(JComboBox jcb) {

        comboBox = jcb;
    }


    public Object getCellEditorValue() {
        return comboBox.getSelectedItem();
    }


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

        comboBox.setSelectedItem(value);
        return comboBox;
    }

    public boolean stopCellEditing() {
        fireEditingStopped();
        return true;

    }


}

class textCellEditor extends AbstractCellEditor implements TableCellEditor{
    JTextField jtextfield;

    public textCellEditor(JTextField jtf) {
        jtextfield = jtf;
    }


    public Object getCellEditorValue() {
        return jtextfield.getText();
    }


    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        if (isSelected) {
            // cell (and perhaps other cells) are selected
        }
        if (value== null)
        {
            value="";
        }
        value = value.toString();
        if (value instanceof Integer) {
            value = value.toString();
        }
        jtextfield.setText((String) value);

        // Return the configured component
        return jtextfield;
    }

    public boolean stopCellEditing() {
        fireEditingStopped();
        return true;

    }

}



}

Thanks for your help.

Upvotes: 2

camickr
camickr

Reputation: 324118

Don't use an ActionListener on the combo box. The "popup" will be displayed by the editor when you click on the cell.

My first problem is that i don't understand why the code in the tutorial works when we implement abstract table model and not working DefaultTableModel.

Editing is controlled by the isCellEditable(...) method of the TableModel. When you click on a cell that is editable the JTable will use the appropriate editor. If the editor is a combo box, then the popup will be displayed when the cell is clicked.

Just find the problem : When commenting the statement jcb.setEditable(true); , if i do a single click on the comboxcell it opens the cell. But i don't know why it works better

When you click on a cell I believe the MouseEvent is forwarded to the editor (ie the combo box). Since the combo box is editable the MouseEvent goes to the text field, so focus remains of the text field and the popup is not displayed. Try this with a normal combo box, not displayed in a JTable so see the same behaviour.

Upvotes: 0

Sergiy Medvynskyy
Sergiy Medvynskyy

Reputation: 11327

I don't know why your code with AbstractTableModel works (because I cannot see it). But I can help you to make your example working.

    jcb.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            System.out.println("test");
            final JComboBox j= (JComboBox)evt.getSource();
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    if (j.isDisplayable()) j.setPopupVisible(true);
                }
            });

        }});

Upvotes: -1

Related Questions