4

我在 JTable 标题中有复选框,我正在使用 Nimbus L&F 并自定义标题背景,但复选框的背景采用默认的灰色背景,而不是像其他列那样自定义的背景。

以下是 CheckboxRenderer 类

public class CheckBoxHeader extends JCheckBox implements TableCellRenderer{

public CheckBoxHeader(ItemListener itemListener) {      
    addItemListener(itemListener);
    setHorizontalAlignment(SwingConstants.CENTER);
    setOpaque(true);        
}

public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {                    
        JTableHeader header = table.getTableHeader();           
        Color bg = header.getBackground();
        setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue()));     
    return this;
}

并在表中

TableColumn tc = getColumnModel().getColumn(0);  
tc.setCellEditor(getDefaultEditor(Boolean.class));  
tc.setCellRenderer(getDefaultRenderer(Boolean.class));      
((JComponent)getDefaultRenderer(Boolean.class)).setOpaque(true);        
tc.setHeaderRenderer(new CheckBoxHeader());

AFAIK 以获得它应该使用 DefaultTableCellRenderer 呈现的标题的正确呈现,但我没有得到它的方式。有什么建议么?

4

1 回答 1

4

我不太确定它是否适用于所有 LnF(仅测试 Windows 7、Java 1.7.0_03):

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class NimbusHeaderCheckBox {
  public JComponent makeUI() {
    Object[] columnNames = {Status.INDETERMINATE, "Integer", "String"};
    Object[][] data = {{true, 1, "b"}, {false, 9, "a"}, {true, 5, "c"}};
    DefaultTableModel model = new DefaultTableModel(data, columnNames) {
      @Override public Class<?> getColumnClass(int column) {
        return getValueAt(0, column).getClass();
      }
    };
    JTable table = new JTable(model);
    model.addTableModelListener(new HeaderCheckBoxHandler(table));

    TableCellRenderer r = new HeaderRenderer(table.getTableHeader(), 0);
    table.getColumnModel().getColumn(0).setHeaderRenderer(r);
    //<ins>
    TableCellRenderer leftAlign = new LeftAlignHeaderRenderer();
    table.getColumnModel().getColumn(1).setHeaderRenderer(leftAlign);
    table.getColumnModel().getColumn(2).setHeaderRenderer(leftAlign);
    //</ins>
    table.getTableHeader().setReorderingAllowed(false);
    return new JScrollPane(table);
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() { createAndShowGUI(); }
    });
  }
  public static void createAndShowGUI() {
    try {
      //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels())
        if ("Nimbus".equals(laf.getName())) UIManager.setLookAndFeel(laf.getClassName());
    } catch(Exception e) {
      e.printStackTrace();
    }
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new NimbusHeaderCheckBox().makeUI());
    frame.setSize(320, 240);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}
class HeaderRenderer extends JCheckBox implements TableCellRenderer {
  public HeaderRenderer(JTableHeader header, final int targetColumnIndex) {
    super((String)null);
    setOpaque(false);
    setFont(header.getFont());
    header.addMouseListener(new MouseAdapter() {
      @Override public void mouseClicked(MouseEvent e) {
        JTableHeader header = (JTableHeader)e.getSource();
        JTable table = header.getTable();
        TableColumnModel columnModel = table.getColumnModel();
        int vci = columnModel.getColumnIndexAtX(e.getX());
        int mci = table.convertColumnIndexToModel(vci);
        if(mci == targetColumnIndex) {
          TableColumn column = columnModel.getColumn(vci);
          Object v = column.getHeaderValue();
          boolean b = Status.DESELECTED.equals(v)?true:false;
          TableModel m = table.getModel();
          for(int i=0; i<m.getRowCount(); i++) m.setValueAt(b, i, mci);
          column.setHeaderValue(b?Status.SELECTED:Status.DESELECTED);
        }
      }
    });
  }
  @Override public Component getTableCellRendererComponent(
      JTable tbl, Object val, boolean isS, boolean hasF, int row, int col) {
    if(val instanceof Status) {
      switch((Status)val) {
      case SELECTED:
        setSelected(true); setEnabled(true); break;
      case DESELECTED:
        setSelected(false); setEnabled(true); break;
      case INDETERMINATE:
        setSelected(true); setEnabled(false); break;
      }
    } else {
      setSelected(true); setEnabled(false);
    }
    TableCellRenderer r = tbl.getTableHeader().getDefaultRenderer();
    JLabel l=(JLabel)r.getTableCellRendererComponent(tbl, null, isS, hasF, row, col);

    l.setIcon(new CheckBoxIcon(this));
    l.setText(null); //XXX Nimbus LnF ???
    ////This block has no effect at all as all the columns are center aligned
    ////(pointed out by rcnpl)
    //if(tbl.convertColumnIndexToModel(col)==0) {
    //  l.setHorizontalAlignment(SwingConstants.CENTER);
    //} else {
    //  l.setHorizontalAlignment(SwingConstants.LEFT);
    //}
    //<ins>
    l.setHorizontalAlignment(SwingConstants.CENTER);
    //</ins>
    return l;
  }
}
//<ins>
class LeftAlignHeaderRenderer implements TableCellRenderer {
  @Override public Component getTableCellRendererComponent(
    JTable t, Object v, boolean isS, boolean hasF, int row, int col) {
    TableCellRenderer r = t.getTableHeader().getDefaultRenderer();
    JLabel l=(JLabel)r.getTableCellRendererComponent(t, v, isS, hasF, row, col);
    l.setHorizontalAlignment(SwingConstants.LEFT);
    return l;
  }
}
//</ins>
enum Status { SELECTED, DESELECTED, INDETERMINATE }
class CheckBoxIcon implements Icon {
  private final JCheckBox check;
  public CheckBoxIcon(JCheckBox check) {
    this.check = check;
  }
  @Override public int getIconWidth() {
    return check.getPreferredSize().width;
  }
  @Override public int getIconHeight() {
    return check.getPreferredSize().height;
  }
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    SwingUtilities.paintComponent(
        g, check, (Container)c, x, y, getIconWidth(), getIconHeight());
  }
}
class HeaderCheckBoxHandler implements TableModelListener {
  private final JTable table;
  public HeaderCheckBoxHandler(JTable table) {
    this.table = table;
  }
  @Override public void tableChanged(TableModelEvent e) {
    if(e.getType()==TableModelEvent.UPDATE && e.getColumn()==0) {
      int mci = 0;
      int vci = table.convertColumnIndexToView(mci);
      TableColumn column = table.getColumnModel().getColumn(vci);
      Object title = column.getHeaderValue();
      if(!Status.INDETERMINATE.equals(title)) {
        column.setHeaderValue(Status.INDETERMINATE);
      } else {
        int selected = 0, deselected = 0;
        TableModel m = table.getModel();
        for(int i=0; i<m.getRowCount(); i++) {
          if(Boolean.TRUE.equals(m.getValueAt(i, mci))) {
            selected++;
          } else {
            deselected++;
          }
        }
        if(selected==0) {
          column.setHeaderValue(Status.DESELECTED);
        } else if(deselected==0) {
          column.setHeaderValue(Status.SELECTED);
        } else {
          return;
        }
      }
      table.getTableHeader().repaint();
    }
  }
}
于 2012-02-21T16:10:06.840 回答