【问题标题】:Checkbox in header of JTable renders differently with Nimbus L&FJTable 标题中的复选框与 Nimbus L&F 的呈现方式不同
【发布时间】:2012-03-10 11:44:45
【问题描述】:

我在 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 呈现的标题,但我没有得到它的方法。有什么建议吗?

【问题讨论】:

    标签: java swing jtable jcheckbox nimbus


    【解决方案1】:

    我不太确定它是否适用于所有 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();
        }
      }
    }
    

    【讨论】:

    • 谢谢@aterai。您提供的示例有效。好吧,我首先尝试了您的示例,效果很好。而且在我的源代码中,我添加了 CheckBoxIcon 并在 getTableCellRendererComponent 方法中进行了必要的更改,效果也很好。因为我只为 Nimbus 实现它,所以我没有尝试过其他 L&F。干杯
    • 嗨@aterai 您提供的答案似乎有一个问题。 if(tbl.convertColumnIndexToModel(col)==0) { l.setHorizontalAlignment(SwingConstants.CENTER); } else { l.setHorizontalAlignment(SwingConstants.LEFT); }这个块完全没有效果,因为所有的列都是中心对齐的。
    • 但是有什么办法可以解决这个问题,因为我希望复选框居中对齐但不影响左对齐的其他标题的对齐方式。
    • 感谢@aterai,LeftAlignHeaderRenderer 完成了这项工作。尽管对您的代码有一些小的建议。为每一列设置 LeftAlignHeaderRenderer 是多余的,设置一次就足够了,因为它将为所有剩余的列设置相同的渲染器。干杯。
    猜你喜欢
    • 2012-02-09
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    相关资源
    最近更新 更多