Q: I have changed the background color of a JFrame, and noticed that certain JComponents still paint their borders with the standard Aqua striped background. How do I make them match the JFrame containing them? A: In Java 1.4.1, various JComponents need to paint a minimal border to fill the square bounds that are left over by the control. For example, a JButton under Aqua has rounded edges, but square bounds need to be filled when adding any Component to a Container. The extraneous space is drawn in the Aqua striped pattern.
To change this, you simply set the component's background to the desired color:
JButton jb = new JButton("Push Me!");
jb.setBackground(Color.red);
The result should be an aqua button that appears to have no square border, blending with the background color of its container.
The problem that arises is with components that produce secondary components, such as a JComboBox. Embedded in a container, JComboBoxes appear as special buttons and have the same border problem that can be solved using the simple technique above. However, when clicked, JComboBoxes show a menu which will also conform to the background color set for the JComboBox. This is typically not in line with what developers wanted when trying to eliminate the borders on their controls in Aqua.
The code listing below demonstrates how one can work around this problem with JComboBoxes in particular. The simple solution involves use of a custom ListCellRenderer that fortifies the default renderer's behavior to replace the custom border background with the default Aqua striped background. The TestRenderer class does the dirty work of overriding the custom background color for cells in the JComboBox menu; the ComboBoxOverride class is the test harness to demonstrate the functionality.
Listing 1. TestRenderer.java
|
// TestRenderer class allows you to paste Aqua striped background
// over whatever had been set as a border background
import javax.swing.*;
import java.awt.*;
public class TestRenderer implements ListCellRenderer {
// The original ListCellRenderer we want to override
ListCellRenderer std;
public TestRenderer (ListCellRenderer override) {
if (override == null) {
throw new NullPointerException(
"TestRenderer constructor: default renderer is null");
}
std = override;
}
// Override of getListCellRendererComponent.
// This is called by the AWT event thread to paint components.
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
// Ask the standard renderer for what it thinks is right
Component c = std.getListCellRendererComponent(list,
value,
index,
isSelected,
cellHasFocus);
if (!isSelected) {
// Set the background of the returned component to Aqua
// striped background, but only for unselected cells;
// The standard renderer functions as desired for
// highlighted cells.
c.setBackground((Color)UIManager.get("ComboBox.background"));
}
return c;
}
}
|
Listing 2. ComboBoxOverride.java
|
// Test case to demonstrate TestRenderer functionality
import java.awt.*;
import javax.swing.*;
public class ComboBoxOverride extends JFrame {
public ComboBoxOverride)( {
Color bgColor = Color.red;
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().setBackground(bgColor);
JButton b = new JButton("Hello");
JComboBox line = new JComboBox( new Object []{
"Option One",
"Option Two",
"Option Three"});
// Replace the JComboBox's renderer
// Our TestRenderer holds onto the original renderer
line.setRenderer(new TestRenderer(line.getRenderer()));
b.setBackground(bgColor);
line.setBackground(bgColor);
this.getContentPane().add(b, BorderLayout.SOUTH);
this.getContentPane().add(line, BorderLayout.NORTH);
setSize(320, 240);
setLocation(500, 500);
setVisible(true);
}
public static void main(String args[]) {
new ComboBoxOverride(true);
}
}
|
[Jul 31, 2003]
|