TITLE:JCheckBoxに不定状態のアイコンを追加する
Posted by at 2011-12-12

JCheckBoxに不定状態のアイコンを追加する

JCheckBoxの選択状態、非選択状態に加えて、不定状態を表すアイコンを追加します。
  • category: swing folder: TriStateCheckBox title: JCheckBoxに不定状態のアイコンを追加する tags: [JCheckBox, Icon, UIManager, JTableHeader, JTable] author: aterai pubdate: 2011-12-12T15:00:11+09:00 description: JCheckBoxの選択状態、非選択状態に加えて不定状態を表すアイコンを追加します。 image: https://lh6.googleusercontent.com/-Rs-vnlD35Cg/TuTNCuEvU_I/AAAAAAAABF4/IzDezx4Rq8M/s800/TriStateCheckBox.png

概要

JCheckBoxの選択状態、非選択状態に加えて不定状態を表すアイコンを追加します。
TriStateCheckBox.png

サンプルコード

#spanend
#spanadd
class TriStateCheckBox extends JCheckBox {
#spanend
  private transient TriStateActionListener listener;
  private transient Icon icon;

#spandel
**サンプルコード [#a11c010e]
#spanend
#spandel
#code{{
#spanend
#spandel
JCheckBox checkBox = new JCheckBox("TriState JCheckBox") {
#spanend
  protected TriStateActionListener listener = null;
  class TriStateActionListener implements ActionListener{
    protected Icon icon;
    public void setIcon(Icon icon) {
      this.icon = icon;
  protected TriStateCheckBox(String title) {
    super(title);
  }
#spanadd

#spanend
  public void updateStatus(Status s) {
    switch (s) {
      case SELECTED:
        setSelected(true);
        setIcon(null);
        break;
      case DESELECTED:
        setSelected(false);
        setIcon(null);
        break;
      case INDETERMINATE:
        setSelected(false);
        setIcon(icon);
        break;
      default:
        throw new AssertionError("Unknown Status");
    }
    @Override public void actionPerformed(ActionEvent e) {
      JCheckBox cb = (JCheckBox)e.getSource();
      if(!cb.isSelected()) {
        cb.setIcon(icon);
      }else if(cb.getIcon()!=null){
        cb.setIcon(null);
        cb.setSelected(false);
      }
    }
  }
#spanadd

#spanend
  @Override public void updateUI() {
    final Icon oi = getIcon();
    setIcon(null);
    removeActionListener(listener);
    setIcon(null);
    super.updateUI();
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        if(listener==null) {
          listener = new TriStateActionListener();
        }
        Icon icon = new IndeterminateIcon();
        listener.setIcon(icon);
        addActionListener(listener);
        if(oi!=null) {
          setIcon(icon);
        }
      }
    });
    listener = new TriStateActionListener();
    icon = new IndeterminateIcon();
    listener.setIcon(icon);
    addActionListener(listener);
    if (Objects.nonNull(getIcon())) {
      setIcon(icon);
    }
  }
#spandel
};
#spanend
#spandel
View in GitHub: Java, Kotlin
}
#spanend
class IndeterminateIcon implements Icon {
    private final Color color = UIManager.getColor("CheckBox.foreground");
    private final Icon icon = UIManager.getIcon("CheckBox.icon");
    @Override public void paintIcon(Component c, Graphics g, int x, int y) {
        icon.paintIcon(c, g, x, y);
        int w = getIconWidth(), h = getIconHeight();
        int a = 4, b = 2;
        Graphics2D g2 = (Graphics2D)g;
        g2.setPaint(Color.BLACK);
        g2.translate(x, y);
        g2.fillRect(a, (h-b)/2, w-a-a, b);
        g2.translate(-x, -y);
    }
    @Override public int getIconWidth()  { return icon.getIconWidth();  }
    @Override public int getIconHeight() { return icon.getIconHeight(); }
  // private  FOREGROUND = UIManager.getColor("CheckBox.foreground");
  private static final Color FOREGROUND = Color.BLACK;
  private static final int MARGIN = 4;
  private static final int HEIGHT = 2;
  private final Icon icon = UIManager.getIcon("CheckBox.icon");
#spanadd

#spanend
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.translate(x, y);
    icon.paintIcon(c, g2, 0, 0);
    g2.setPaint(FOREGROUND);
    g2.fillRect(
      MARGIN,
      (getIconHeight() - HEIGHT) / 2,
      getIconWidth() - MARGIN - MARGIN,
      HEIGHT);
    g2.dispose();
  }
#spanadd

#spanend
  @Override public int getIconWidth() {
    return icon.getIconWidth();
  }
#spanadd

#spanend
  @Override public int getIconHeight() {
    return icon.getIconHeight();
  }
}
#spanadd

#spanend
#spanadd
enum Status {
#spanend
  SELECTED, DESELECTED, INDETERMINATE
#spanadd
}
#spanend

解説

上記のサンプルでは、UIManager.getIcon("CheckBox.icon");で取得した非選択状態のチェックボックスアイコンの上に横棒を引いて不定状態のアイコンを作成しています。

解説

  • UIManager.getIcon("CheckBox.icon")で取得した非選択状態のチェックボックスアイコンの上に一本の横棒を引いて不定状態のアイコンを作成
  • JCheckBox#getIcon()nullの場合、チェックボックスは不定状態であると判定して上記の不定状態のアイコンを表示
  • 横棒の色はUIManager.getColor("CheckBox.foreground")を使用しているがLookAndFeelによっては無意味
  • JTableHeaderにJCheckBoxを追加してセルの値を切り替えるで使用するとNimbusLookAndFeelでアイコンと文字列のベースラインがずれる?
    • 文字列もImageIconにして回避
  • NimbusLookAndFeelで不定状態アイコンのフォーカスやロールオーバーが表示されない
  • 不定状態かどうかは、JCheckBox#getIcon()がnullかどうかで判断する手抜き版
  • 横棒の色はUIManager.getColor("CheckBox.foreground");を使用しているが、LnFによっては無意味
  • JTableHeaderにJCheckBoxを追加してセルの値を切り替える で使用すると、Nimbus LnF の場合だけ、アイコンと文字列のベースラインがずれる?
  • Nimbus LnF で、不定状態アイコンのフォーカスやロールオーバーが表示されない

参考リンク

参考リンク

コメント