Swing/ComboBoxFocusBorder の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/ComboBoxFocusBorder へ行く。
- Swing/ComboBoxFocusBorder の差分を削除
--- 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 --- * 概要 [#summary] `WindowsLookAndFeel`で`JComboBox`の内部アイテムに適用される点線の`FocusBorder`を非表示にし、代替として`JComboBox`自体に実線の`FocusBorder`を表示します。 #download(https://drive.google.com/uc?id=1c5v18Ay9IHqlvUQYoK72CBW4ln2OS5QXxQ) * サンプルコード [#sourcecode] #code(link){{ 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"); } }; }} * 解説 [#explanation] - `default` -- デフォルトの`WindowsLookAndFeel`で編集不可の`JComboBox`にフォーカスがある場合、内部アイテム(セルレンダラー内部)に点線の`FocusBorder`が表示される -- 点線と文字列の間隔が近く?若干うるさい感じがする --- 参考: [[JTreeのノードの文字列に余白を追加>Swing/TreeCellMargin]] - `setFocusable(false)` -- `JComboBox#setFocusable(false)`で点線は非表示になるが、フォーカスが当たらなくなる -- `JComboBox#setFocusable(false)`で点線は非表示になるがフォーカスが当たらなくなる - `setRenderer(...)` -- `DefaultListCellRenderer#getListCellRendererComponent(...)`メソッドをオーバーライドし、インデックスが`0`以下(`JComboBox`本体での内部アイテムの描画)の場合は空の`Border`を使用することで点線を非表示に設定 -- `WindowsLookAndFeel`以外では、内部アイテムに`FocusBorder`は付かないのでこのセルレンダラーは適用しない -- フォーカスが当たっているかどうかが判別しづらくなる - `paintBorder(...)` -- 上記と同様のフォーカスがあっても点線を非表示にするセルレンダラーを適用 -- `JComboBox#paintBorder(...)`をオーバーライドして別途`JComboBox`本体に`FocusBorder`を描画 ---- - `WindowsLookAndFeel`でも`UIManager.put("ComboBox.border", ...)`で`JComboBox`本体の`Border`を変更することは可能だが、内部アイテムに適用される`Border`を変更する方法は現状では存在しない? #code{{ UIManager.put("ComboBox.border", new LineBorder(Color.GRAY.brighter()) { @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { super.paintBorder(c, g, x, y, width, height); if (c.isFocusOwner()) { Graphics2D g2 = (Graphics2D) g.create(); g2.setPaint(Color.DARK_GRAY); g2.drawRect(x, y, width - 1, height - 1); g2.dispose(); } } }); }} * 参考リンク [#reference] - [[JTreeのノードの文字列に余白を追加>Swing/TreeCellMargin]] -- `JTree`の場合で、フォーカスの点線と文字列の間に余白を追加 * コメント [#comment] #comment #comment