Swing/FocusBorder の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/FocusBorder へ行く。
- Swing/FocusBorder の差分を削除
--- category: swing folder: FocusBorder title: JTextFieldにフォーカスの有無でフチ色を変更するBorderを設定する tags: [JTextField, Focus, Border, LookAndFeel] author: aterai pubdate: 2023-10-30T00:32:37+09:00 description: JTextFieldにフォーカスが適用されたらそのフチ色を変更してハイライトするBorderを設定します。 image: https://drive.google.com/uc?id=1uxBRQ_jk5WrG6Q6E7Jqg0BaaVQFLgrYD --- * 概要 [#summary] `JTextField`にフォーカスが適用されたらそのフチ色を変更してハイライトする`Border`を設定します。 #download(https://drive.google.com/uc?id=1uxBRQ_jk5WrG6Q6E7Jqg0BaaVQFLgrYD) * サンプルコード [#sourcecode] #code(link){{ JTextField field2 = new JTextField(20) { private transient FocusListener handler; @Override public void updateUI() { removeFocusListener(handler); super.updateUI(); setOpaque(false); setBorder(new RoundedCornerBorder()); handler = new FocusBorderListener(); addFocusListener(handler); } @Override protected void paintComponent(Graphics g) { Border b = getBorder(); if (!isOpaque() && b instanceof RoundedCornerBorder) { Graphics2D g2 = (Graphics2D) g.create(); g2.setPaint(getBackground()); int w = getWidth() - 1; int h = getHeight() - 1; g2.fill(((RoundedCornerBorder) b).getBorderShape(0, 0, w, h)); g2.dispose(); } super.paintComponent(g); } }; // ... class RoundedCornerBorder extends AbstractBorder { private static final Paint ALPHA_ZERO = new Color(0x0, true); private static final int ARC = 4; @Override public void paintBorder( Component c, Graphics g, int x, int y, int width, int height) { Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Shape border = getBorderShape(x, y, width - 1, height - 1); g2.setPaint(ALPHA_ZERO); Area corner = new Area(new Rectangle2D.Double(x, y, width, height)); corner.subtract(new Area(border)); g2.fill(corner); Color borderColor; if (c.hasFocus()) { borderColor = new Color(0x4F_C1_E9); } else if (c.isEnabled()) { borderColor = Color.LIGHT_GRAY; } else { borderColor = Color.WHITE; } g2.setPaint(borderColor); g2.draw(border); g2.dispose(); } public Shape getBorderShape(int x, int y, int w, int h) { return new RoundRectangle2D.Double(x, y, w, h, ARC, ARC); } @Override public Insets getBorderInsets(Component c) { return new Insets(ARC, ARC, ARC, ARC); } @Override public Insets getBorderInsets(Component c, Insets insets) { insets.set(ARC, ARC, ARC, ARC); return insets; } } class FocusBorderListener implements FocusListener { @Override public void focusGained(FocusEvent e) { update(e.getComponent()); } @Override public void focusLost(FocusEvent e) { update(e.getComponent()); } private void update(Component c) { c.repaint(); } } }} * 解説 [#explanation] - `JTextField`に角丸の`Border`を設定 -- [[JTextFieldの角を丸める>Swing/RoundedTextField]] - この`FocusBorder`の`paintBorder(...)`メソッドをオーバーライドし、`Component#hasFocus()`の場合はフチ色を変更するよう設定 - デフォルトではフォーカスの有無でフチ色が変化しない`MetalLookAndFeel`や`WindowsLookAndFeel`の場合、`JTextField`にフォーカスが設定されたらフチを含むコンポーネント全体を再描画する`FocusListener`を追加する必要がある -- `NimbusLookAndFeel`は`FocusListener`を実装する`SynthTextFieldUI.Handler`で再描画を実行している -- `MotifLookAndFeel`は`FocusListener`ではなく`DefaultCaret#focusGained(...)`などをオーバーライドして再描画を実行している -- `MotifLookAndFeel`は`FocusListener`ではなく以下のように`DefaultCaret#focusGained(...)`などをオーバーライドして再描画を実行している #code{{ public class MotifTextUI { public static class MotifCaret extends DefaultCaret implements UIResource { @Override public void focusGained(FocusEvent e) { super.focusGained(e); getComponent().repaint(); } @Override public void focusLost(FocusEvent e) { super.focusLost(e); getComponent().repaint(); } // ... }} * 参考リンク [#reference] - [[Borderのアニメーション>Swing/RippleBorder]] - [[JComboBoxのFocusBorderの対象を内部のアイテムではなくJComboBox自体に変更する>Swing/ComboBoxFocusBorder]] - [[JTextFieldにフォーカスがある場合の背景色を設定>Swing/FocusColor]] - [[JTextFieldの角を丸める>Swing/RoundedTextField]] * コメント [#comment] #comment #comment