• category: swing folder: BitSetCheckBoxes title: JCheckBoxの選択状態をBitSetで管理する tags: [JCheckBox, BitSet, UndoManager, UndoableEditSupport] author: aterai pubdate: 2018-03-26T16:22:10+09:00 description: 複数のJCheckBoxの選択状態をBitSetを使用して管理します。 image: https://drive.google.com/uc?id=1u_RLXjvLSINB0mb0ar_COqlBq5jbVhPByg

概要

複数のJCheckBoxの選択状態をBitSetを使用して管理します。

サンプルコード

// Long.MAX_VALUE
// 0b111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
// protected static final int BIT_LENGTH = 63;
protected static final int BIT_LENGTH = 72;
BitSet status = BitSet.valueOf(new long[] {Long.valueOf("111000111", 2)});
// ...
IntStream.range(0, BIT_LENGTH).forEach(i -> {
  JCheckBox c = new JCheckBox(Integer.toString(i), status.get(i));
  c.addActionListener(e -> {
    JCheckBox cb = (JCheckBox) e.getSource();
    BitSet newValue = status.get(0, BIT_LENGTH);
    newValue.set(i, cb.isSelected());
    undoSupport.postEdit(new StatusEdit(status, newValue));
    status = newValue;
    label.setText(print(status));
  });
  panel.add(c);
});
View in GitHub: Java, Kotlin

解説

  • JCheckBoxの選択状態をBitSetで管理
  • UndoManagerを使用したアンドゥ・リドゥはJCheckBoxの選択状態をBigIntegerで記憶し、UndoManagerを使用して元に戻したりやり直したりすると同じ
  • JCheckBoxがクリックされて値が変化した場合BitSet内のビットを2進数の形でJLabelに表示
    • BitSet#toLongArray()を使用しているのでLong.MAX_VALUEより2進数での桁数が大きくなる場合は注意が必要
    • BitSet#toLongArray()が返すlong配列は0から63ビットが存在すればインデックス064から127ビットが存在すればインデックス1と続く
    • BitSet内のビットが全て空の場合、bitSet.toLongArray().length0となり、bitSet.toLongArray()[0]ArrayIndexOutOfBoundsExceptionになる
    • bitSet.toLongArray()[0]0から63ビットのすべてにフラグが立ったlonglvが入っている場合、符号ビットにもフラグが立った状態なのでLong.toString(lv, 2)-1Lになる
      • 符号なし整数として扱うようLong.toUnsignedString(lv, 2)を使用する必要がある
// 0 から 63 ビットのすべてにフラグがある場合、bitSet.toLongArray()[0] には、
// -1L: (イメージ的?には大きすぎるが 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111)
// が入っている
private static String print(BitSet bitSet) {
  StringBuilder buf = new StringBuilder();
  for (long lv: bitSet.toLongArray()) {
    buf.insert(0, Long.toUnsignedString(lv, 2));
  }
  String b = buf.toString();
  int count = bitSet.cardinality();
  return "<html>0b" + ZEROPAD.substring(b.length()) + b + "<br/> count: " + count;
}

参考リンク

コメント