Home > Enterprise >  Java Swing macOS buttons are grey instead of blue when selected
Java Swing macOS buttons are grey instead of blue when selected

Time:06-04

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.

Demo of the issue on a JToggleButton

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:

first fix try

Also added button.setBorderPainted(false); which removes the border but also removes the macOS button look entirely gives the text a darker background color:

try 2, I hate my life

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)

enter image description here

  • Related