【问题标题】:Custom CellEditor with JScrollPane - start editing issue带有 JScrollPane 的自定义 CellEditor - 开始编辑问题
【发布时间】:2014-11-15 01:16:24
【问题描述】:

我有一个带有自定义 CellEditor 的 JTable,它使用 JScrollPane 中的 JTextArea。当我通过鼠标单击进入编辑模式时,它工作得很好。但是,当我尝试在单元格聚焦时键入一些字母时,什么也没有发生。单元格获得“编辑模式样式”(背景更改),但保持为空...

有什么想法吗?

public class MultiLineCellEditor extends DefaultCellEditor {

    JTextArea textArea;
    JScrollPane scrollPane;

    public MultiLineCellEditor( final JTable table ) {
        super( new JTextField() );

        getComponent().setName( "Table.editor" );
        setClickCountToStart( 2 );

        textArea = new JTextArea();

        scrollPane = new JScrollPane();
        scrollPane.setViewportView( textArea );
        editorComponent = scrollPane;

    }//end MultiLineCellEditor


    public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected,
                                                  int row, int column ) {
        this.setValue( value );
        scrollPane.setBorder( new LineBorder( Color.black ) );
        return scrollPane;
    }


    public void setValue( Object value ) {
        textArea.setText( ( value != null ) ? value.toString() : "" );
    }


    public Object getCellEditorValue() {
        return textArea.getText();
    }

}//end class

【问题讨论】:

  • 如需尽快获得更好的帮助,请发帖SSCCE
  • 也可以考虑TablePopupEditor
  • 这是一个无效的 cellEditor 实现:它必须在终止编辑时通知其侦听器

标签: java swing jtable jscrollpane jtextarea


【解决方案1】:

这是我的测试代码:

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

