作为JTable-CellEditor的JTextArea-Dialog错过了第一个输入的字符

我们需要一个用于JTableCellEditor来编辑大型多行文本。 我们尝试使用一个可视化扩展TableCell的弹出TableCell ,它将细胞重叠到右边和底部。 如果电池位于右下角,屏幕边界附近等,则会导致各种问题。

然后我们决定使用模态JDialog来编辑单元格值。 因此用户可以移动对话框,我们可以坚持其大小和位置。

现在问题开始了;-)

我们无法将第一个键入的字符“转发”到Dialog。 有很多关于堆栈溢出的例子,这个问题是针对自定义CellEditor解决的,它直接显示在Table(Cell)中,例如: 在基于JTable面板的单元格编辑器中丢失第一个字符

以下SSCCE(来自camickrs的回答: https ://stackoverflow.com/a/3591230/361227)显示第二个TableColumn中的第一次击键大部分时间都会丢失。

 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Frame; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.DefaultCellEditor; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; /** * Example taken from this answer: https://stackoverflow.com/a/3591230/361227 * * @author camickr */ public class TablePopupEditor extends DefaultCellEditor { private PopupDialog popup; private String currentText = ""; private JButton editorComponent1; public TablePopupEditor() { super( new JTextField() ); setClickCountToStart( 2 ); // Use a JButton as the editor component editorComponent1 = new JButton(); editorComponent1.setBackground( Color.white ); editorComponent1.setBorderPainted( false ); editorComponent1.setContentAreaFilled( false ); // Set up the dialog where we do the actual editing popup = new PopupDialog(); } @Override public Object getCellEditorValue() { return currentText; } @Override public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected, int row, int column ) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { System.out.println( "run" ); popup.setText( currentText ); Point p = editorComponent1.getLocationOnScreen(); popup.setLocation( px, py + editorComponent1.getSize().height ); popup.setVisible( true ); fireEditingStopped(); } } ); currentText = value.toString(); editorComponent1.setText( currentText ); return editorComponent1; } /* * Simple dialog containing the actual editing component */ class PopupDialog extends JDialog implements ActionListener { private JTextArea textArea; public PopupDialog() { super( (Frame) null, "Change Description", true ); textArea = new JTextArea( 5, 20 ); textArea.setLineWrap( true ); textArea.setWrapStyleWord( true ); KeyStroke keyStroke = KeyStroke.getKeyStroke( "ENTER" ); textArea.getInputMap().put( keyStroke, "none" ); JScrollPane scrollPane = new JScrollPane( textArea ); getContentPane().add( scrollPane ); JButton cancel = new JButton( "Cancel" ); cancel.addActionListener( this ); JButton ok = new JButton( "Ok" ); ok.setPreferredSize( cancel.getPreferredSize() ); ok.addActionListener( this ); JPanel buttons = new JPanel(); buttons.add( ok ); buttons.add( cancel ); getContentPane().add( buttons, BorderLayout.SOUTH ); pack(); getRootPane().setDefaultButton( ok ); } public void setText( String text ) { textArea.setText( text ); } /* * Save the changed text before hiding the popup */ @Override public void actionPerformed( ActionEvent e ) { if ( "Ok".equals( e.getActionCommand() ) ) { currentText = textArea.getText(); } textArea.requestFocusInWindow(); setVisible( false ); } } public static void main( String[] args ) { String[] columnNames = { "Item", "Description" }; Object[][] data = { { "Item 1", "Description of Item 1" }, { "Item 2", "Description of Item 2" }, { "Item 3", "Description of Item 3" } }; JTable table = new JTable( data, columnNames ); table.getColumnModel().getColumn( 1 ).setPreferredWidth( 300 ); table.setPreferredScrollableViewportSize( table.getPreferredSize() ); JScrollPane scrollPane = new JScrollPane( table ); // Use the popup editor on the second column TablePopupEditor popupEditor = new TablePopupEditor(); table.getColumnModel().getColumn( 1 ).setCellEditor( popupEditor ); JFrame frame = new JFrame( "Popup Editor Test" ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().add( scrollPane ); frame.pack(); frame.setLocationRelativeTo( null ); frame.setVisible( true ); } } 

是否有可靠的方法来捕捉第一个角色?

我甚至无法弄清楚角色是如何附加到文本区域的。 我尝试了大约200次调用编辑器,它只出现一次。 所以显然存在一些时间问题。 像这样的随机问题通常是代码未在EDT上执行的标志。

无论如何我想出了一个解决方法:

 public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected, int row, int column) { AWTEvent event = EventQueue.getCurrentEvent(); SwingUtilities.invokeLater(new Runnable() { public void run() { String append = ""; if (event.getID() == KeyEvent.KEY_PRESSED) { KeyEvent ke = (KeyEvent)event; String keyText = ke.getKeyText(ke.getKeyCode()); if (keyText.length() == 1) append += ke.getKeyChar(); } popup.setText(currentText + append); //popup.setLocationRelativeTo( editorComponent ); Point p = editorComponent.getLocationOnScreen(); popup.setLocation(px, py + editorComponent.getSize().height); popup.show(); fireEditingStopped(); } }); currentText = value.toString(); editorComponent.setText( currentText ); return editorComponent; } 

上面的代码保存了用于调用编辑器的事件。 因此,当弹出窗口显示时,它可以检查键事件并获取按下的字符。