2014-03-02 73 views
3

我有一个3列JTable。第2列是一个复选框,我想为该行启用/禁用JSpinner。JTable与JSpinner启用/禁用

我一直在努力,除了一件事情--JSpinner看起来并不像它的残疾人(文本和微调按钮变灰)。我不太清楚如何实现这一点。我试着在JSpinner上强制调用setEnabled(false),但表似乎没有正确重画。

下面是一些代码,我已经得到了通过其他StackOverflow的实例工作:

import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.util.EventObject; 

import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JSpinner; 
import javax.swing.JTable; 
import javax.swing.WindowConstants; 
import javax.swing.event.CellEditorListener; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellEditor; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumn; 

public class SpinnerTable { 
    public JComponent makeUI() { 
     String[] columnNames = { "Name", "Spinner Enable", "Spinner" }; 
     final Object[][] data = { { "aaa", true, 1 }, { "bbb", true, 10 }, 
       { "ccc", true, 10 } }; 

     final DefaultTableModel model = new DefaultTableModel(data, columnNames) { 
      @Override 
      public Class<?> getColumnClass(int column) { 
       return getValueAt(0, column).getClass(); 
      } 
     }; 
     JTable table = new JTable(model) { 

      @Override 
      public void setValueAt(Object aValue, int row, int column) { 
       super.setValueAt(aValue, row, column); 

      } 

      @Override 
      public boolean isCellEditable(int row, int column) { 

       if (column == 2) 
        return (Boolean) model.getValueAt(row, 1); 

       return super.isCellEditable(row, column); 
      } 

     }; 

     table.setRowHeight(36); 
     table.setAutoCreateRowSorter(true); 
     TableColumn column = table.getColumnModel().getColumn(2); 
     column.setCellRenderer(new ComboBoxCellRenderer()); 
     column.setCellEditor(new ComboBoxCellEditor()); 

     return new JScrollPane(table); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 

    public static void createAndShowGUI() { 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     f.getContentPane().add(new SpinnerTable().makeUI()); 
     f.setSize(320, 240); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 
} 

class SpinnerPanel extends JPanel { 
    protected JSpinner spinner = new JSpinner() { 
     @Override 
     public Dimension getPreferredSize() { 
      Dimension d = super.getPreferredSize(); 
      return new Dimension(40, d.height); 
     } 
    }; 

    public SpinnerPanel() { 
     super(); 
     setOpaque(true); 
     add(spinner); 
    } 
} 

class ComboBoxCellRenderer extends SpinnerPanel implements TableCellRenderer { 
    public ComboBoxCellRenderer() { 
     super(); 
     setName("Table.cellRenderer"); 
    } 

    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, 
      boolean isSelected, boolean hasFocus, int row, int column) { 
     setBackground(isSelected ? table.getSelectionBackground() : table 
       .getBackground()); 
     if (value != null) { 
      spinner.setValue(value); 
     } 
     return this; 
    } 
} 

class ComboBoxCellEditor extends SpinnerPanel implements TableCellEditor { 
    public ComboBoxCellEditor() { 
     super(); 
     spinner.addChangeListener(new ChangeListener() { 

      @Override 
      public void stateChanged(ChangeEvent e) { 
       fireEditingStopped(); 

      } 
     }); 
     addMouseListener(new MouseAdapter() { 
      @Override 
      public void mousePressed(MouseEvent e) { 
       fireEditingStopped(); 
      } 
     }); 
    } 

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

    // Copid from DefaultCellEditor.EditorDelegate 
    @Override 
    public Object getCellEditorValue() { 
     return spinner.getValue(); 
    } 

    @Override 
    public boolean shouldSelectCell(EventObject anEvent) { 
     if (anEvent instanceof MouseEvent) { 
      MouseEvent e = (MouseEvent) anEvent; 
      return e.getID() != MouseEvent.MOUSE_DRAGGED; 
     } 
     return true; 
    } 

    @Override 
    public boolean stopCellEditing() { 
     fireEditingStopped(); 
     return true; 
    }; 

    transient protected ChangeEvent changeEvent = null; 

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

    @Override 
    public void cancelCellEditing() { 
     fireEditingCanceled(); 
    } 

    @Override 
    public void addCellEditorListener(CellEditorListener l) { 
     listenerList.add(CellEditorListener.class, l); 
    } 

    @Override 
    public void removeCellEditorListener(CellEditorListener l) { 
     listenerList.remove(CellEditorListener.class, l); 
    } 

    public CellEditorListener[] getCellEditorListeners() { 
     return listenerList.getListeners(CellEditorListener.class); 
    } 

    protected void fireEditingStopped() { 
     // Guaranteed to return a non-null array 
     Object[] listeners = listenerList.getListenerList(); 
     // Process the listeners last to first, notifying 
     // those that are interested in this event 
     for (int i = listeners.length - 2; i >= 0; i -= 2) { 
      if (listeners[i] == CellEditorListener.class) { 
       // Lazily create the event: 
       if (changeEvent == null) 
        changeEvent = new ChangeEvent(this); 
       ((CellEditorListener) listeners[i + 1]) 
         .editingStopped(changeEvent); 
      } 
     } 
    } 

    protected void fireEditingCanceled() { 
     // Guaranteed to return a non-null array 
     Object[] listeners = listenerList.getListenerList(); 
     // Process the listeners last to first, notifying 
     // those that are interested in this event 
     for (int i = listeners.length - 2; i >= 0; i -= 2) { 
      if (listeners[i] == CellEditorListener.class) { 
       // Lazily create the event: 
       if (changeEvent == null) 
        changeEvent = new ChangeEvent(this); 
       ((CellEditorListener) listeners[i + 1]) 
         .editingCanceled(changeEvent); 
      } 
     } 
    } 
} 

回答

4

该表不知道它应该重新绘制细胞在列2时,第1栏被修改。您可以通过手动启动更新来通知表格。例如,扩展模型的setValueAt()

@Override 
public void setValueAt(Object aValue, int row, int column) { 
    super.setValueAt(aValue, row, column); 
    if (column == 1) 
     fireTableRowsUpdated(row, row); 
} 

这将禁用编辑和微调将成为不可编辑。如果你需要真正的视觉禁用微调的话,您可以启用渲染器内/禁用基于isCellEditable微调,即:

spinner.setEnabled(table.isCellEditable(row, column)); 

注意,在当前的实现,则延长JTable实现isCellEditablesetValueAt。这些应该真的是模型的一部分。

+0

fireTableRowsUpdated(row,row);不需要关注DefaultTableModel,那么这个通知器被调用两次 – mKorbel

+0

@dubdubdubdot移动所有东西,从JTable到DefaultTableModel – mKorbel

+0

的每条代码行都将简单的微调器放到了渲染器上,而JPanel是无用的,或者还有另一个选项所有的JComponents到JPanel,[那么将有一列的JTable](http://stackoverflow.com/a/15090127/714968) – mKorbel