选中时如何将颜色 arrowIcon 更改为 JMenu

How change the color arrowIcon to JMenu when it is selected

我对 JMenu 的 arrowIcon 有问题:当我将鼠标悬停在它上面时,它会失去我为其设置的颜色。

这是最小的例子

public class DemoLookAndFeel extends JFrame {

    private JMenuBar menuBar = new JMenuBar();
    private JMenu arrowMenuOne = new JMenu("Root Menu 1");
    private JMenu arrowMenuTwo = new JMenu("Root Menu 2");

    static {
        UIManager.put("MenuItem.selectionForeground", Color.MAGENTA);
        UIManager.put("MenuItem.foreground",  Color.MAGENTA);
        UIManager.put("Menu.selectionForeground", Color.MAGENTA);
        UIManager.put("Menu.foreground",  Color.MAGENTA);
    }

    public void init() {

        setJMenuBar(menuBar);

        addSubMenus(arrowMenuOne, 5);
        addSubMenus(arrowMenuTwo, 3);

        menuBar.add(arrowMenuOne);
        menuBar.add(arrowMenuTwo);

        this.setSize(800,800);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }

    public void addSubMenus(JMenu parent, int number) {
        for (int i = 1; i <= number; i++) {
            JMenu menu = new JMenu("Sub Menu " + i);
            parent.add(menu);

            addSubMenus(menu, number - 1);
            addMenuItems(menu, number);
        }
    }

    public void addMenuItems(JMenu parent, int number) {
        for (int i = 1; i <= number; i++) {
            parent.add(new JMenuItem("Item " + i));
        }
    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                DemoLookAndFeel demo = new DemoLookAndFeel();
                demo.init();
            }
        });
    }

}

请注意,此代码的某些部分取自有关堆栈溢出的其他答案。

我知道图标是用 BasiMenuUI 中的这段代码绘制的,但我仍然不明白为什么我没有得到想要的行为。

private void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh,
                                MenuItemLayoutHelper.LayoutResult lr,
                                Color foreground) {
        if (lh.getArrowIcon() != null) {
            ButtonModel model = lh.getMenuItem().getModel();
            if (model.isArmed() || (lh.getMenuItem() instanceof JMenu
                                && model.isSelected())) {
                g.setColor(foreground);
            }
            if (lh.useCheckAndArrow()) {
                lh.getArrowIcon().paintIcon(lh.getMenuItem(), g,
                        lr.getArrowRect().x, lr.getArrowRect().y);
            }
        }
    }

你能帮帮我吗?谢谢

when i mouse-over it, it loses the color that i have set for it.

这是因为 MetalLookAndFeelMetalTheme 忽略了 BasicLookAndFeel 颜色设置,如下所示。

/* @see javax/swing/plaf/metal/MetalIconFactory.java */
class MenuArrowIcon implements Icon {
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    JMenuItem b = (JMenuItem) c;
    ButtonModel model = b.getModel();

    g.translate(x, y);
    if (!model.isEnabled()) {
      g.setColor(MetalLookAndFeel.getMenuDisabledForeground());
    } else {
      if (model.isArmed() || (c instanceof JMenu && model.isSelected())) {
        g.setColor(MetalLookAndFeel.getMenuSelectedForeground());
        // use Color.MAGENTA: g.setColor(UIManager.getColor("Menu.selectedForeground"));
      } else {
        g.setColor(b.getForeground());
      }
    }
    // if (MetalUtils.isLeftToRight(b)) {
      int[] xPoints = {0, 3, 3, 0};
      int[] yPoints = {0, 3, 4, 7};
      g.fillPolygon(xPoints, yPoints, 4);
      g.drawPolygon(xPoints, yPoints, 4);
    // } else {
    //   int[] xPoints = {4, 4, 1, 1};
    //   int[] yPoints = {0, 7, 4, 3};
    //   g.fillPolygon(xPoints, yPoints, 4);
    //   g.drawPolygon(xPoints, yPoints, 4);
    // }
    g.translate(-x, -y);
  }

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

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

要更改菜单箭头图标的选择前景色,您可能需要更改 MetalTheme 或设置您自己的MenuArrowIcon:

import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.metal.*;

public class DemoLookAndFeel2 extends JFrame {
  private JMenuBar menuBar = new JMenuBar();
  private JMenu arrowMenuOne = new JMenu("Root Menu 1");
  private JMenu arrowMenuTwo = new JMenu("Root Menu 2");

  static {
    UIManager.put("MenuItem.selectionForeground", Color.MAGENTA);
    UIManager.put("MenuItem.foreground", Color.MAGENTA);
    UIManager.put("Menu.selectionForeground", Color.MAGENTA);
    UIManager.put("Menu.foreground", Color.MAGENTA);
    // or: UIManager.put("Menu.arrowIcon", new MenuArrowIcon());
  }

  public void init() {
    setJMenuBar(menuBar);
    addSubMenus(arrowMenuOne, 5);
    addSubMenus(arrowMenuTwo, 3);

    menuBar.add(arrowMenuOne);
    menuBar.add(arrowMenuTwo);

    this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    this.setSize(800, 800);
    // this.pack();
    this.setLocationRelativeTo(null);
    this.setVisible(true);
  }

  public void addSubMenus(JMenu parent, int number) {
    for (int i = 1; i <= number; i++) {
      JMenu menu = new JMenu("Sub Menu " + i);
      parent.add(menu);

      addSubMenus(menu, number - 1);
      addMenuItems(menu, number);
    }
  }

  public void addMenuItems(JMenu parent, int number) {
    for (int i = 1; i <= number; i++) {
      parent.add(new JMenuItem("Item " + i));
    }
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override public void run() {
        MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme() {
          @Override public ColorUIResource getMenuSelectedForeground() {
            return new ColorUIResource(Color.MAGENTA);
          };
        });
        DemoLookAndFeel2 demo = new DemoLookAndFeel2();
        demo.init();
      }
    });
  }
}