【问题标题】:JSpinner (Time) in JTableJTable中的JSpinner(时间)
【发布时间】:2012-05-16 18:35:16
【问题描述】:

我正在尝试在 JTable 中实现一个 JSpinner ,它在第一眼看起来就很好用,但是在失去单元格的焦点后,编辑的单元格被设置为“Thu Jan 01 +time+ UTC 1970”时间设置正确。如何从时间中删除日期?

这是我的坑 SpinnerEditor.class ,添加了一些 cmets。

代码:

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;
}

【问题讨论】:

    标签: java swing date jtable jspinner


    【解决方案1】:

    不容易,对于ButtonGroup中的JRadioButtons的意义,简单的JButton和JSpinner,有两种方式

    • 使用两个 JSpinners(JButton e.i. 的要求相同)和 SpinnerListModel 在这种情况下非常有希望减少 JTable 中提到的 JButton 所需的一堆代码

    此代码用于 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);
                }
            });
        }
    }
    
    • 通过在 TableCellEditor 中重新创建 JSpinner

    代码

    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);
                }
            });
        }
    }
    

    【讨论】:

      【解决方案2】:

      您混淆了编辑器和渲染器。编辑器是在编辑单元格时显示的小部件。当不再编辑单元格时,单元格渲染器用于“绘制”单元格。这一切都在this paragraph 中进行了解释。我真的建议您阅读它,因为它清楚地解释了如何执行表格渲染。

      您应该做的是为相关列使用自定义 CellRenderer,以便它使用您的日期格式化程序。

      查看this tutorial,了解有关单元格编辑器和单元格渲染器的更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-13
        • 1970-01-01
        • 1970-01-01
        • 2017-02-08
        相关资源
        最近更新 更多