Есть ли удобный способ использовать счетчик в качестве редактора в Swing JTable?

Я имею дело с числовыми данными, которые часто редактируются в большую или меньшую сторону на 0,01*Value_of_variable, поэтому счетчик выглядит как хороший выбор по сравнению с обычной текстовой ячейкой.

Я просмотрел DefaultCellEditor, но он будет принимать только текстовые поля, поля со списком или флажки.

Есть ли удобный способ использовать спиннер?


person Uri    schedule 10.12.2009    source источник
comment
Спасибо, ребята. Я подумал, что могу создать пользовательский компонент, я просто (ошибочно) предположил, что может быть другой способ.   -  person Uri    schedule 11.12.2009


Ответы (4)


... и перезаписать метод getCellEditorValue():

class SpinnerEditor extends DefaultCellEditor
{
    private JSpinner spinner;

    public SpinnerEditor()
    {
        super( new JTextField() );
        spinner = new JSpinner(new SpinnerNumberModel(0, 0, 100, 5));
        spinner.setBorder( null );
    }

    public Component getTableCellEditorComponent(
        JTable table, Object value, boolean isSelected, int row, int column)
    {
        spinner.setValue( value );
        return spinner;
    }

    public Object getCellEditorValue()
    {
        return spinner.getValue();
    }
}
person camickr    schedule 10.12.2009
comment
Это решение имеет некоторые особенности поведения, которые могут оказаться нежелательными для многих пользователей. Когда пользователь вводит число до того, как редактор начнет редактирование, JTable сосредоточит внимание на JSpinner, а не на редакторе в JSpinner. Это означает, что текст, который только что набрал пользователь, никуда не денется. Сравните это с тем, как ведет себя DefaultCellEditor: вновь введенный ключ вставляется в ячейку после текущего значения. - person Jason; 27.01.2012
comment
-1 недопустимая реализация cellEditor, поскольку она не соответствует контракту уведомления - person kleopatra; 28.01.2012

Вот пример, который касается проблемы, которую я прокомментировал в ответе camickr. Это полный и компилируемый пример. Возьмите то, что вам нужно, и выбросьте то, что вам не нужно.

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

public class JSpinnerInTables {
    static String[] columnNames = {
        "Name","Value"
    };
    static Object[][] data = {
        {"one",1.0},
        {"two",2.0}
    };
    public static void main( String[] args ) {
        JFrame frame = new JFrame();
        JTable table = new JTable(data,columnNames);
        //table.setSurrendersFocusOnKeystroke(true);
        TableColumnModel tcm = table.getColumnModel();
        TableColumn tc = tcm.getColumn(1);
        tc.setCellEditor(new SpinnerEditor());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(table);
        frame.pack();
        frame.setVisible(true);
    }
    public static class SpinnerEditor extends DefaultCellEditor
    {
        JSpinner spinner;
        JSpinner.DefaultEditor editor;
        JTextField textField;
        boolean valueSet;

        // Initializes the spinner.
        public SpinnerEditor() {
            super(new JTextField());
            spinner = new JSpinner();
            editor = ((JSpinner.DefaultEditor)spinner.getEditor());
            textField = editor.getTextField();
            textField.addFocusListener( new FocusListener() {
                public void focusGained( FocusEvent fe ) {
                    System.err.println("Got focus");
                    //textField.setSelectionStart(0);
                    //textField.setSelectionEnd(1);
                    SwingUtilities.invokeLater( new Runnable() {
                        public void run() {
                            if ( valueSet ) {
                                textField.setCaretPosition(1);
                            }
                        }
                    });
                }
                public void focusLost( FocusEvent fe ) {
                }
            });
            textField.addActionListener( new ActionListener() {
                public void actionPerformed( ActionEvent ae ) {
                    stopCellEditing();
                }
            });
        }

        // Prepares the spinner component and returns it.
        public Component getTableCellEditorComponent(
            JTable table, Object value, boolean isSelected, int row, int column
        ) {
            if ( !valueSet ) {
                spinner.setValue(value);
            }
            SwingUtilities.invokeLater( new Runnable() {
                public void run() {
                    textField.requestFocus();
                }
            });
            return spinner;
        }

