vincenzopalazzo
vincenzopalazzo

Reputation: 1645

How change the color arrowIcon to JMenu when it is selected

I have a problem with the arrowIcon of the JMenu: when i mouse-over it, it loses the color that i have set for it.

This is the minimal example

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();
            }
        });
    }

}

Please note that some parts of this code have been taken from other answers on stack overflow.

I know that the icon is painted with this code from BasiMenuUI, but still i can't understand why i am not getting the desired behaviour.

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);
            }
        }
    }

Can you please help me? thanks

Upvotes: 1

Views: 569

Answers (1)

aterai
aterai

Reputation: 9833

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

This is because MetalTheme of MetalLookAndFeel ignores BasicLookAndFeel color settings as follows.

/* @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;
  }
}

To change the selection foreground color of the menu arrow icon, you might need to change MetalTheme or set your ownMenuArrowIcon:

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();
      }
    });
  }
}

Upvotes: 2

Related Questions