jbutton的图标在悬停时变为像素化

pobjuy32  于 2021-07-11  发布在  Java
关注(0)|答案(2)|浏览(342)

我正在制作一个JavaSwing应用程序,遇到了一个问题。我想做一个有图标的按钮。要创建它,我首先创建一个重新缩放的图像图标:

studentIcon = new ImageIcon(new ImageIcon( 
"D:\\Programming\\Java\\ELearningDesktop\\src\\com\\core\\student.png")
                .getImage().getScaledInstance(64, 64, Image.SCALE_SMOOTH));

然后我做一个按钮并在上面设置图标:

JButton studentButton = new JButton();
studentButton.setIcon(studentIcon);
studentButton.setFocusable(false);

它工作得很好,但由于某些原因,每当我将鼠标悬停在按钮上时,按钮上的图标就会变成像素。在悬停之后,它永远不会变得平滑,除非我重新缩放jframe,这样它可能会调用 repaint() 在某个地方重新粉刷。
我使用下载的外观,但如果使用默认的外观,问题仍然存在。以同样的方式使用imageicon,但不重新缩放也没有帮助-仍会出现像素化。解决办法是什么?
课程起点

public class Starter {
    public static void main(String[] args) {
        FlatLightLaf.install();
        EventQueue.invokeLater(()->{
            AuthFrame frame = new AuthFrame();
            frame.setVisible(true);
        });
    }
}

authframe公司

public class AuthFrame extends JFrame {

    private JPanel mainPanel;
    private LoginPanel loginPanel;
    private ImageIcon studentIcon;
    private ImageIcon teacherIcon;

    public AuthFrame() {
        setLayout(new GridBagLayout());
        ImageIcon imageIcon = new ImageIcon(new ImageIcon(
                "D:\\Programming\\Java\\ELearningDesktop\\src\\com\\core\\tileBackground.jpg")
                .getImage().getScaledInstance(321, 333, Image.SCALE_SMOOTH));
        mainPanel = new BackgroundPanel(imageIcon.getImage(), BackgroundPanel.TILED,
                0f, 0.5f);

        add(mainPanel, new GBC(0, 0).setFill(BOTH).setWeights(1, 1));

        mainPanel.setLayout(new GridBagLayout());

        studentIcon = new ImageIcon(new ImageIcon(
                "D:\\Programming\\Java\\ELearningDesktop\\src\\com\\core\\student.png")
                .getImage().getScaledInstance(64, 64, Image.SCALE_SMOOTH));
        teacherIcon = new ImageIcon(new ImageIcon(
                "D:\\Programming\\Java\\ELearningDesktop\\src\\com\\core\\teacher.png")
                .getImage().getScaledInstance(64, 64, Image.SCALE_SMOOTH));

        loginPanel = new LoginPanel();
        mainPanel.add(loginPanel);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(FRAME_WIDTH, FRAME_HEIGHT);
        setExtendedState(Frame.MAXIMIZED_BOTH);
    }

loginpanel—在authframe中使用的私有内部类

private class LoginPanel extends JPanel {
        private JTextField usernameField;
        private JPasswordField passwordField;
        private JLabel errorLabel;
        private JButton studentButton;
        private JButton teacherButton;
        private JLabel titleLabel;
        private boolean forStudent = true;

