JComboBoxにJSeparatorを挿入

編集者:Terai Atsuhiro~

作成日:2005-08-29
更新日:2021-02-21 (日) 03:52:16
  • category: swing folder: ComboBoxSeparator title: JComboBoxにJSeparatorを挿入 tags: [JComboBox, JSeparator, ListCellRenderer, ItemListener, ActionMap, InputMap] author: aterai pubdate: 2005-08-29T00:43:58+09:00 description: JComboBoxに選択できないJSeparatorを挿入します。 image: https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTJt9fH4ZI/AAAAAAAAAU0/c9vovQi9Jvo/s800/ComboBoxSeparator.png

概要

JComboBoxに選択できないJSeparatorを挿入します。

概要

JComboBoxに選択できないJSeparatorを挿入します。

サンプルコード

#spanend
#spanadd
JComboBox<Object> combo = new JComboBox<>();
#spanend
#spanadd
combo.setRenderer(new DefaultListCellRenderer() {
#spanend
  @Override public Component getListCellRendererComponent(
      JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    if (value instanceof JSeparator) {
      return (Component) value;
    } else {
      return super.getListCellRendererComponent(
          list, value, index, isSelected, cellHasFocus);
    }
  }
#spanadd
});
#spanend
#spanadd
DefaultComboBoxModel model = new DefaultComboBoxModel() {
#spanend
  @Override public void setSelectedItem(Object o) {
    if (o instanceof JSeparator) {
      return;
    }
    super.setSelectedItem(o);
  }
#spanadd
};
#spanend
#spanadd
model.addElement("aaaaa");
#spanend
#spanadd
model.addElement(new JSeparator());
#spanend
#spanadd
model.addElement("bbbbb");
#spanend
#spanadd
combo.setModel(model);
#spanend
#spanadd
View in GitHub: Java, Kotlin
http://terai.xrea.jp/swing/comboboxseparator/screenshot.png

解説

  • ListCellRenderer
    • JSeparatorが選択された場合は、セル描画ComponentとしてJSeparatorを返すListCellRendererを設定
  • DefaultComboBoxModel
    • JSeparatorが選択された場合は何もしないよう、setSelectedItemメソッドをオーバーライド

サンプルコード

final ListCellRenderer lcr = combobox.getRenderer();
combobox.setRenderer(new ListCellRenderer() {
  public Component getListCellRendererComponent(JList list, Object value,
                    int index, boolean isSelected, boolean cellHasFocus) {
    if(value instanceof JSeparator) {
      return (JSeparator)value;
    }else{
      return (JLabel)lcr.getListCellRendererComponent(
                  list,value,index,isSelected,cellHasFocus);
    }
  }
});
DefaultComboBoxModel model = new DefaultComboBoxModel() {
  public void setSelectedItem(Object anObject) {
    if(!(anObject instanceof JSeparator)) {
      super.setSelectedItem(anObject);
    }
  }
};
model.addElement("aaaa");
model.addElement(new JSeparator());
model.addElement("bbb1");
combobox.setModel(model);
  • -
  • DefaultComboBoxModel#setSelectedItemメソッドをオーバーライドする代わりに、以下のようにJSeparatorが選択された場合はひとつ前のItemに戻すようなItemListenerを追加しても同様
    #spanend
    #spanadd
    combobox.addItemListener(new ItemListener() {
    #spanend
      private Object prev;
      @Override public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED) {
          Object obj = e.getItem();
          if (obj instanceof JSeparator) {
            if (prev == null) {
              prev = combobox.getItemAt(0);
            }
            combobox.setSelectedItem(prev);
          } else {
            prev = obj;
          }
        }
      }
    #spanadd
    });
    #spanend
    #spanadd
    

解説

  • ListCellRenderer
    • JSeparatorが選択された場合は、JSeparatorにキャストして返すようなListCellRendererを設定しています。
  • UpDownキーでの選択状態移動を可能にする(JSeparatorなら飛ばす)場合は、以下のようなキーストロークのアクションを設定する必要がある
    #spanend
    #spanadd
    Action up = new AbstractAction() {
    #spanend
      @Override public void actionPerformed(ActionEvent e) {
        int index = combobox.getSelectedIndex();
        if (index == 0) {
          return;
        }
        Object o = combobox.getItemAt(index - 1);
        if (o instanceof JSeparator) {
          combobox.setSelectedIndex(index - 2);
        } else {
          combobox.setSelectedIndex(index - 1);
        }
      }
    #spanadd
    };
    #spanend
    #spanadd
    Action down = new AbstractAction() {
    #spanend
      @Override public void actionPerformed(ActionEvent e) {
        int index = combobox.getSelectedIndex();
        if (index == combobox.getItemCount() - 1) {
          return;
        }
        Object o = combobox.getItemAt(index + 1);
        if (o instanceof JSeparator) {
          combobox.setSelectedIndex(index + 2);
        } else {
          combobox.setSelectedIndex(index + 1);
        }
      }
    #spanadd
    };
    #spanend
    #spanadd
    ActionMap am = combobox.getActionMap();
    #spanend
    #spanadd
    am.put("selectPrevious3", up);
    #spanend
    #spanadd
    am.put("selectNext3", down);
    #spanend
    #spanadd
    InputMap im = combobox.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    #spanend
    #spanadd
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "selectPrevious3");
    #spanend
    #spanadd
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_UP, 0), "selectPrevious3");
    #spanend
    #spanadd
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "selectNext3");
    #spanend
    #spanadd
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_DOWN, 0), "selectNext3");
    #spanend
    #spanadd
    
  • DefaultComboBoxModel
    • JSeparatorが選択された場合は何もしないよう、setSelectedItemメソッドをオーバーライドしています。

参考リンク

DefaultComboBoxModel#setSelectedItemメソッドをオーバーライドする代わりに、以下のようにJSeparatorが選択された場合はひとつ前のItemに戻すようなItemListenerを追加しても同様になります。
combobox.addItemListener(new ItemListener() {
  private Object prev;
  public void itemStateChanged(ItemEvent e) {
    if(e.getStateChange()==ItemEvent.SELECTED) {
      Object obj = e.getItem();
      if(obj instanceof JSeparator) {
        if(prev==null) prev = combobox.getItemAt(0);
        combobox.setSelectedItem(prev);
      }else{
        prev = obj;
      }
    }
  }
});

コメント