英文:
LookAndFeel blocking JComboBox background change?
问题
// 无LookAndFeel:
// JComboBox 在 JFrame 调整大小后可见
import javax.swing.*;
import java.awt.*;
import static java.awt.Color.WHITE;
public class TestFrame extends JFrame {
private static final String[] ANIMALS = new String[]{"Cat", "Mouse", "Dog", "Elephant", "Bird", "Goat", "Bear"};
public TestFrame() {
setSize(600, 300);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JComboBox<String> comboBox = new JComboBox<>();
comboBox.setModel(new DefaultComboBoxModel<>(ANIMALS));
comboBox.setForeground(WHITE);
comboBox.setBackground(new Color(71, 81, 93));
comboBox.getEditor().getEditorComponent().setBackground(new Color(71, 81, 93));
comboBox.getEditor().getEditorComponent().setForeground(WHITE);
comboBox.setRenderer(new DefaultListCellRenderer() {
@Override
public void paint(Graphics g) {
setBackground(new Color(71, 81, 93));
setForeground(WHITE);
super.paint(g);
}
});
panel.add(comboBox);
add(panel);
}
public static void main(String[] args) {
new TestFrame();
}
}
// 有LookAndFeel:
import javax.swing.*;
import java.awt.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.awt.Color.WHITE;
public class TestFrame extends JFrame {
private static final String[] ANIMALS = new String[]{"Cat", "Mouse", "Dog", "Elephant", "Bird", "Goat", "Bear"};
public TestFrame() {
setSize(600, 300);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JComboBox<String> comboBox = new JComboBox<>();
comboBox.setModel(new DefaultComboBoxModel<>(ANIMALS));
comboBox.setForeground(WHITE);
comboBox.setBackground(new Color(71, 81, 93));
comboBox.getEditor().getEditorComponent().setBackground(new Color(71, 81, 93));
comboBox.getEditor().getEditorComponent().setForeground(WHITE);
comboBox.setRenderer(new DefaultListCellRenderer() {
@Override
public void paint(Graphics g) {
setBackground(new Color(71, 81, 93));
setForeground(WHITE);
super.paint(g);
}
});
panel.add(comboBox);
add(panel);
}
public static void main(String[] args) {
try {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
Logger.getLogger(TestFrame.class.getName()).log(Level.SEVERE, null, ex);
}
/* Create and display the form */
EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame();
}
});
}
}
如何在启用LookAndFeel的情况下实现对组合框的完整绘制?
<details>
<summary>英文:</summary>
The goal is to change the background of all combo box when LookAndFeel is in the main method.
But I get different results when LookAndFeel exists and not.
**Without LookAndFeel:** JComboBox is visible after JFrame resizing
[![enter image description here][1]][1]
import javax.swing.;
import java.awt.;
import static java.awt.Color.WHITE;
public class TestFrame extends JFrame {
private static final String[] ANIMALS = new String[]{"Cat", "Mouse", "Dog", "Elephant", "Bird", "Goat", "Bear"};
public TestFrame() {
setSize(600, 300);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JComboBox<String> comboBox = new JComboBox<>();
comboBox.setModel(new DefaultComboBoxModel<>(ANIMALS));
comboBox.setForeground(WHITE);
comboBox.setBackground(new Color(71, 81, 93));
comboBox.getEditor().getEditorComponent().setBackground(new Color(71, 81, 93));
comboBox.getEditor().getEditorComponent().setForeground(WHITE);
comboBox.setRenderer(new DefaultListCellRenderer() {
@Override
public void paint(Graphics g) {
setBackground(new Color(71, 81, 93));
setForeground(WHITE);
super.paint(g);
}
});
panel.add(comboBox);
add(panel);
}
public static void main(String[] args) {
new TestFrame();
}
}
**With LookAndFeel:**
[![enter image description here][2]][2]
import javax.swing.;
import java.awt.;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.awt.Color.WHITE;
public class TestFrame extends JFrame {
private static final String[] ANIMALS = new String[]{"Cat", "Mouse", "Dog", "Elephant", "Bird", "Goat", "Bear"};
public TestFrame() {
setSize(600, 300);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JComboBox<String> comboBox = new JComboBox<>();
comboBox.setModel(new DefaultComboBoxModel<>(ANIMALS));
comboBox.setForeground(WHITE);
comboBox.setBackground(new Color(71, 81, 93));
comboBox.getEditor().getEditorComponent().setBackground(new Color(71, 81, 93));
comboBox.getEditor().getEditorComponent().setForeground(WHITE);
comboBox.setRenderer(new DefaultListCellRenderer() {
@Override
public void paint(Graphics g) {
setBackground(new Color(71, 81, 93));
setForeground(WHITE);
super.paint(g);
}
});
panel.add(comboBox);
add(panel);
}
public static void main(String[] args) {
try {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
Logger.getLogger(TestFrame.class.getName()).log(Level.SEVERE, null, ex);
}
/* Create and display the form */
EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame();
}
});
}
}
How can I achieve full painting of the combo box with LookAndFeel enabled?
[1]: https://i.stack.imgur.com/0hGcf.png
[2]: https://i.stack.imgur.com/dWYUu.png
</details>
# 答案1
**得分**: 1
这里没有"禁用"或"启用"的`LookAndFeel`。您的应用程序中始终设置了一个外观。您似乎只是设置了另一个外观,而在您的情况下是**Nimbus**。然而,为了回答您的问题,**Nimbus**将`DefaultListCellRenderer`的不透明性属性设置为`false`(例如,`MetalLookAndFeel`将其设置为`true`),这就是您所展示的可视化表示的原因。您可以通过重写`DefaultListCellRenderer`的`getListCellRendererComponent`方法来解决这个问题,代码如下:
```java
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JComponent comp = (JComponent) super.getListCellRendererComponent(list,
value, index, isSelected, cellHasFocus);
list.setBackground(COMBO_COLOR);
list.setForeground(Color.WHITE);
list.setOpaque(false);
return comp;
}
您还需要将UIManagers的属性ComboBox.forceOpaque
设置为false
,代码如下:
UIManager.put("ComboBox.forceOpaque", false);
Nimbus的完整默认列表可以在此处找到。
如果需要,以下是修复问题的完整示例代码:
import java.awt.*;
import java.util.Arrays;
import javax.swing.*;
public class JComboBoxExample {
private static final Color COMBO_COLOR = new Color(71, 81, 93);
private static final String[] COMBO_DATA = {"Get back!", "Go!", "Help!", "Careful!"};
public static void main(String[] args) throws Exception {
String nimbus = Arrays.asList(UIManager.getInstalledLookAndFeels())
.stream()
.filter(i -> i.getName().equals("Nimbus"))
.findFirst()
.get()
.getClassName();
UIManager.setLookAndFeel(nimbus);
UIManager.put("ComboBox.forceOpaque", false);
JFrame jf = new JFrame();
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLocationRelativeTo(null);
MyComboBox comboBox = new MyComboBox(new DefaultComboBoxModel(COMBO_DATA));
jf.add(comboBox);
jf.pack();
}
private static class MyComboBox extends JComboBox {
public MyComboBox(DefaultComboBoxModel model) {
super(model);
setForeground(Color.WHITE);
setFont(new Font("Arial", Font.PLAIN, 30));
setPreferredSize(new Dimension(350, 50));
setRenderer(new MyRenderer());
}
}
private static class MyRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JComponent comp = (JComponent) super.getListCellRendererComponent(list,
value, index, isSelected, cellHasFocus);
list.setBackground(COMBO_COLOR);
list.setForeground(Color.WHITE);
list.setOpaque(false);
return comp;
}
}
}
运行结果如下:
顺便提一下,我通过使用NetBeans IDE的可视化调试器找到了这个解决方案。
英文:
There is no thing like a disabled or enabled LookAndFeel
. You always have a Look and feel set in your aplication. You just seem to set another LookAndFeel
, which in your case is Nimbus. However, to answer your question, Nimbus sets the DefaultListCellRenderer
's opacity-Property to false
, (MetalLookAndFeel
for example sets it to true
) which is the reason for the visual representation you are showing. You should be able to fix this by overriding the getListCellRendererComponent
method of DefaultListCellRenderer
like so:
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JComponent comp = (JComponent) super.getListCellRendererComponent(list,
value, index, isSelected, cellHasFocus);
list.setBackground(COMBO_COLOR);
list.setForeground(Color.WHITE);
list.setOpaque(false);
return comp;
}
You also have to set the UIManagers property ComboBox.forceOpaque
to false
, like so:
UIManager.put("ComboBox.forceOpaque", false);
A full list of the Nimubs defauts can be found here.
A full working example of the fixed problem if needed:
import java.awt.*;
import java.util.Arrays;
import javax.swing.*;
public class JComboBoxExample {
private static final Color COMBO_COLOR = new Color(71, 81, 93);
private static final String[] COMBO_DATA = {"Get back!", "Go!", "Help!", "Careful!"};
public static void main(String[] args) throws Exception {
String nimbus = Arrays.asList(UIManager.getInstalledLookAndFeels())
.stream()
.filter(i -> i.getName().equals("Nimbus"))
.findFirst()
.get()
.getClassName();
UIManager.setLookAndFeel(nimbus);
UIManager.put("ComboBox.forceOpaque", false);
JFrame jf = new JFrame();
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLocationRelativeTo(null);
MyComboBox comboBox = new MyComboBox(new DefaultComboBoxModel(COMBO_DATA));
jf.add(comboBox);
jf.pack();
}
private static class MyComboBox extends JComboBox {
public MyComboBox(DefaultComboBoxModel model) {
super(model);
setForeground(Color.WHITE);
setFont(new Font("Arial", Font.PLAIN, 30));
setPreferredSize(new Dimension(350, 50));
setRenderer(new MyRenderer());
}
}
private static class MyRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JComponent comp = (JComponent) super.getListCellRendererComponent(list,
value, index, isSelected, cellHasFocus);
list.setBackground(COMBO_COLOR);
list.setForeground(Color.WHITE);
list.setOpaque(false);
return comp;
}
}
}
results in:
By the way, I figured this out by using the visual debugger of the NetBeans IDE.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论