简体   繁体   English

JTable中的JSpinner(时间)

[英]JSpinner (Time) in JTable

I am trying to implement an JSpinner for time in to a JTable , it worked preaty goot at the first look but after losing the focus of the cell the edited cell is being set to "Thu Jan 01 +time+ UTC 1970" the time is being set correctly. 我试图在JTable中实现一个JSpinner的时间,乍一看它工作得很好,但是在失去单元格的焦点之后,已编辑的单元格被设置为“ Thu Jan 01 + time + UTC 1970”正确设置。 How can I remove the Date from the Time ? 如何从时间中删除日期?

here is my hole SpinnerEditor.class , have added some comments. 这是我的孔SpinnerEditor.class,添加了一些注释。

Code : 代码:

public SpinnerEditor(String timeFormat) {
    super(new JTextField());

    // Default Time I want to Display (1 Hour)
    Time date = new Time(3600000);
    SpinnerDateModel timeModel = new SpinnerDateModel(date, null, null,Calendar.MINUTE);
    spinner = new JSpinner(timeModel);
    editorDate = new JSpinner.DateEditor(spinner, timeFormat);
    spinner.setEditor(editorDate);


    editorDate = ((JSpinner.DateEditor)spinner.getEditor());
    // println result : "Thu Jan 01 01:00:00 UTC 1970"
    System.out.println(editorDate.getTextField().getValue());
    textField = editorDate.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()));
        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");
    // after stopcellEditing is called the TextField is being set with the wrong values (Thu Jan 01 01:00:00 UTC 1970)
    super.stopCellEditing();
    try {
        if( editorNumeric!=null) 
        {
            editorNumeric.commitEdit();
            spinner.commitEdit();

        }
        if( editorDate!=null)
        {
            SimpleDateFormat lFormat = new SimpleDateFormat("HH:mm");
            textField.setText((spinner.getValue() != null) ? lFormat.format(spinner.getValue()) : "");
        }

    } catch ( java.text.ParseException e ) {
        JOptionPane.showMessageDialog(null,
            "Invalid value, discarding.");
    }

    return true;
}

not easy job, meaning for JRadioButtons in the ButtonGroup, simple JButton and JSpinner, there are two ways 并非易事,对于ButtonGroup中的JRadioButtons(简单的JButton和JSpinner)而言,有两种方法

  • use two JSpinners (the same requird for JButton ei) and with SpinnerListModel that in this case is very hopefull to reduce the bunch of code required for mentioned JButton in the JTable 使用两个JSpinners(对JButton ei的要求相同)和SpinnerListModel一起使用 ,在这种情况下非常希望减少JTable中提到的JButton所需的代码

this code is for NumberInstance 该代码用于NumberInstance

import java.awt.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;

public class SpinnerColumn extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

    private static final long serialVersionUID = 1L;
    private JSpinner editSpinner, renderSpinner;
    private JTable table;
    private String[] list;
    private Border originalBorder;

    public SpinnerColumn(JTable table, int column) {
        editSpinner = new JSpinner();
        renderSpinner = new JSpinner();
        originalBorder = editSpinner.getBorder();
        editSpinner.setBorder(new LineBorder(Color.BLUE));
        this.table = table;
        table.getColumnModel().getColumn(column).setCellEditor(this);
    }

    public SpinnerColumn(String[] list, JTable table, int column) {
        editSpinner = new JSpinner();
        editSpinner.setModel(new SpinnerListModel(list));
        renderSpinner = new JSpinner();
        originalBorder = editSpinner.getBorder();
        editSpinner.setBorder(new LineBorder(Color.BLUE));
        this.list = list;
        this.table = table;
        table.getColumnModel().getColumn(column).setCellEditor(this);
    }

    @Override
    public Object getCellEditorValue() {
        return editSpinner.getValue();
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
            int row, int column) {
        if (list != null) {
            editSpinner.setValue(list[0]);
        } else {
            editSpinner.setValue(0);
        }
        if (value != null) {
            editSpinner.setValue(value);
        }
        return editSpinner;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
            boolean hasFocus, int row, int column) {
        if (hasFocus) {
            renderSpinner.setBorder(new LineBorder(Color.BLUE));
        } else {
            renderSpinner.setBorder(originalBorder);
        }
        // *** here's where we set the spinner's value
        if (value == null) {
            renderSpinner.setValue(0);
        } else {
            int intValue = ((Integer) value).intValue();
            renderSpinner.setValue(intValue);
        }
        return renderSpinner;
    }

    @Override
    public boolean isCellEditable(EventObject evt) {
        return true;
    }

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

            @Override
            public void run() {
                JFrame frame = new JFrame("SpinnerColumn");
                JPanel panel = new JPanel(new GridLayout(1, 1));
                JTable table = new JTable(5, 1);
                SpinnerColumn spinnerColumn = new SpinnerColumn(table, 0);
                table.setDefaultRenderer(Object.class, spinnerColumn);
                panel.add(table);
                frame.setContentPane(panel);
                frame.pack();
                frame.setVisible(true);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
        });
    }
}
  • by recreating JSpinner in the TableCellEditor 通过在TableCellEditor中重新创建JSpinner

