简体   繁体   English

使用复合JPanel单元格编辑器编辑后,JTable失去焦点

[英]JTable loses focus after editing with compound JPanel cell editor

I have a cell editor that is composed of several components on a JPanel. 我有一个单元格编辑器,由JPanel上的几个组件组成。 When my custom cell editor stops editing, the table loses focus instead of transfering focus to the next cell. 当我的自定义单元格编辑器停止编辑时,表将失去焦点,而不是将焦点转移到下一个单元格。

Here's a simple example. 这是一个简单的例子。 Type into each cell and tab through the table. 键入每个单元格并在表格中选项卡。 Notice that after visiting the 3rd column, the table loses focus to another text field on the panel. 请注意,在访问第3列后,表将失去焦点到面板上的另一个文本字段。

Update: This issue appears to be fixed in Java7. 更新:此问题似乎在Java7中得到修复。 The example must be run with Java 6 to see the focus lost behavior. 必须使用Java 6运行该示例才能查看焦点丢失行为。

import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.AbstractCellEditor;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;
import javax.swing.text.JTextComponent;


public class TableEditorFocusExample extends JFrame
{

   private JTable m_table;
   private TableModel tableModel;


   public TableEditorFocusExample()
   {
       setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

       Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
       {

           @Override
           public void eventDispatched( AWTEvent event )
           {
               System.out.println( "FOCUS " + 
                                   event + 
                                   "\n   source=" + 
                                   event.getSource() );
           }
       }, AWTEvent.FOCUS_EVENT_MASK | AWTEvent.WINDOW_FOCUS_EVENT_MASK );

       tableModel = new DefaultTableModel( 4, 4 );
       m_table = new JTable( tableModel )
       {
           @Override
           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();
                   if ( editor instanceof JTextComponent )
                   {
                       ( (JTextComponent)editor ).selectAll();
                   }
               }
           }

       };

       m_table.setModel( tableModel );
       m_table.setSurrendersFocusOnKeystroke( true );
       m_table.putClientProperty( "terminateEditOnFocusLost", Boolean.TRUE ); //$NON-NLS-1$    

       DefaultCellEditor textFieldCellEditor = new DefaultCellEditor( new JTextField() );
       textFieldCellEditor.setClickCountToStart( 1 );

       TableCellEditor panelBasedCellEditor = new PanelCellEditor();

       m_table.getColumnModel().getColumn( 0 ).setCellEditor( textFieldCellEditor );
       m_table.getColumnModel().getColumn( 1 ).setCellEditor( textFieldCellEditor );
       m_table.getColumnModel().getColumn( 2 ).setCellEditor( panelBasedCellEditor );
       m_table.getColumnModel().getColumn( 3 ).setCellEditor( textFieldCellEditor );
       m_table.setColumnSelectionAllowed( true );

       final JButton ok = new JButton( "reset" );

       JPanel panel = new JPanel();
       panel.add( m_table );

       // add a component to grab focus when the table editor loses focus 
       final JTextField textField = new JTextField( 8 );
       final Color origTextColor = textField.getBackground();
       textField.addFocusListener( new FocusAdapter()
       {
           @Override
           public void focusGained( FocusEvent e )
           {
               System.err.println( "focus gained from: " + e.getSource() );
               textField.setBackground( Color.red );
           }
       } );

       // reset the text field background color to the pre-focus color
       ok.addActionListener( new ActionListener()
       {
           @Override
           public void actionPerformed( ActionEvent e )
           {
               textField.setBackground( origTextColor );
           }
       } );

       panel.add( textField );
       panel.add( ok );

       getContentPane().add( panel );
   }


   public class PanelCellEditor extends AbstractCellEditor implements
           TableCellEditor
   {
       public PanelCellEditor()
       {
           m_textfield.setBackground( Color.green );

           m_panel = new JPanel( new GridLayout() )
           {
               @Override
               public boolean requestFocusInWindow()
               {
                   // when the table transfers focus to the editor,
                   // forward focus onto the text field.
                   return m_textfield.requestFocusInWindow();
               }
           };

           m_panel.add( m_textfield );
       }


       @Override
       public Object getCellEditorValue()
       {
           return m_textfield.getText();
       }


       @Override
       public Component getTableCellEditorComponent(
               JTable table,
               Object value,
               boolean isSelected,
               int row,
               int column )
       {
           m_textfield.setText( value == null ? "" : value.toString() );
           return m_panel;
       }


       private JPanel m_panel;
       private JTextField m_textfield = new JTextField( 5 );
   }


   public static void main( String[] args )
   {
       EventQueue.invokeLater( new Runnable()
       {

           @Override
           public void run()
           {
               TableEditorFocusExample test = new TableEditorFocusExample();
               test.setSize( 600, 300 );
               test.setVisible( true );
           }
       } );
   }
}

I found a similar question here , but the solution seems to be incomplete since the text field on the custom editor doesn't have focus, its cursor doesn't display making it unclear to the user that the field is available for text entry. 我在这里找到了一个类似的问题,但解决方案似乎不完整,因为自定义编辑器上的文本字段没有焦点,它的光标不显示,使用户不清楚该字段是否可用于文本输入。

Anyone have a better solution? 谁有更好的解决方案?

nice digging :-) 很好的挖掘:-)

For jdk6 you might consider using SwingX and its JXTable which has that problem fixed (just checked, forgot we had worked around some focus issues :-). 对于jdk6,您可以考虑使用SwingX及其JXTable修复该问题(刚检查过,忘记了我们已经解决了一些焦点问题:-)。 Or, if that's not an option, look at its code and copy the overridden transferFocus (and related) methods and the improved EditorRemover. 或者,如果这不是一个选项,请查看其代码并复制重写的transferFocus(及相关)方法和改进的EditorRemover。

And don't forget to make your editor comply to its contract: 不要忘记让编辑遵守合同:

       Action action = new AbstractAction() {

        @Override
        public void actionPerformed(ActionEvent e) {
            stopCellEditing();
        }

       };
       m_textfield.setAction(action);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM