Java Swing macOS 按钮在被选中时是灰色的而不是蓝色的

Java Swing macOS buttons are grey instead of blue when selected

我的 Swing 程序中有一个错误,当组件被选中时,JButtonJToggleButton 组件的背景为灰色而不是蓝色。这是 JToggleButton 上问题的屏幕截图,但按下 JButton.

时会出现同样的问题

我试过用

手动设置背景
button.setBackground(Color.BLUE);
button.setOpaque(true);

但这只是在按钮周围画了一个小边框:

还添加了 button.setBorderPainted(false);,它删除了边框,但也完全删除了 macOS 按钮外观 + 为文本提供了更深的背景颜色:

看起来边框 (AquaButtonBorder) 阻止了背景颜色的改变?因为简单地设置 button.setBackground(Color.BLUE); 绝对没有任何作用。

外观设置为 UIManager.getSystemLookAndFeelClassName(),但也尝试了 UIManager.getCrossPlatformLookAndFeelClassName(),但未成功。

Java 规范:运行 在 Java 11,但同样的问题在 Java 17

中仍然存在

系统规格:M1 MacBook Pro,macOS 版本 12.4

Sooo,我花了很多时间研究“Aqua”外观的源代码,我发现 AquaButtonUI 有一个“按钮类型”客户端 属性用于(除其他外)确定边框类型。

Sooo,我提取了所有内部“类型”并进行了快速测试...

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));
        }
    }
}

一般来说,我发现 bevelsegmented-only 会达到你想要的结果(虽然 segment-first/middle/last 看起来很有趣)