JTable中的JSpinner(时间)

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

这是我的洞SpinnerEditor.class,添加了一些评论。

代码:

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

你让编辑和渲染器感到困惑。 编辑器是在编辑单元格时显示的小部件。 当不再编辑单元格时,单元格渲染器用于“绘制”单元格。 这一点在本段中都有解释。 我真的建议你阅读它,因为它清楚地解释了如何执行表格渲染。

您应该做的是,为所涉及的列使用Custom CellRenderer,以便它使用您的日期格式化程序。

有关单元格编辑器和单元格渲染器的更多信息,请查看本教程 。

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

  • 使用两个JSpinner(与JButton ei相同)和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 theEntries; MyTableModel() { theEntries = new Vector(); } @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); } }); } }