Search code examples
javaswingjtablefocusjcombobox

Return the focus to JComboBox inside a JTable after showOptionDialog


I'm having problems with a JComboBox used as a CellEditor for a JTable. I want after editing the JComboBox and pressing tab to show an OptionsDialog and, if a specific option is selected, the focus to remain on the JComboBox. The problem is that the focus moves to the next cell because of tab and I cannot return it to the JComboBox
Below is one of my test cases:

import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class TestFocus {

    public static void main(String[] args) {

        TestFocus test = new TestFocus();
        test.go();

    }

    public void go() {

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

        // create and add a tabbed pane to the frame
        JTabbedPane tabbedPane = new JTabbedPane();
        frame.getContentPane().add(tabbedPane);
        //create a table and add it to a scroll pane in a new tab
        JTable table = new JTable(new DefaultTableModel(new Object[] {"A", "B"}, 5));
        JScrollPane scrollPane = new JScrollPane(table);
        tabbedPane.addTab("test", scrollPane);

        // create a simple JComboBox and set is as table cell editor on column A
        Object[] comboElements = {"aaaaa1", "aaaaaa2", "b"};
        final JComboBox comboBox = new JComboBox(comboElements);
        comboBox.setEditable(true);
        table.getColumn("A").setCellEditor(new DefaultCellEditor(comboBox));

        // add an action listener for when the combobox is edited to display an options dialog
        comboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (e.getActionCommand().equals("comboBoxEdited")) {
                    // display an options pane
                    Object[] options = {"Yes", "No"};
                    System.out.println(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner());
                    int response = JOptionPane.showOptionDialog(SwingUtilities.getWindowAncestor(comboBox),
                            "Do you want to return the focus to the ComboBox?",
                            "This is just a test",
                            JOptionPane.YES_NO_OPTION,
                            JOptionPane.QUESTION_MESSAGE,
                            null,
                            options,
                            options[0]);
                    comboBox.requestFocusInWindow();
                    if (response == 0) {
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                comboBox.requestFocusInWindow();
                            }
                        });
                    }
                    System.out.println(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner());
                }

            }
        });

        // pack and show frame
        frame.pack();
        frame.setVisible(true);

    }
}

Solution

  • I'm asking him to confirm the adding

    Then you should be creating a custom editor and override the stopCellEditing() method.

    Here is an example that makes sure the data entered is exactly 5 characters.

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.text.*;
    import javax.swing.event.*;
    import javax.swing.border.*;
    import javax.swing.table.*;
    
    public class TableEdit extends JFrame
    {
        TableEdit()
        {
            JTable table = new JTable(5,5);
            table.setPreferredScrollableViewportSize(table.getPreferredSize());
    
            JScrollPane scrollpane = new JScrollPane(table);
            add(scrollpane);
    
            //  Use a custom editor
    
            TableCellEditor fce = new FiveCharacterEditor();
            table.setDefaultEditor(Object.class, fce);
    
            add(new JTextField(), BorderLayout.NORTH);
        }
    
        class FiveCharacterEditor extends DefaultCellEditor
        {
            FiveCharacterEditor()
            {
                super( new JTextField() );
            }
    
            public boolean stopCellEditing()
            {
                JTable table = (JTable)getComponent().getParent();
    
                try
                {
                    String editingValue = (String)getCellEditorValue();
    
                    if(editingValue.length() != 5)
                    {
                        JTextField textField = (JTextField)getComponent();
                        textField.setBorder(new LineBorder(Color.red));
                        textField.selectAll();
                        textField.requestFocusInWindow();
    
                        JOptionPane.showMessageDialog(
                            null,
                            "Please enter string with 5 letters.",
                            "Alert!",JOptionPane.ERROR_MESSAGE);
                        return false;
                    }
                }
                catch(ClassCastException exception)
                {
                    return false;
                }
    
                return super.stopCellEditing();
            }
    
            public Component getTableCellEditorComponent(
                JTable table, Object value, boolean isSelected, int row, int column)
            {
                Component c = super.getTableCellEditorComponent(
                    table, value, isSelected, row, column);
                ((JComponent)c).setBorder(new LineBorder(Color.black));
    
                return c;
            }
    
        }
    
        public static void main(String [] args)
        {
            JFrame frame = new TableEdit();
            frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
            frame.pack();
            frame.setLocationRelativeTo( null );
            frame.setVisible(true);
        }
    }