code

import javax.swing.*;
import javax.swing.table.*;
import java.util.Date;
import java.util.Vector;
import java.awt.*;
import java.awt.event.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import javax.swing.UIManager.LookAndFeelInfo;

public class TableTestPanel extends JPanel {

    private static final String[] COLUMN_NAMES = {"List ID", "Expiration Date", "Status", "Date Created"};
    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy");
    private static final long serialVersionUID = 1L;

    private static class StatusPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        private JRadioButton theSingleOption;
        private JRadioButton theMarriedOption;
        private JRadioButton theDivorcedOption;

        StatusPanel() {
            super(new GridLayout(3, 1));
            setOpaque(true);
            ButtonGroup buttonGroup = new ButtonGroup();
            theSingleOption = new JRadioButton("Single");
            theSingleOption.setOpaque(false);
            add(theSingleOption);
            buttonGroup.add(theSingleOption);
            theMarriedOption = new JRadioButton("Married");
            theMarriedOption.setOpaque(false);
            add(theMarriedOption);
            buttonGroup.add(theMarriedOption);
            theDivorcedOption = new JRadioButton("Divorced");
            theDivorcedOption.setOpaque(false);
            add(theDivorcedOption);
            buttonGroup.add(theDivorcedOption);
        }

        public Status getStatus() {
            if (theMarriedOption.isSelected()) {
                return Status.MARRIED;
            } else if (theDivorcedOption.isSelected()) {
                return Status.DIVORCED;
            } else {
                return Status.SINGLE;
            }
        }