public class MultiLineCellEditorTest {
  public JComponent makeUI() {
    String[] columnNames = {"JTextField", "JTextArea"};
    Object[][] data = {
      {"aaa", "JTextArea+JScrollPane\nCtrl-Enter: stopCellEditing"},
      {"bbb", "ggg"}, {"ccccDDD", "hhh\njjj\nkkk"}
    };
    TableModel model = new DefaultTableModel(data, columnNames) {
      @Override public Class<?> getColumnClass(int column) {
        return String.class;
      }
    };
    JTable table = new JTable(model) {
      @Override public void updateUI() {
        super.updateUI();
        TableColumn col = getColumnModel().getColumn(1);
        col.setCellEditor(new TextAreaCellEditor());
        col.setCellRenderer(new TextAreaCellRenderer());
      }
    };
    table.setAutoCreateRowSorter(true);
    table.setSurrendersFocusOnKeystroke(true);
    table.setRowHeight(64);
    return new JScrollPane(table);
  }
  public static void main(String... args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new MultiLineCellEditorTest().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}
class TextAreaCellRenderer implements TableCellRenderer {
  private final JTextArea textArea = new JTextArea();
  public TextAreaCellRenderer() {
    textArea.setLineWrap(true);
    textArea.setBorder(BorderFactory.createEmptyBorder(1, 5, 1, 5));
  }
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected,
      boolean hasFocus, int row, int column) {
    if (isSelected) {
      textArea.setForeground(table.getSelectionForeground());
      textArea.setBackground(table.getSelectionBackground());
    } else {
      textArea.setForeground(table.getForeground());
      textArea.setBackground(table.getBackground());
    }
    textArea.setFont(table.getFont());
    textArea.setText(Objects.toString(value, ""));
    return textArea;
  }
}
//class TextAreaCellEditor extends AbstractCellEditor implements TableCellEditor {
class TextAreaCellEditor implements TableCellEditor {
  private static final String KEY = "Stop-Cell-Editing";
  private final JScrollPane scroll;
  private final JTextArea textArea = new JTextArea();
  public TextAreaCellEditor() {
    //super();
    scroll = new JScrollPane(textArea);
    scroll.setBorder(BorderFactory.createEmptyBorder());
    textArea.setLineWrap(true);
    textArea.setBorder(BorderFactory.createEmptyBorder(1, 5, 1, 5));
    KeyStroke enter = KeyStroke.getKeyStroke(
        KeyEvent.VK_ENTER, InputEvent.CTRL_MASK);
    textArea.getInputMap(JComponent.WHEN_FOCUSED).put(enter, KEY);
    textArea.getActionMap().put(KEY, new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        stopCellEditing();
      }
    });
  }
  @Override public Object getCellEditorValue() {
    return textArea.getText();
  }
  @Override public Component getTableCellEditorComponent(
      JTable table, Object value, boolean isSelected, int row, int column) {
    System.out.println("2. getTableCellEditorComponent");
    textArea.setFont(table.getFont());
    textArea.setText(Objects.toString(value, ""));
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        textArea.setCaretPosition(textArea.getText().length());
        textArea.requestFocusInWindow();
        System.out.println("4. invokeLater: getTableCellEditorComponent");
      }
    });
    return scroll;
  }
  @Override public boolean isCellEditable(final EventObject e) {
    if (e instanceof MouseEvent) {
      return ((MouseEvent) e).getClickCount() >= 2;
    }
    System.out.println("1. isCellEditable");
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        if (e instanceof KeyEvent) {
          KeyEvent ke = (KeyEvent) e;
          char kc = ke.getKeyChar();
          if (Character.isUnicodeIdentifierStart(kc)) {
            textArea.setText(textArea.getText() + kc);
            System.out.println("3. invokeLater: isCellEditable");
          }
        }
      }
    });
    return true;
  }

  //Copid from AbstractCellEditor
  protected EventListenerList listenerList = new EventListenerList();
  transient protected ChangeEvent changeEvent = null;
  @Override public boolean shouldSelectCell(EventObject e) {
    return true;
  }
  @Override public boolean stopCellEditing() {
    fireEditingStopped();
    return true;
  }
  @Override public void cancelCellEditing() {
    fireEditingCanceled();
  }
  @Override public void addCellEditorListener(CellEditorListener l) {
    listenerList.add(CellEditorListener.class, l);
  }
  @Override public void removeCellEditorListener(CellEditorListener l) {
    listenerList.remove(CellEditorListener.class, l);
  }
  public CellEditorListener[] getCellEditorListeners() {
    return listenerList.getListeners(CellEditorListener.class);
  }
  protected void fireEditingStopped() {
    // Guaranteed to return a non-null array
    Object[] listeners = listenerList.getListenerList();
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for(int i = listeners.length-2; i>=0; i-=2) {
      if(listeners[i]==CellEditorListener.class) {
        // Lazily create the event:
        if(changeEvent == null) changeEvent = new ChangeEvent(this);
        ((CellEditorListener)listeners[i+1]).editingStopped(changeEvent);
      }
    }
  }
  protected void fireEditingCanceled() {
    // Guaranteed to return a non-null array
    Object[] listeners = listenerList.getListenerList();
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for(int i = listeners.length-2; i>=0; i-=2) {
      if(listeners[i]==CellEditorListener.class) {
        // Lazily create the event:
        if(changeEvent == null) changeEvent = new ChangeEvent(this);
        ((CellEditorListener)listeners[i+1]).editingCanceled(changeEvent);
      }
    }
  }
}

编辑:用委托代替继承

【讨论】:

  • 抽象/默认 cellRenderer 做对了一件事情(与默认渲染器相比,后者没有)——它们扩展组件。就目前而言,您的解决方案不是最理想的:它应该遵循核心示例,子类 AbstractCellEditor 和 use 一个 textArea - +1 以获得正确的通知:-)
  • @kleopatra 谢谢。我重构了上面发布的代码,用委托替换了继承。
  • 其实可以。但问题依然存在:当我双击编辑时,光标总是设置在文本的末尾,我无法用鼠标放置它。我必须使用键盘箭头...一个简单的解决方法:删除 getTableCellEditorComponent 方法中的textArea.setCaretPosition( textArea.getText().length() );
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-11
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 2020-02-13
  • 1970-01-01
相关资源
最近更新 更多