• category: swing folder: MenuArrowIcon title: JMenuのArrowIconを変更する tags: [JMenu, Icon, LookAndFeel] author: aterai pubdate: 2018-05-07T15:33:15+09:00 description: JMenuの右端に表示されるArrowIconの形状や選択色などを変更します。 image: https://drive.google.com/uc?id=1hLKnZ5Zcz3tP7v6YtwXYj0Gd8CKvno8r6w

概要

JMenuの右端に表示されるArrowIconの形状や選択色などを変更します。

サンプルコード

UIManager.put("Menu.arrowIcon", new ArrowIcon());
// or: UIManager.getLookAndFeelDefaults().put("Menu.arrowIcon", new ArrowIcon());
// ...
class ArrowIcon implements Icon {
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    Graphics2D g2 = (Graphics2D) g.create();

    if (c instanceof AbstractButton && ((AbstractButton) c).getModel().isSelected()) {
      g2.setPaint(Color.WHITE);
    } else {
      g2.setPaint(Color.GRAY);
    }

    int w = getIconWidth() / 2;
    Path2D p = new Path2D.Double();
    p.moveTo(0, 0);
    p.lineTo(w, w);
    p.lineTo(0, getIconHeight());
    p.closePath();

    g2.translate(x, y);
    g2.fill(p);
    g2.dispose();
  }

  @Override public int getIconWidth() {
    return 8;
  }

  @Override public int getIconHeight() {
    return 8;
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、UIManager.put("Menu.arrowIcon", new Icon() {...})を使用してJMenuが使用するArrowIconを変更しています。

  • Icon#paintIcon(...)メソッドをオーバーライドし、JMenuが選択されている場合は色を変更
    if (c instanceof AbstractButton && ((AbstractButton) c).getModel().isSelected()) {
      g2.setPaint(Color.WHITE);
    } else {
      g2.setPaint(Color.GRAY);
    }
    
  • WindowsLookAndFeelJMenuが選択されてサブメニューが表示されたときにArrowIconと重ならないようにアイコンの右側に余白を設定
  • NimbusLookAndFeelではUIManager.put("Menu.arrowIcon", new Icon() {...})は無効、かつJMenuBarに追加されているJMenuMenu.arrowIconが不正に表示されてしまう?
  • 以下のようにUIManager.getLookAndFeelDefaults()でアイコンを設定するとNimbusLookAndFeelでも有効だが、JMenuBarに追加されているJMenuMenu.arrowIconが不正に表示されてしまう現象は同じ
    UIManager.getLookAndFeelDefaults().put("Menu.arrowIcon", new ArrowIcon());
    
  • NimbusLookAndFeelなどの場合、個別にJMenu#putClientProperty("Nimbus.Overrides", ...)でアイコンを変更することで回避可能
  • 親がJMenuBarのコンポーネントにアイコンが設定されている場合は非表示にすることで回避可能
    class ArrowIcon implements Icon {
      @Override public void paintIcon(Component c, Graphics g, int x, int y) {
        Container parent = SwingUtilities.getUnwrappedParent(c);
        if (parent instanceof JMenuBar) {
          return;
        }
        Graphics2D g2 = (Graphics2D) g.create();
        // ...
    

参考リンク

コメント