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

标签 java swing jtable jdialog tablecelleditor

我们需要一个用于 JTableCellEditor 来编辑大型多行文本。 我们尝试使用弹出窗口在视觉上扩展 TableCell,该弹出窗口与右侧和底部的单元格重叠。如果单元格位于右下角、靠近屏幕边界等,这会导致各种问题。

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

现在问题开始了;-)

我们无法将第一个输入的字符“转发”到对话框。 关于堆栈溢出的例子有很多,其中直接显示在表格(单元格)中的自定义CellEditor解决了这个问题,例如:Losing first character in JTable panel based cell editor

以下 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( 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 );
  }
}

有可靠的方法来捕获第一个字符吗?

最佳答案

我什至不知道如何将字符附加到文本区域。我尝试调用编辑器大约 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;
}

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

关于java - JTextArea-Dialog 作为 JTable-CellEditor 错过了第一个键入的字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50256757/

相关文章:

java - 用Java进行水平计算

java - 无法将数据库数据填充到 jcombobox 中

java - 想要在Java中确定自相交多边形的面积

java - CoinCounter实验室

java - 使用 MS Access 数据库中的数据填充 JTable 的代码

java - jFrame 无法正确打开或显示内容

java - JSP/Java 表问题

java - 如何在removeKeyListener之后使用addKeyListener?

java - JScrollPane 不起作用(MigLayout)

java - jList 不显示来自自定义模型的数据?