        public void setStatus(Status status) {
            if (status == Status.MARRIED) {
                theMarriedOption.setSelected(true);
            } else if (status == Status.DIVORCED) {
                theDivorcedOption.setSelected(true);
            } else {
                theSingleOption.setSelected(true);
            }
        }
    }

    private static class Status {

        static final Status SINGLE = new Status("Single");
        static final Status MARRIED = new Status("Married");
        static final Status DIVORCED = new Status("Divorced");
        private final String myName; // for debug only

        private Status(String name) {
            myName = name;
        }

        @Override
        public String toString() {
            return myName;
        }
    }

    private static class TableEntry {

        private static int instanceNumber;
        private Long theId;
        private Date theExpirationDate;
        private Status theStatus;
        private Date theCreationDate;

        TableEntry() {
            instanceNumber++;
            theId = new Long(instanceNumber);
            theExpirationDate = new Date();
            theStatus = Status.SINGLE;
            theCreationDate = new Date();
        }

        TableEntry(Long anId, Date anExpirationDate, Status aStatus, Date aCreationDate) {
            theId = anId;
            theExpirationDate = anExpirationDate;
            theStatus = aStatus;
            theCreationDate = aCreationDate;
        }

        public Long getId() {
            return theId;
        }

        public Date getExpirationDate() {
            return theExpirationDate;
        }

        public Status getStatus() {
            return theStatus;
        }

        public Date getCreationDate() {
            return theCreationDate;
        }

        public void setId(Long anId) {
            theId = anId;
        }

        public void setExpirationDate(Date anExpirationDate) {
            theExpirationDate = anExpirationDate;
        }

        public void setStatus(Status aStatus) {
            theStatus = aStatus;
        }

        public void setCreationDate(Date aCreationDate) {
            theCreationDate = aCreationDate;
        }
    }

    private static class MyTableModel extends AbstractTableModel {

        private static final long serialVersionUID = 1L;
        private Vector<Object> theEntries;

        MyTableModel() {
            theEntries = new Vector<Object>();
        }

        @SuppressWarnings("unchecked")
        public void add(TableEntry anEntry) {
            int index = theEntries.size();
            theEntries.add(anEntry);
            fireTableRowsInserted(index, index);
        }

        public void remove(int aRowIndex) {
            if (aRowIndex < 0 || aRowIndex >= theEntries.size()) {
                return;
            }
            theEntries.removeElementAt(aRowIndex);
            fireTableRowsDeleted(aRowIndex, aRowIndex);

        }

        public int getRowCount() {
            return theEntries.size();
        }

        @Override
        public String getColumnName(int column) {
            return COLUMN_NAMES[column];
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            switch (columnIndex) {
                case 0:
                    return Long.class;
                case 1:
                    return Date.class;
                case 2:
                    return Status.class;
                case 3:
                    return Date.class;
            }
            return Object.class;
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            TableEntry entry = (TableEntry) theEntries.elementAt(rowIndex);
            switch (columnIndex) {
                case 0:
                    try {
                        entry.setId(new Long(Long.parseLong(aValue.toString())));
                    } catch (NumberFormatException nfe) {
                        return;
                    }
                    break;
                case 1:
                    entry.setExpirationDate((Date) aValue);
                    break;
                case 2:
                    entry.setStatus((Status) aValue);
                    break;
                case 3:
                    entry.setCreationDate((Date) aValue);
                    break;
                default:
                    return;
            }
            fireTableCellUpdated(rowIndex, columnIndex);
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return true;
        }

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

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            TableEntry entry = (TableEntry) theEntries.elementAt(rowIndex);
            switch (columnIndex) {
                case 0:
                    return entry.getId();
                case 1:
                    return entry.getExpirationDate();
                case 2:
                    return entry.getStatus();
                case 3:
                    return entry.getCreationDate();
            }
            return null;
        }
    }

    private static class DateRenderer extends DefaultTableCellRenderer {

        private static final long serialVersionUID = 1L;

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (!(value instanceof Date)) {
                return this;
            }
            setText(DATE_FORMAT.format((Date) value));
            return this;
        }
    }

    private static class DateEditor extends AbstractCellEditor implements TableCellEditor {

        private static final long serialVersionUID = 1L;
        private JSpinner theSpinner;
        private Object value;

        DateEditor() {
            theSpinner = new JSpinner(new SpinnerDateModel());
            theSpinner.setOpaque(true);
            theSpinner.setEditor(new JSpinner.DateEditor(theSpinner, "dd/MM/yyyy"));
        }

        @Override
        public Object getCellEditorValue() {
            return theSpinner.getValue();
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            theSpinner.setValue(value);
            if (isSelected) {
                theSpinner.setBackground(table.getSelectionBackground());
            } else {
                theSpinner.setBackground(table.getBackground());
            }
            return theSpinner;
        }
    }

    private static class StatusEditor extends AbstractCellEditor implements TableCellEditor {

        private static final long serialVersionUID = 1L;
        private StatusPanel theStatusPanel;

        StatusEditor() {
            theStatusPanel = new StatusPanel();
        }

        @Override
        public Object getCellEditorValue() {
            return theStatusPanel.getStatus();
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            theStatusPanel.setStatus((Status) value);
            if (isSelected) {
                theStatusPanel.setBackground(table.getSelectionBackground());
            } else {
                theStatusPanel.setBackground(table.getBackground());
            }
            return theStatusPanel;
        }
    }

    private static class StatusRenderer extends StatusPanel implements TableCellRenderer {

        private static final long serialVersionUID = 1L;

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            setStatus((Status) value);
            if (isSelected) {
                setBackground(table.getSelectionBackground());
            } else {
                setBackground(table.getBackground());
            }
            return this;
        }
    }
    private MyTableModel theTableModel;
    private JTable theTable;

    public TableTestPanel() {
        super(new BorderLayout(0, 5));
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        theTableModel = new MyTableModel();
        theTable = new JTable(theTableModel);
        theTable.setDefaultEditor(Date.class, new DateEditor());
        theTable.setDefaultRenderer(Date.class, new DateRenderer());
        theTable.setDefaultEditor(Status.class, new StatusEditor());
        theTable.setDefaultRenderer(Status.class, new StatusRenderer());
// comment out the two preceding lines and uncomment the following one if you want a more standard editor
// theTable.setDefaultEditor(Status.class, new DefaultCellEditor(new JComboBox(new Status[]{Status.SINGLE, Status.MARRIED, Status.DIVORCED})));
        add(new JScrollPane(theTable), BorderLayout.CENTER);
        JToolBar toolBar = new JToolBar();
        toolBar.setFloatable(false);
        toolBar.add(new AbstractAction("Add new") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                theTableModel.add(new TableEntry());
                packTable();
            }
        });
        toolBar.add(new AbstractAction("Remove") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                theTableModel.remove(theTable.getSelectedRow());
            }
        });
        add(toolBar, BorderLayout.NORTH);
    }

    private void packTable() {
        TableColumnModel columnModel = theTable.getColumnModel();
        int columnCount = theTable.getColumnCount();
        int rowCount = theTable.getRowCount();
        int[][] preferredHeights = new int[columnCount][rowCount];
        TableCellRenderer renderer;
        Component comp;
        for (int col = 0; col < columnCount; col++) {
            renderer = columnModel.getColumn(col).getCellRenderer();
            if (renderer == null) {
                renderer = theTable.getDefaultRenderer(theTableModel.getColumnClass(col));
            }
            for (int row = 0; row < rowCount; row++) {
                comp = renderer.getTableCellRendererComponent(theTable, theTableModel.getValueAt(row, col), false, false, row, col);
                preferredHeights[col][row] = (int) comp.getPreferredSize().getHeight();
            }
        }
        for (int row = 0; row < rowCount; row++) {
            int pref = 0;
            for (int col = 0; col < columnCount; col++) {
                pref = Math.max(pref, preferredHeights[col][row]);
            }
            theTable.setRowHeight(row, pref);
        }
    }

    public static void main(String[] args) {
        try {
            // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if (info.getName().equals("Nimbus")) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        final JFrame frame = new JFrame("TestRadioButtonRenderer");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(new TableTestPanel());
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                frame.setSize(400, 300);
                frame.setVisible(true);
            }
        });
    }
}

You are confusing Editors and Renderers. 您会混淆编辑器和渲染器。 Editor is a widget displayed when a cell is being edited. 编辑器是在编辑单元格时显示的小部件。 When the cell is no longer edited, the cell renderer is used to "paint" the cell. 当不再编辑单元格时,将使用单元格渲染器“绘制”该单元格。 This is all explained in this paragraph . 这一切都在本段中说明。 I would really recommend you to read it, as it explains clearly how table rendering is performed. 我真的建议您阅读它,因为它清楚地说明了表呈现的执行方式。

What you should do, is use a Custom CellRenderer for the involved column so that it uses your date formatter. 您应该做的是对相关列使用自定义CellRenderer,以便它使用日期格式程序。

Take a look at this tutorial for more information on cell editors and cell renderers. 请看一下本教程 ,以获取有关单元格编辑器和单元格渲染器的更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM