---
category: swing
folder: TableModelEvent
title: JTableのモデルが変更されたことをイベントで受け取る
tags: [JTable, TableModelListener, TableModelEvent, JCheckBox]
author: aterai
pubdate: 2014-03-31T00:21:38+09:00
description: JTableのモデルの変更を受け取ってJTableHeaderに追加したJCheckBoxを更新します。
image: https://lh3.googleusercontent.com/-Mndxsu0wtCM/Uzg00YuVfyI/AAAAAAAACCw/HoRS9CVP_-o/s800/TableModelEvent.png
---
* 概要 [#summary]
`JTable`のモデルの変更を受け取って`JTableHeader`に追加した`JCheckBox`を更新します。

#download(https://lh3.googleusercontent.com/-Mndxsu0wtCM/Uzg00YuVfyI/AAAAAAAACCw/HoRS9CVP_-o/s800/TableModelEvent.png)

* サンプルコード [#sourcecode]
#code(link){{
class HeaderCheckBoxHandler implements TableModelListener {
  private final JTable table;
  private final int targetColumnIndex;
  public HeaderCheckBoxHandler(JTable table, int index) {
    this.table = table;
    this.targetColumnIndex = index;
  }

  @Override public void tableChanged(TableModelEvent e) {
    int vci = table.convertColumnIndexToView(targetColumnIndex);
    TableColumn column = table.getColumnModel().getColumn(vci);
    Object status = column.getHeaderValue();
    TableModel m = table.getModel();
    if (e.getType() == TableModelEvent.DELETE) {
      if (m.getRowCount() == 0) {
        column.setHeaderValue(Status.DESELECTED);
      } else if (Status.INDETERMINATE.equals(status)) {
        boolean selected = true;
        boolean deselected = true;
        for (int i = 0; i < m.getRowCount(); i++) {
          Boolean b = (Boolean) m.getValueAt(i, targetColumnIndex);
          selected &= b;
          deselected &= !b;
        }
        if (deselected) {
          column.setHeaderValue(Status.DESELECTED);
        } else if (selected) {
          column.setHeaderValue(Status.SELECTED);
        } else {
          return;
        }
      }
    } else if (e.getType() == TableModelEvent.INSERT
               && !Status.INDETERMINATE.equals(status)) {
      boolean selected = Status.DESELECTED.equals(status);
      boolean deselected = Status.SELECTED.equals(status);
      for (int i = e.getFirstRow(); i <= e.getLastRow(); i++) {
        Boolean b = (Boolean) m.getValueAt(i, targetColumnIndex);
        selected &= b;
        deselected &= !b;
      }
      if (selected && m.getRowCount() == 1) {
        column.setHeaderValue(Status.SELECTED);
      } else if (selected || deselected) {
        column.setHeaderValue(Status.INDETERMINATE);
      }
    } else if (e.getType() == TableModelEvent.UPDATE
               && e.getColumn() == targetColumnIndex) {
      if (Status.INDETERMINATE.equals(status)) {
        boolean selected = true;
        boolean deselected = true;
        for (int i = 0; i < m.getRowCount(); i++) {
          Boolean b = (Boolean) m.getValueAt(i, targetColumnIndex);
          selected &= b;
          deselected &= !b;
          if (selected == deselected) {
            return;
          }
        }
        if (deselected) {
          column.setHeaderValue(Status.DESELECTED);
        } else if (selected) {
          column.setHeaderValue(Status.SELECTED);
        } else {
          return;
        }
      } else {
        column.setHeaderValue(Status.INDETERMINATE);
      }
    }
    JTableHeader h = table.getTableHeader();
    h.repaint(h.getHeaderRect(vci));
  }
}
}}

* 解説 [#explanation]
上記のサンプルでは、`0`列目のセルの値(`boolean`)変更、行の追加、削除イベントなどを受け取って、`JTableHeader`のチェック状態を更新する`TableModelListener`を作成して、これを`TableModel#addTableModelListener(...)`で設定しています。

- 行の削除: `e.getType() == TableModelEvent.DELETE`
-- 削除によって行数が`0`になった場合は`JTableHeader`は未選択状態
-- `JTableHeader`が選択状態、または未選択状態の場合、削除によってその状態は変化しない
-- `JTableHeader`が不定状態の場合は、全行を検索して選択状態を変更するかどうかを調査する
-- `JTableHeader`が不定状態の場合は全行を検索して選択状態を変更するかどうかを調査する
- 行の追加: `e.getType() == TableModelEvent.INSERT`
-- `JTableHeader`がすでに不定状態の場合は、追加される行の選択状態にかかわらずその状態は変化しない
-- `JTableHeader`が不定状態でない場合は、追加される行と`JTableHeader`の選択状態を合わせて調査する
-- `JTableHeader`がすでに不定状態の場合は追加される行の選択状態にかかわらずその状態は変化しない
-- `JTableHeader`が不定状態でない場合は追加される行と`JTableHeader`の選択状態を合わせて調査する
- 行(`0`列目)の更新: `e.getType() == TableModelEvent.UPDATE`
-- `JTableHeader`が不定状態の場合は、全行を検索して選択状態を変更するかどうかを調査する
-- `JTableHeader`が不定状態でない場合は、この更新によって`JTableHeader`は不定状態になる
-- `JTableHeader`が不定状態の場合は全行を検索して選択状態を変更するかどうかを調査する
-- `JTableHeader`が不定状態でない場合はこの更新によって`JTableHeader`は不定状態になる

* 参考リンク [#reference]
- [[JTableHeaderにJCheckBoxを追加してセルの値を切り替える>Swing/TableHeaderCheckBox]]

* コメント [#comment]
#comment
#comment