Swing and Nimbus: заменить фон JPopupMenu (прилагается к JMenu)
Нимбус часто выглядит великолепно, но для определенных комбинаций цветов результат неоптимальный. В моем случае фон JPopupMenu
не подходит, поэтому я хочу установить его вручную.
Я на Java 7, и, что интересно, Nimbus полностью игнорирует настройку некоторых свойств в UIManager
(например, PopupMenu.background
). Поэтому мой единственный вариант - создать подкласс JPopupMenu
, который переопределяет paintComponent(...)
. Я знаю, что это противно, но, по крайней мере, это сработало.
Однако, если вы добавите JMenu
в другое меню, он введет в него собственный экземпляр JPopupMenu
, и я не мог понять, как заменить его своим собственным подклассом.
Даже присвоение встроенного экземпляра PopupMenuUI
не принесло никаких результатов. Если унаследовано непосредственно из JPopupMenu
, был вызван метод overriden paint(...)
, но неважно, что я сделал, ничего не было нарисовано. Если унаследовано от javax.swing.plaf.synth.SynthPopupMenuUI
paint
, даже не вызывается, и результат получается, если я вообще не установил собственный PopupMenuUI
.
Итак, простой вопрос: как отрегулировать цвет фона одного JPopupMenu
или (если это проще) все из них на Java 7 с помощью Nimbus как L & F?
Изменить: Пример кода
Взгляните на следующий код и результат:
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);
}
Я знаю, некоторые говорят, что вы должны использовать UIManager.put(key, value)
или UIManager.getLookAndFeelDefautls().put(key,value)
перед установкой L & F, но для меня это не приносит никаких результатов (что означает: никаких изменений в цветах по умолчанию вообще не происходит). Приведенный выше код, по крайней мере, приносит:
![First screenshot]()
То же самое (что означает ничего) происходит, если вы используете 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());
}
};
Что приносит
![SecondScreen]()
Однако это обходное решение не работает, если вы вставляете JMenu
, который сам обертывает JPopupMenu
, который вы не можете переопределить:
JMenu jmenu = new JMenu("D");
jmenu.add(new JMenuItem("E"));
menu.add(jmenu);
дает, как и ожидалось:
![Third screen]()
Вы можете получить этот JPopupMenu
с помощью JMenu.getPopupMenu()
, но вы не можете его установить. Даже переопределение этого метода в собственном подклассе JMenu
не приводит к каким-либо результатам, так как JMenu
, похоже, обращается к нему, включив экземпляр JPopupMenu
без использования getter.
Ответы
Ответ 1
-
в обоих ответах есть несколько ошибок
-
и выше, чтобы потребовать переопределения большинства UIDeafaults, которые оказали влияние на другой JComponents и его цвет (ы)
-
У Nimbus есть собственный Painter, один пример для этого...
![enter image description here]()
из кода
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);
}
}
Ответ 2
Один из способов сделать это - цвет фона отдельных JMenuItems и сделать их непрозрачными:
JMenuItem a = new JMenuItem("A");
a.setOpaque(true);
a.setBackground(Color.GREEN);
Затем дайте самому меню зеленую рамку, чтобы заполнить остальные:
menu.setBorder(BorderFactory.createLineBorder(Color.GREEN));
Там может быть легкий/более простой способ, но это сработало для меня.
Ответ 3
не вся история - но похоже, что непрозрачность меню/элементов истинно частично решает его (поскольку @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);
и т.д. для всех типов элементов, таких как radioButton/checkBox.
Это все еще оставляет верхнюю/нижнюю серое пространство - не знаю, какая часть отвечает за этот рисунок. Удаление маржи помогает при цене зажатой
// this looks not so good, but without the margins above/below are still grey
ui.put("PopupMenu.contentMargins", null);
В учебнике содержится список ключей свойств.