I have a bug in my Swing program where the background of JButton
and JToggleButton
components is grey instead of blue, when the component is selected. Here is a screenshot of the issue on a JToggleButton
, but the same issue occurs when pressing down on a JButton
.
I have tried manually setting the background with
button.setBackground(Color.BLUE);
button.setOpaque(true);
but that just paints a small border around the button:
Also added button.setBorderPainted(false);
which removes the border but also removes the macOS button look entirely gives the text a darker background color:
It looks like the border (AquaButtonBorder) blocks the background color from changing or something? Because simply setting button.setBackground(Color.BLUE);
does absolutely nothing.
The look and feel is set to UIManager.getSystemLookAndFeelClassName()
, but also tried UIManager.getCrossPlatformLookAndFeelClassName()
which was unsuccessful.
Java specifications: running on Java 11, but the same issue persists in Java 17
System specifications: M1 MacBook Pro, macOS version 12.4
CodePudding user response:
Sooo, I spent WAY to much time digging into the source code for the "Aqua" look and feel, and I found that the AquaButtonUI
has a "button type" client property which is used to (amongst a couple of other things) determine the border type.
Sooo, I pulled all the internal "types" and did a quick test...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
System.out.println(System.getProperty("user.dir"));
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private String[] keys = new String[]{
"toolbar",
"icon",
"text",
"toggle",
"combobox",
"comboboxInternal",
"comboboxEndCap",
"square",
"gradient",
"bevel",
"textured",
"roundRect",
"recessed",
"well",
"help",
"round",
"texturedRound",
"segmented-first",
"segmented-middle",
"segmented-last",
"segmented-only",
"segmentedRoundRect-first",
"segmentedRoundRect-middle",
"segmentedRoundRect-last",
"segmentedRoundRect-only",
"segmentedTexturedRounded-first",
"segmentedTexturedRounded-middle",
"segmentedTexturedRounded-last",
"segmentedTexturedRounded-only",
"segmentedTextured-first",
"segmentedTextured-middle",
"segmentedTextured-last",
"segmentedTextured-only",
"segmentedCapsule-first",
"segmentedCapsule-middle",
"segmentedCapsule-last",
"segmentedCapsule-only",
"segmentedGradient-first",
"segmentedGradient-middle",
"segmentedGradient-last",
"segmentedGradient-only",
"disclosure",
"scrollColumnSizer"
};
public TestPane() {
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new BorderLayout());
JPanel contentPane = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
for (String key : keys) {
JToggleButton btn = new JToggleButton(key);
btn.putClientProperty("JButton.buttonType", key);
contentPane.add(btn, gbc);
}
add(new JScrollPane(contentPane));
}
}
}
Generally, I found that bevel
and segmented-only
will achieve your desired result (although segment-first/middle/last
looks interesting)