Java 如何使用自定义TableCellEditor通过单击选择表行?

Java 如何使用自定义TableCellEditor通过单击选择表行?,java,swing,jtable,selection,tablecelleditor,Java,Swing,Jtable,Selection,Tablecelleditor,我有一个JTable,带有一个自定义TableCellRenderer和一个自定义TableCellEditor。默认情况下,第一次单击表格行将从渲染器切换到编辑器,第二次单击选择行 是否有任何方法可以使行在单击时被选中(并切换到编辑器) 我尝试使用: table.getSelectionModel().setSelectionInterval(row, row); 在我的getTableCellEditorComponent中,它不起作用,如果我将它添加到我的gettableCellRend

我有一个
JTable
,带有一个自定义
TableCellRenderer
和一个自定义
TableCellEditor
。默认情况下,第一次单击表格行将从渲染器切换到编辑器,第二次单击选择行

是否有任何方法可以使行在单击时被选中(并切换到编辑器)

我尝试使用:

table.getSelectionModel().setSelectionInterval(row, row);
在我的
getTableCellEditorComponent
中,它不起作用,如果我将它添加到我的
gettableCellRenderComponent
中,它会起作用,但只是有时起作用

以下是一个完整的示例:

public class SelectRowDemo extends JFrame {

    public SelectRowDemo() {
        CellRendererAndEditor rendererAndEditor = new CellRendererAndEditor();
        StringTableModel model = new StringTableModel();
        JTable table = new JTable(model);
        table.setDefaultEditor(String.class, rendererAndEditor);
        table.setDefaultRenderer(String.class, rendererAndEditor);

        model.addElement("");
        model.addElement("");
        model.addElement("");

        add(new JScrollPane(table));
        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
                } catch (Exception e) {
                    e.printStackTrace();
                }

                new SelectRowDemo();
            }

        });
    }

    class CellRendererAndEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

        private final JLabel renderer = new JLabel();
        private final JLabel editor = new JLabel();

        @Override
        public Object getCellEditorValue() {
            return editor.getText();
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {

            String str = "renderer ";
            str += (isSelected) ? "selected" : "not selected";

            renderer.setText(str);
            return renderer;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value,
                boolean isSelected, int row, int column) {

            table.getSelectionModel().setSelectionInterval(row, row);

            String str = "editor ";
            str += (isSelected) ? "selected" : "not selected";

            editor.setText(str);
            return editor;
        }

    }

    class StringTableModel extends AbstractTableModel {

        private final List<String> data = new ArrayList<String>();

        @Override
        public int getColumnCount() {
            return 1;
        }

        @Override
        public int getRowCount() {
            return data.size();
        }

        @Override
        public Object getValueAt(int row, int column) {
            return data.get(row);
        }

        @Override
        public Class<?> getColumnClass(int column) {
            return String.class;
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return true;
        }

        @Override
        public void setValueAt(Object aValue, int row, int column) {
            if(aValue instanceof String) {
                data.set(row, (String)aValue);
                fireTableRowsUpdated(row, column);
            } else throw new IllegalStateException("aValue is not a String");
        }

        public void addElement(String s) {
            data.add(s);
        }

    }

}
公共类SelectRowDemo扩展JFrame{
public SelectRowDemo(){
CellRenderAndEditor RenderAndEditor=新的CellRenderAndEditor();
StringTableModel模型=新的StringTableModel();
JTable table=新的JTable(模型);
table.setDefaultEditor(String.class、RenderAndEditor);
table.setDefaultRenderer(String.class、RenderAndEditor);
模型.附录(“”);
模型.附录(“”);
模型.附录(“”);
添加(新JScrollPane(表));
包装();
setDefaultCloseOperation(关闭时退出);
setVisible(真);
}
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
试一试{
UIManager.setLookAndFeel(“javax.swing.plaf.nimbus.NimbusLookAndFeel”);
}捕获(例外e){
e、 printStackTrace();
}
新建SelectRowDemo();
}
});
}
类CellRenderAndEditor扩展AbstractCellEditor实现TableCellEditor,TableCellRenderer{
私有最终JLabel呈现程序=新JLabel();
私有最终JLabel编辑器=新JLabel();
@凌驾
公共对象getCellEditorValue(){
返回editor.getText();
}
@凌驾
公共组件GetTableCellRenderComponent(JTable表、对象值、,
布尔值(已选择,布尔值为焦点,整数行,整数列){
String str=“渲染器”;
str+=(isSelected)?“已选”:“未选”;
setText(str);
返回渲染器;
}
@凌驾
公共组件getTableCellEditorComponent(JTable表、对象值、,
布尔值(选定,int行,int列){
table.getSelectionModel().setSelectionInterval(行,行);
String str=“编辑器”;
str+=(isSelected)?“已选”:“未选”;
编辑:setText(str);
返回编辑器;
}
}
类StringTableModel扩展了AbstractTableModel{
私有最终列表数据=新的ArrayList();
@凌驾
public int getColumnCount(){
返回1;
}
@凌驾
public int getRowCount(){
返回data.size();
}
@凌驾
公共对象getValueAt(int行,int列){
返回数据.get(行);
}
@凌驾
公共类getColumnClass(int列){
返回字符串.class;
}
@凌驾
公共布尔值可编辑(int行,int列){
返回true;
}
@凌驾
public void setValueAt(对象有效、整行、整列){
if(字符串的有效实例){
数据集(行,(字符串)aValue);
fireTableRowsUpdated(行、列);
}else抛出新的非法状态异常(“aValue不是字符串”);
}
公共void addElement(字符串s){
数据。添加;
}
}
}

发生的情况是,表格UI在更改选择之前开始编辑单元格。如果在getTableCellEditor()和shouldSelectCell()中放置println,则首先调用编辑器,并使用isSelected==false,然后调用shouldSelectCell并更改选择

您可以在BasicTableUI.adjustSelection(MouseeEvent)中看到它发生的确切位置


出于渲染目的,我只需将其渲染为selected==true,因为它将在事件处理完成之前执行。

是否尝试过
XxxCellEditor#setClickCountToStart()
不应尝试在编辑器中更改选择模型(或表的任何属性)。编辑器是用来编辑的。@mKorbel:那个方法不相关。我不明白这个问题的最终目的。这是好奇心吗?如果调用了编辑器,那么显然该行已被选中。为什么编辑不能假设这一点?编辑器的目的是允许用户输入新数据,然后将数据保存在模型中。数据是否正确保存?如果您试图基于行对数据进行某种验证,那么我猜应该在编辑器的停止编辑方法中进行验证,此时我猜所选行可用。我正面临着这个问题。有人有什么解决办法吗?我无法听从建议。请你详细解释一下,我该如何应对这个问题。我已经为一个单元格创建了编辑器和渲染器。
  boolean dragEnabled = table.getDragEnabled();

            if (!dragEnabled && !isFileList && table.editCellAt(pressedRow, pressedCol, e)) {
                setDispatchComponent(e);
                repostEvent(e);
            }

            CellEditor editor = table.getCellEditor();
            if (dragEnabled || editor == null || editor.shouldSelectCell(e)) {
                table.changeSelection(pressedRow, pressedCol, 
                        BasicGraphicsUtils.isMenuShortcutKeyDown(e), 
                        e.isShiftDown());
            }