        public boolean isCellEditable( EventObject eo ) {
            System.err.println("isCellEditable");
            if ( eo instanceof KeyEvent ) {
                KeyEvent ke = (KeyEvent)eo;
                System.err.println("key event: "+ke.getKeyChar());
                textField.setText(String.valueOf(ke.getKeyChar()));
                //textField.select(1,1);
                //textField.setCaretPosition(1);
                //textField.moveCaretPosition(1);
                valueSet = true;
            } else {
                valueSet = false;
            }
            return true;
        }

        // Returns the spinners current value.
        public Object getCellEditorValue() {
            return spinner.getValue();
        }

        public boolean stopCellEditing() {
            System.err.println("Stopping edit");
            try {
                editor.commitEdit();
                spinner.commitEdit();
            } catch ( java.text.ParseException e ) {
                JOptionPane.showMessageDialog(null,
                    "Invalid value, discarding.");
            }
            return super.stopCellEditing();
        }
    }
}
person Jason    schedule 28.01.2012

Просто расширьте DefaultCellEditor и перезапишите метод getTableCellEditorComponent(), чтобы он возвращал JSpinner.

person Michael Borgwardt    schedule 10.12.2009
comment
+1 @Uri. См. также Использование других редакторов java.sun.com/docs/books/tutorial/uiswing/components/ - person ssakl; 10.12.2009

Ответ Джейсона идеален. Чтобы помочь другим, которые могут искать версию Time and Date, я отредактировал код Джейсона. Надеюсь, это поможет кому-то, как Джейсон помог мне.

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

public class SpinnerInJTable {
static String[] columnNames = {
    "Name","Time & Date"
};
static Object[][] data = {
    {"Date One",new Date(Long.decode("1397091313404"))},
    {"Date Two", new Date(Long.decode("1397001313404"))}
};
public static void main( String[] args ) {
    JFrame frame = new JFrame();
    JTable table = new JTable(data,columnNames);
    //table.setSurrendersFocusOnKeystroke(true);
    TableColumnModel tcm = table.getColumnModel();
    TableColumn tc = tcm.getColumn(1);
    tc.setCellEditor(new SpinnerEditor());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(table);
    frame.pack();
    frame.setVisible(true);
}
public static class SpinnerEditor extends DefaultCellEditor
{
    JSpinner spinner;
    JSpinner.DefaultEditor editor;
    JTextField textField;
    boolean valueSet;

    // Initializes the spinner.
    public SpinnerEditor() {
        super(new JTextField());
        spinner = new JSpinner(new SpinnerDateModel());
        editor = ((JSpinner.DateEditor)spinner.getEditor());
        textField = editor.getTextField();
        textField.addFocusListener( new FocusListener() {
            public void focusGained( FocusEvent fe ) {
                System.err.println("Got focus");
                //textField.setSelectionStart(0);
                //textField.setSelectionEnd(1);
                SwingUtilities.invokeLater( new Runnable() {
                    public void run() {
                        if ( valueSet ) {
                            textField.setCaretPosition(1);
                        }
                    }
                });
            }
            public void focusLost( FocusEvent fe ) {
            }
        });
        textField.addActionListener( new ActionListener() {
            public void actionPerformed( ActionEvent ae ) {
                stopCellEditing();
            }
        });
    }

    // Prepares the spinner component and returns it.
    public Component getTableCellEditorComponent(
        JTable table, Object value, boolean isSelected, int row, int column
    ) {
        if ( !valueSet ) {
            spinner.setValue(value);
        }
        SwingUtilities.invokeLater( new Runnable() {
            public void run() {
                textField.requestFocus();
            }
        });
        return spinner;
    }

    public boolean isCellEditable( EventObject eo ) {
        System.err.println("isCellEditable");
        if ( eo instanceof KeyEvent ) {
            KeyEvent ke = (KeyEvent)eo;
            System.err.println("key event: "+ke.getKeyChar());
            textField.setText(String.valueOf(ke.getKeyChar()));
            //textField.select(1,1);
            //textField.setCaretPosition(1);
            //textField.moveCaretPosition(1);
            valueSet = true;
        } else {
            valueSet = false;
        }
        return true;
    }

    // Returns the spinners current value.
    public Object getCellEditorValue() {
        return spinner.getValue();
    }

    public boolean stopCellEditing() {
        System.err.println("Stopping edit");
        try {
            editor.commitEdit();
            spinner.commitEdit();
        } catch ( java.text.ParseException e ) {
            JOptionPane.showMessageDialog(null,
                "Invalid value, discarding.");
        }
        return super.stopCellEditing();
    }
}

}

person Jason Edmonds    schedule 16.04.2014