【问题标题】:JTextArea-Dialog as JTable-CellEditor misses first typed characterJTextArea-Dialog 作为 JTable-CellEditor 错过了第一个键入的字符
【发布时间】:2018-10-19 18:31:09
【问题描述】:

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

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

现在问题开始了 ;-)

我们无法将第一个键入的字符“转发”到对话框。 有很多关于堆栈溢出的示例,其中针对直接显示在表格(单元格)中的自定义CellEditors 解决了这个问题,例如这里: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 );
  }
}

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

【问题讨论】:

    标签: java swing jtable jdialog tablecelleditor


    【解决方案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;
    }
    

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

    【讨论】:

    • 这个解决方案的问题是,第一个给定的字符有时会出现两次,因为正如问题内部已经说明的那样,第一次按键有时会通过。在这种情况下,我们手动附加字符并通过按键获取它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 2013-11-27
    相关资源
    最近更新 更多