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

时间:2018-05-09 15:15:17

标签: java swing jtable jdialog tablecelleditor

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

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

现在问题开始了;-)

我们无法将第一个键入的字符“转发”到对话框。 堆栈溢出有很多例子,这个问题在自定义CellEditor中得到解决,自定义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( p.x, p.y + 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 ); } } 直接显示在表(单元格)中,例如:Losing first character in JTable panel based cell editor

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

$index = array_search(count_chars($content), array_map('count_chars', $fruits));

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

1 个答案:

答案 0 :(得分:1)

我甚至无法弄清楚角色是如何附加到文本区域的。我尝试了大约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(p.x, p.y + editorComponent.getSize().height);
            popup.show();
            fireEditingStopped();
        }
    });

    currentText = value.toString();
    editorComponent.setText( currentText );
    return editorComponent;
}

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