Java swing Button 高亮效果因增加边框尺寸而消失

Java swing Button highlighting effect gone due to increased border size

我有一个代表库存的按钮面板,为了特别强调一个按钮,我增加了它的边框大小。然而,边框向内增加,这完全没问题,它没有掩盖鼠标悬停在按钮上时按钮的高亮效果。有什么方法可以让按钮高亮效果在被边框遮住的情况下仍然以某种方式显示出来吗?也许通过增加高光效果的边框大小?

这张图片就是我所说的例子。顶部按钮是强调按钮,边框尺寸增加。第二个按钮是一个被光标突出显示的普通按钮(鼠标光标不会出现在截图快照中)。如图所示,增加的边框尺寸大于突出显示效果,因此当您尝试突出显示第一个按钮时似乎没有任何反应。 third/fourth 只是没有任何作用的普通按钮。

抱歉,如果这里的措辞有点混乱,但我不确定表达我的问题的最佳方式是什么。

这是一个简单的例子。当鼠标光标悬停在带有红色边框的按钮上时,它不再突出显示。

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;

public class Test {
    JFrame window;
    JPanel screen1;
    Border borderThick = BorderFactory.createLineBorder(Color.red, 3);

    public Test(){

    //Frame Window
    window = new JFrame();
    window.setSize(800,600);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.getContentPane().setBackground(Color.blue);

    //Screen 1
    screen1 = new JPanel();
    screen1.setBounds(100, 100, 600, 205);
    screen1.setBackground(Color.blue);

    JButton buttonThickBorder = new JButton("Thick Button");
    buttonThickBorder.setBorder(borderThick);
    screen1.add(buttonThickBorder);

    JButton buttonNormalButton = new JButton("NormalButton");
    screen1.add(buttonNormalButton);

    window.add(screen1);
    window.setVisible(true);

}

public static void main(String[] args){
    new Test();
}
}

JButtons 带有它们自己的默认值 Border,这是您默认看到的(带有悬停效果、按下效果等)。如果您更改边框以提供自己的边框,则默认边框将消失。

要解决此问题,一种方法是实现您自己的边框,它将监听悬停事件,通过监听 JButton 的模型更改更容易完成,如下所示:

import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;

public class Custom {
    
    private static void createAndShowGUI() {
        
        JFrame window;
        JPanel screen1;
        Border borderThick = BorderFactory.createLineBorder(Color.red, 3);

        //Frame Window
        window = new JFrame();
        window.setSize(400,300);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.getContentPane().setBackground(Color.blue);

        //Screen 1
        screen1 = new JPanel();
        screen1.setBounds(100, 100, 600, 205);
        screen1.setBackground(Color.blue);

        JButton buttonThickBorder = new JButton("Thick Button");
        buttonThickBorder.setBorder(borderThick);
        screen1.add(buttonThickBorder);
        
        //Changes:
        Border borderThickRollover = BorderFactory.createLineBorder(Color.CYAN, 3);
        buttonThickBorder.getModel().addChangeListener(e -> {
            final ButtonModel model = (ButtonModel) e.getSource();
            if (model.isRollover())
                buttonThickBorder.setBorder(borderThickRollover);
            else
                buttonThickBorder.setBorder(borderThick);
        });

        JButton buttonNormalButton = new JButton("NormalButton");
        screen1.add(buttonNormalButton);

        window.add(screen1);
        window.setVisible(true);
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(Custom::createAndShowGUI);
    }
}

同样,您可以监听其他事件,例如按钮被按下、装备、选择或启用(所有这些都通过按钮的模型)并相应地更改边框。对于更多事件,您可以在按钮本身上使用侦听器(例如 FocusListener)。

解决您遇到的问题的另一种方法是使用默认边框本身以及您的自定义边框,方法是构建 CompoundBorder,例如:

import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;

public class Default {
    
    private static void createAndShowGUI() {
        
        JFrame window;
        JPanel screen1;
        //Border borderThick = BorderFactory.createLineBorder(Color.red, 3);

        //Frame Window
        window = new JFrame();
        window.setSize(400,300);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.getContentPane().setBackground(Color.blue);

        //Screen 1
        screen1 = new JPanel();
        screen1.setBounds(100, 100, 600, 205);
        screen1.setBackground(Color.blue);

        JButton buttonThickBorder = new JButton("Thick Button");
        //buttonThickBorder.setBorder(borderThick);
        screen1.add(buttonThickBorder);
        
        //Changes:
        Border borderThickRollover = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.CYAN, 5), buttonThickBorder.getBorder());
        buttonThickBorder.setBorder(borderThickRollover);

        JButton buttonNormalButton = new JButton("NormalButton");
        screen1.add(buttonNormalButton);

        window.add(screen1);
        window.setVisible(true);
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(Default::createAndShowGUI);
    }
}

这样您就可以获得默认边框加上您的额外边框。这样你就不一定需要监听模型变化了。

请注意,在第二个示例中,当您将鼠标悬停在复合一的外边框(即青色子边框)上时,按钮模型变为 rolled over通知内部(默认)边框。发生这种情况是因为复合边框由按钮维护,因此将复合边框悬停在任何地方都会使按钮的模型翻转。如果这不是你想要的,那么我现在能想到的最简单的解决方法是你可以在 JPanel 中添加按钮,它将有一个青色 LineBorder 并在该面板上安装按钮。

一般来说,你可以通过UIManager获得一个JButton的默认Border,而不需要实际构造一个JButton

Border buttonDefaultBorder = javax.swing.UIManager.getBorder("Button.border");

...除非你安装自己的 Look And Feel (L&F),它的行为不同,在这种情况下你可以在构造按钮后获得默认边框,但是那是另一回事(可能是错误的 L&F 实现)。