代码改变世界

[Java] Header checkBox in Jtable

2018-10-19 06:44  Johnson_强生仔仔  阅读(741)  评论(0编辑  收藏  举报

     The reference is from here

     在Jtable里面我们可能会有checkbox, 而有时候我们有很多checkbox需要同时check或者同时uncheck的时候, 如果有一个总的checkbox能够同时check所以该列的所有checkbox或者同时uncheck, 就会很有用. 所以这里我用一个checkBoxHeader 的class, 去将第一栏的header变为checkbox, 并且能够完成上述功能.

 

加checkBoxHeader之前:

加checkBoxHeader之后:

 

主要加的class为checkBoxHeader

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JCheckBox;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;

/**
 * Used to create checkBox into the jTable header column
 *
 * @author Johnson
 */
public class CheckBoxHeader extends JCheckBox
   implements TableCellRenderer, MouseListener
{
   protected CheckBoxHeader rendererComponent;
   protected int column;
   protected boolean mousePressed = false;

   public CheckBoxHeader(ItemListener itemListener)
   {
      rendererComponent = this;
      rendererComponent.addItemListener(itemListener);
   }

   /**
    *
    * @param table
    * @param value
    * @param isSelected
    * @param hasFocus
    * @param row
    * @param column
    * @return
    */
   @Override
   public Component getTableCellRendererComponent(
      JTable table, Object value,
      boolean isSelected, boolean hasFocus, int row, int column)
   {
      if (table != null)
      {
         JTableHeader header = table.getTableHeader();
         if (header != null)
         {

            final Color bg = isSelected ? table.getSelectionBackground() : table.getBackground();
            rendererComponent.setForeground(table.getForeground());
            rendererComponent.setBackground(bg);
            rendererComponent.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
            rendererComponent.setHorizontalAlignment(SwingConstants.CENTER);
            header.addMouseListener(rendererComponent);
         }
      }
      setColumn(column);
      return rendererComponent;
   }

   protected void setColumn(int column)
   {
      this.column = column;
   }

   public int getColumn()
   {
      return column;
   }

   protected void handleClickEvent(MouseEvent e)
   {
      if (mousePressed)
      {
         mousePressed = false;
         JTableHeader header = (JTableHeader)(e.getSource());
         JTable tableView = header.getTable();
         TableColumnModel columnModel = tableView.getColumnModel();
         int viewColumn = columnModel.getColumnIndexAtX(e.getX());
         int checkBoxColumn = tableView.convertColumnIndexToModel(viewColumn);

         if (viewColumn == this.column && e.getClickCount() == 1 && checkBoxColumn != -1)
         {
            doClick();
         }
      }
   }

   @Override
   public void mouseClicked(MouseEvent e)
   {
      handleClickEvent(e);
      ((JTableHeader)e.getSource()).repaint();
   }

   @Override
   public void mousePressed(MouseEvent e)
   {
      mousePressed = true;
   }

   @Override
   public void mouseReleased(MouseEvent e)
   {
      // Do nothing here.
   }

   @Override
   public void mouseEntered(MouseEvent e)
   {
      // Do nothing here.
   }

   @Override
   public void mouseExited(MouseEvent e)
   {
      // Do nothing here.
   }
}

 

       这样, 我们已经建立了一个checkBoxHeader的class, 这样建一个object就可以去将Jtable的某一列的header变为checkbox了, 但是我们还需要给参数告诉它是在哪一列, 并且写logic, 去改变该列所有的其他的checkBox. 另外我们实际上是override之前有可能设置的header的类型及value, 比如上图中的header为string, value为" ". 

      加进去的话就是我们加入这几行在jtable的initialization的后面.

      

      TableColumn tc = jTable.getColumnModel().getColumn(0); // 这里看是第几列, 最好用enum去代替实际的列数
      tc.setCellEditor(jTable.getDefaultEditor(Boolean.class)); // 这一列好像可以不要? 记住千万不要加入 tc.etCellRenderer(cellRenderer), 否者会override你设置的其他checkBox的设置.
      tc.setHeaderRenderer(new CheckBoxHeader(new MyItemListener()));  // 这里就是override之前的header的类型以及value

 

      然后我们再实现MyItemListener这个函数, 在里面加入checkBoxHeader的logic, 也就是同时check或者uncheck所有的checkBox即可.

 /**
    * Listener for check the headerCheckBox
    */
   class MyItemListener implements ItemListener
   {
      /**
       *
       * @param e
       */
      public void itemStateChanged(ItemEvent e)
      {
         Object source = e.getSource();
         if (source instanceof AbstractButton == false) // 这个if好像可以不要?
         {
            return;
         }
         boolean checked = e.getStateChange() == ItemEvent.SELECTED;
         for (PathEntry eachRow : _pathTableModel.rowData)  // 这个for loop可以根据具体情况去改loop每一行或者可以有一个list去for每个元素好像更好, 最好不要用数字去代替每一行, 因为好像很不reusable. 
         {
            if (eachRow.enabled)
            {
               eachRow.checked = checked;
            }
         }
         jTable.getRowSorter().modelStructureChanged();
      }
   }