• category: swing folder: ComboBoxFocusBorder title: JComboBoxのFocusBorderの対象を内部のアイテムではなくJComboBox自体に変更する tags: [JComboBox, Focus, Border, WindowsLookAndFeel] author: aterai pubdate: 2018-06-04T15:29:53+09:00 description: WindowsLookAndFeelでJComboBoxの内部アイテムに適用される点線のFocusBorderを非表示にし、代替としてJComboBox自体に実線のFocusBorderを表示します。 image: https://drive.google.com/uc?id=1c5v18Ay9IHqlvUQYoK72CBW4ln2OS5QXxQ

概要

WindowsLookAndFeelJComboBoxの内部アイテムに適用される点線のFocusBorderを非表示にし、代替としてJComboBox自体に実線のFocusBorderを表示します。

サンプルコード

JComboBox<String> combo3 = new JComboBox<String>(model) {
  @Override public void updateUI() {
    setRenderer(null);
    super.updateUI();
    if (isWindowsLnF()) {
      setRenderer(new DefaultListCellRenderer() {
        @Override public Component getListCellRendererComponent(
            JList<?> list, Object value, int index,
            boolean isSelected, boolean cellHasFocus) {
          JLabel l = (JLabel) super.getListCellRendererComponent(
              list, value, index, isSelected, cellHasFocus);
          if (index < 0) {
            l.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
          }
          return l;
        }
      });
    }
  }
  @Override protected void paintBorder(Graphics g) {
    super.paintBorder(g);
    if (isFocusOwner() && !isPopupVisible() && isWindowsLnF()) {
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setPaint(Color.DARK_GRAY);
      g2.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
      g2.dispose();
    }
  }
  private boolean isWindowsLnF() {
    return getUI().getClass().getName().contains("WindowsComboBoxUI");
  }
};
View in GitHub: Java, Kotlin

解説

  • default
    • デフォルトのWindowsLookAndFeelで編集不可のJComboBoxにフォーカスがある場合、内部アイテム(セルレンダラー内部)に点線のFocusBorderが表示される
    • 点線と文字列の間隔が近く?、若干うるさい感じがする
  • setFocusable(false)
    • JComboBox#setFocusable(false)で点線は非表示になるが、フォーカスが当たらなくなる
  • setRenderer(...)
    • DefaultListCellRenderer#getListCellRendererComponent(...)メソッドをオーバーライドし、インデックスが0以下(JComboBox本体での内部アイテムの描画)の場合は空のBorderを使用することで点線を非表示に設定
    • フォーカスが当たっているかどうかが判別しづらくなる
  • paintBorder(...)
    • 上記と同様のフォーカスがあっても点線を非表示にするセルレンダラーを適用
    • JComboBox#paintBorder(...)をオーバーライドして、別途JComboBox本体にFocusBorderを描画

参考リンク

コメント