        public LoginPanel() {
            setLayout(new GridBagLayout());
            setBackground(new Color(255, 255, 255, 181));

            studentButton = new JButton();
            studentButton.setIcon(studentIcon);
            studentButton.setFocusable(false);
            //add(studentButton, new GBC(0, 0).setAnchor(GBC.WEST).setInsets(10));

            teacherButton = new JButton(teacherIcon);
            teacherButton.setFocusable(false);
            add(teacherButton, new GBC(0, 0).setAnchor(GBC.WEST).setInsets(10));

            titleLabel = new JLabel("<html>Signing in as <b>student</b></html>");
            Utils.deriveFontForTo(titleLabel, 24f);
            add(titleLabel, new GBC(1, 0).setAnchor(GBC.EAST).setInsets(10));
            titleLabel.setVerticalAlignment(JLabel.BOTTOM);

            JLabel usernameLabel = new JLabel("Username");
            Utils.deriveFontForTo(usernameLabel, 24f);
            add(usernameLabel, new GBC(0, 1).setAnchor(GBC.WEST).setInsets(10));
            usernameLabel.setHorizontalAlignment(LEFT);

            JLabel passwordLabel = new JLabel("Password");
            Utils.deriveFontForTo(passwordLabel, 24f);
            add(passwordLabel, new GBC(0, 2).setAnchor(GBC.WEST).setInsets(10));

            usernameField = new JTextField(15);
            Utils.deriveFontForTo(usernameField, 24f);
            add(usernameField, new GBC(1, 1).setInsets(10));

            passwordField = new JPasswordField(15);
            Utils.deriveFontForTo(passwordField, 24f);
            add(passwordField, new GBC(1, 2).setInsets(10));

            errorLabel = new JLabel();
            Utils.deriveFontForTo(errorLabel, 16f);
            errorLabel.setForeground(Color.RED);
            add(errorLabel, new GBC(1, 3).setAnchor(GBC.WEST).setInsets(2));
            errorLabel.setHorizontalAlignment(LEFT);

            JButton loginButton = new JButton("Log in");
            loginButton.setFocusable(false);
            Utils.deriveFontForTo(loginButton, 24f);
            add(loginButton, new GBC(1, 4, 1, 1)
                    .setFill(GridBagConstraints.HORIZONTAL).setInsets(10));

            JButton registerButton = new JButton("Sign Up");
            loginButton.setFocusable(false);
            Utils.deriveFontForTo(registerButton, 24f);
            add(registerButton, new GBC(1, 5, 1, 1)
                    .setInsets(10));
        }
    }

gbc-一个使用gridbaglayout的covenence类

package com.core.helpers.graphics;

import java.awt.*;

public class GBC extends GridBagConstraints {

    public GBC(int gridX, int gridY){
        super.gridx = gridX;
        super.gridy = gridY;
    }

    public GBC(int gridX, int gridY, int gridWidth, int gridHeight){
        super.gridx = gridX;
        super.gridy = gridY;
        super.gridwidth = gridWidth;
        super.gridheight = gridHeight;
    }

    public GBC setAnchor(int anchor){
        super.anchor = anchor;
        return this;
    }

    public GBC setWeights(double weightX, double weightY){
        super.weightx = weightX;
        super.weighty = weightY;
        return this;
    }

    public GBC setFill(int fill){
        super.fill = fill;
        return this;
    }

    public GBC setInsets(int k){
        this.insets = new Insets(k,k,k,k);
        return this;
    }

}

谢谢
截图:
前两个按钮是平滑的

第二个悬停按钮变为像素化

第三个按钮在调整帧大小后再次变得平滑

h6my8fg2

h6my8fg21#

它永远不会变得平滑,除非我重新缩放jframe,这样它可能会在某个地方调用repaint(),然后重新绘制它。

setBackground(new Color(255, 255, 255, 181));

我想以上是与这个问题有关的。swing不支持透明背景。
swing希望组件是不透明的,在这种情况下,组件负责绘制不透明的背景。
或者,组件可以是非不透明的,在这种情况下,首先绘制父组件以确保绘制不透明的背景。
如果您有透明度,那么您需要使组件不透明,并覆盖paintcomponent方法和自己绘制背景。
基本代码是:

JPanel panel = new JPanel()
{
    protected void paintComponent(Graphics g)
    {
        g.setColor( getBackground() );
        g.fillRect(0, 0, getWidth(), getHeight());
        super.paintComponent(g);
    }
};
panel.setOpaque(false); // background of parent will be painted first
panel.setBackground( new Color(255, 0, 0, 20) );
frame.add(panel);

有关更多信息和可重用解决方案,请参见透明背景,这样就不必每次都使用自定义绘制。

mpgws1up

mpgws1up2#

编辑:
看起来我的问题与windows缩放有关,正如javaswing给出的答案所示,所有图像都是像素化的。使用这个链接中的标记答案对我很有帮助。在这里:https://stackoverflow.com/a/50566705/12538636
暴力方法:
通过重新油漆按钮的面板,每次有一个按钮的变化,使它看起来光滑的所有时间。下面是代码片段:

teacherButton.getModel().addChangeListener(new ChangeListener() {
     @Override
     public void stateChanged(ChangeEvent e) {
         mainPanel.repaint();
     }
});

studentButton.getModel().addChangeListener(new ChangeListener() {
     @Override
     public void stateChanged(ChangeEvent e) {
         mainPanel.repaint();
     }
});

唯一的小问题是,现在悬停和按钮对悬停的响应之间有一个很小的差距(稍微改变一个颜色来表示悬停)。

相关问题