17

Nimbus 通常看起来很棒,但对于某些颜色组合,结果并不理想。就我而言, a 的背景JPopupMenu不适合,这就是我要手动设置它的原因。

我在 Java 7 上,有趣的是,Nimbus 完全忽略了UIManager(like PopupMenu.background) 中某些属性的设置。所以我唯一的选择是创建一个JPopupMenuoverrides的子类paintComponent(...)。我知道,这很糟糕,但至少它奏效了。

但是,如果您将 a 添加JMenu到另一个菜单,它会嵌入它自己的实例,JPopupMenu我无法弄清楚如何用我自己的子类替换它。

即使为嵌入式实例分配一个自己PopupMenuUI也没有带来任何结果。JPopupMenu如果调用了直接从被覆盖的方法继承的paint(...)方法,但是无论我做什么,都没有绘制任何内容。如果从 继承javax.swing.plaf.synth.SynthPopupMenuUI paint甚至没有被调用,结果是如果我根本没有设置自己PopupMenuUI的。

所以一个简单的问题是:如何JPopupMenu使用 Nimbus 作为 L&F 在 Java 7 上调整一个或(如果更容易的话)所有这些的背景颜色?

编辑:代码示例

看看下面的代码和结果:

public static void main(final String[] args) {
    try {
        UIManager.setLookAndFeel(NimbusLookAndFeel.class.getCanonicalName());
        UIManager.getLookAndFeelDefaults().put("PopupMenu.background", Color.GREEN);
        UIManager.getLookAndFeelDefaults().put("Panel.background", Color.RED);
        UIManager.getLookAndFeelDefaults().put("List.background", Color.BLUE);
    } catch (ClassNotFoundException | InstantiationException
            | IllegalAccessException | UnsupportedLookAndFeelException e) {
        e.printStackTrace();
    }
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(200,200);

    JPanel panel = new JPanel(new BorderLayout());
    panel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
    JList list = new JList();
    panel.add(list);

    frame.getContentPane().add(panel);

    JPopupMenu menu = new JPopupMenu();
    menu.add(new JMenuItem("A"));
    menu.add(new JMenuItem("B"));
    menu.add(new JMenuItem("C"));

    frame.setVisible(true);
    menu.show(frame, 50, 50);
}

我知道,有人说你应该在设置 L&F之前UIManager.put(key, value)使用or ,但对我来说这不会带来任何结果(意思是:根本没有改变默认颜色)。上面的代码至少带来了:UIManager.getLookAndFeelDefautls().put(key,value)

第一张截图

如果您使用JPopupMenu.setBackground(...). 这是因为 Nimbus 使用了一个内部绘制程序,它根据 Nimbus 的原色计算颜色并忽略组件的属性。在此示例中,您可以使用以下解决方法:

JPopupMenu menu = new JPopupMenu() {
    @Override
    public void paintComponent(final Graphics g) {
        g.setColor(Color.GREEN);
        g.fillRect(0,0,getWidth(), getHeight());
    }
};

这带来了

第二屏

JMenu但是,如果您插入一个本身包装JPopupMenu您无法覆盖的a,则此解决方法不起作用:

JMenu jmenu = new JMenu("D");
jmenu.add(new JMenuItem("E"));
menu.add(jmenu);

正如预期的那样:

第三屏

JPopupMenu您可以使用它来检索它,JMenu.getPopupMenu()但不能设置它。即使在自己的子类中重写此方法JMenu也不会带来任何结果,因为JMenu似乎在JPopupMenu不使用 getter 的情况下访问它的封装实例。

4

3 回答 3

9
  • 两个答案都有一些错误

  • 和上面提到的方法来覆盖大多数对另一个 JComponents 及其颜色产生影响的 UIDeafaults

  • Nimbus 有自己的 Painter,就是一个例子……

在此处输入图像描述

从代码

import com.sun.java.swing.Painter;
import java.awt.*;
import javax.swing.*;

public class MyPopupWithNimbus {

    public MyPopupWithNimbus() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(200, 200);
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        JList list = new JList();
        panel.add(list);
        frame.getContentPane().add(panel);
        JPopupMenu menu = new JPopupMenu();
        menu.add(new JMenuItem("A"));
        menu.add(new JMenuItem("B"));
        menu.add(new JMenuItem("C"));
        JMenu jmenu = new JMenu("D");
        jmenu.add(new JMenuItem("E"));
        menu.add(jmenu);
        frame.setVisible(true);
        menu.show(frame, 50, 50);
    }

    public static void main(String[] args) {

        try {
            for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(laf.getName())) {
                    UIManager.setLookAndFeel(laf.getClassName());
                    UIManager.getLookAndFeelDefaults().put("PopupMenu[Enabled].backgroundPainter",
                            new FillPainter(new Color(127, 255, 191)));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                MyPopupWithNimbus aa = new MyPopupWithNimbus();
            }
        });
    }
}

class FillPainter implements Painter<JComponent> {

    private final Color color;

    FillPainter(Color c) {
        color = c;
    }

    @Override
    public void paint(Graphics2D g, JComponent object, int width, int height) {
        g.setColor(color);
        g.fillRect(0, 0, width - 1, height - 1);
    }
}
于 2012-08-01T12:35:16.213 回答
9

一种方法是为各个 JMenuItems 的背景着色并使它们不透明:

JMenuItem a = new JMenuItem("A");
a.setOpaque(true);
a.setBackground(Color.GREEN);

然后给菜单本身一个绿色边框来填充其余部分:

menu.setBorder(BorderFactory.createLineBorder(Color.GREEN));

那里可能有一个简单/更直接的方法,但这对我有用。

于 2012-07-27T18:43:46.997 回答
7

不是全部 - 但看起来将菜单/项目的不透明度设置为 true 部分解决了它(正如@Derek Richard 已经为在完全应用程序控制下创建的项目所做的那样):

UIDefaults ui = UIManager.getLookAndFeelDefaults();
ui.put("PopupMenu.background", GREEN);
ui.put("Menu.background", GREEN);
ui.put("Menu.opaque", true);
ui.put("MenuItem.background", GREEN);
ui.put("MenuItem.opaque", true);

等等,适用于所有类型的项目,如单选按钮/复选框。

这仍然留下一个上/下灰色区域 - 不知道哪个部分负责该绘图。去除边距有助于以看起来受到挤压的代价

// this looks not so good, but without the margins above/below are still grey
ui.put("PopupMenu.contentMargins", null);

本教程中有一个属性键列表。

于 2012-07-30T09:17:43.380 回答