使用自定义图标在按下状态下绘制错误的 JCheckBox

问题描述 投票:0回答:1

我需要一个带有自定义图标的

JCheckBox

但是,一旦我设置了自定义图标,我的复选框在“按下”状态下画错了

具体来说,它始终显示选定的图标

// snippet 1

package demos.button;

import di.Icons;

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

public class CheckBoxDemo {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Check Box demo");
        JPanel mainPanel = createMainPanel();
        frame.setContentPane(mainPanel);
        frame.setLocationRelativeTo(null);
        frame.pack();
        frame.setVisible(true);
    }

    private static JPanel createMainPanel() {
        FlowLayout layout = new FlowLayout();
        layout.setAlignment(FlowLayout.CENTER);
        JPanel mainPanel = new JPanel(layout);
        mainPanel.add(createCheckBox());
        return mainPanel;
    }

    private static JCheckBox createCheckBox() {
        JCheckBox checkBox = new JCheckBox();
        checkBox.setIcon(Icons.unchecked());
        checkBox.setSelectedIcon(Icons.checked());
        return checkBox;
    }
}
// snippet 2

package di;

import util.IconUtil;

import javax.swing.*;

public class Icons {
    private Icons() {
    }
    public static Icon checked() {
        return IconUtil.findIcon("/checked.gif").orElse(null);
    }
    public static Icon unchecked() {
        return IconUtil.findIcon("/unchecked.gif").orElse(null);
    }
}
// snippet 3

package util;

import javax.swing.*;
import java.net.URL;
import java.util.Optional;

public class IconUtil {
    private IconUtil() {
    }

    public static Optional<Icon> findIcon(String path) {
        URL iconUrl = IconUtil.class.getResource(path);
        return Optional.ofNullable(iconUrl).map(ImageIcon::new);
    }
}

checked.gif

选中图标

unchecked.gif

未选中的图标

如果我不设置自定义图标,则无法重现

// snippet 4

    private static JCheckBox createCheckBox() {
        JCheckBox checkBox = new JCheckBox();
        return checkBox;
    }

这似乎与

setIcon()
的文档相矛盾,该文档明确指出

设置按钮的默认图标。如果没有明确设置按下的图标,则此图标也用作“按下”和“禁用”图标。

由于我将未选中的图标设置为默认图标,因此只要复选框处于按下状态,它就应该显示

但是,

已选择图标是

您可以将

borderPainted

 属性设置为 
true
 以看得更清楚。当按下时它总是在视觉上被选择

// snippet 5 private static JCheckBox createCheckBox() { JCheckBox checkBox = new JCheckBox(); checkBox.setIcon(Icons.unchecked()); checkBox.setSelectedIcon(Icons.checked()); checkBox.setBorderPainted(true); return checkBox; }
就好像我调用了

// snippet 6 checkBox.setIcon(Icons.checked());
而不是

// snippet 7 checkBox.setIcon(Icons.unchecked());

复选框演示:按下的图标被选中

归根结底,我真正想要的是:

    按下后,保留我的自定义图标(选中或取消选中)
  1. 但是使复选框看起来“被按下”(使框区域成为阴影)
基本上,与默认情况下发生的情况相同

JCheckBox

(参见片段 4),但使用自定义图标

无自定义图标:未选择、按下 无自定义图标:选择、按下

#UPD:

我进行了调查并找到了错误的根源。文档确实撒了谎。这是 L&F 特定的

// javax.swing.plaf.metal.MetalRadioButtonUI#paint // OR javax.swing.plaf.basic.BasicRadioButtonUI#paint // it seems the code was copied and pasted } else if(model.isPressed() && model.isArmed()) { altIcon = b.getPressedIcon(); if(altIcon == null) { // Use selected icon altIcon = b.getSelectedIcon(); }
不过,

NimbusLookAndFeel

遵循文档

如果您不设置自定义图标,则根本不会调用

getPressedIcon()

,而是绘制默认图标

// in the same paint method if(altIcon != null) { // invoke getPressedIcon() if necessary etc. } else { getDefaultIcon().paintIcon(c, g, iconRect.x, iconRect.y); }
// javax.swing.plaf.metal.MetalIconFactory.CheckBoxIcon#paintIcon
        public void paintIcon(Component c, Graphics g, int x, int y) {
            if (MetalLookAndFeel.usingOcean()) {
                paintOceanIcon(c, g, x, y);
                return;
            }
默认图标

咨询按钮型号

private void paintOceanIcon(Component c, Graphics g, int x, int y) { ButtonModel model = ((JCheckBox)c).getModel(); g.translate(x, y); int w = getIconWidth(); int h = getIconHeight(); if ( model.isEnabled() ) { if (model.isPressed() && model.isArmed()) { g.setColor(MetalLookAndFeel.getControlShadow()); g.fillRect(0, 0, w, h); g.setColor(MetalLookAndFeel.getControlDarkShadow()); g.fillRect(0, 0, w, 2); g.fillRect(0, 2, 2, h - 2); g.fillRect(w - 1, 1, 1, h - 1); g.fillRect(1, h - 1, w - 2, 1);
我不明白为什么

JCheckBox

es不公开
setPressedSelectedIcon()
方法(类似于
setRolloverIcon()
setRolloverSelectedIcon()

java swing
1个回答
0
投票
因此,您必须显式设置一个“智能”

pressedIcon

,以考虑复选框的模型

// CheckBoxDemo private static JCheckBox createCheckBox() { JCheckBox checkBox = new JCheckBox(); checkBox.setIcon(Icons.uncheckedBox()); checkBox.setPressedIcon(Icons.pressedBox(checkBox)); checkBox.setSelectedIcon(Icons.checkedBox()); return checkBox; }
// Icons
    public static Icon pressedBox(JCheckBox checkBox) {
        return new Icon() {
            @Override
            public void paintIcon(Component c, Graphics g, int x, int y) {
                if (checkBox.isSelected())
                    checkedPressedBox().paintIcon(c, g, x, y);
                else
                    uncheckedPressedBox().paintIcon(c, g, x, y);
            }

            @Override
            public int getIconWidth() {
                return Math.max(checkedBox().getIconWidth(), uncheckedBox().getIconWidth());
            }

            @Override
            public int getIconHeight() {
                return Math.max(checkedBox().getIconHeight(), uncheckedBox().getIconHeight());
            }
        };
    }

    private static Icon checkedPressedBox() {
        return IconUtil.findIcon("/checkedPressed.png").orElse(null);
    }

    private static Icon uncheckedPressedBox() {
        return IconUtil.findIcon("/uncheckedPressed.png").orElse(null);
    }

checkedPressed.png


选中按下的图标

uncheckedPressed.png


未选中按下的图标

演示:复选框未选中,按下

演示:选中复选框并按下

© www.soinside.com 2019 - 2024. All rights reserved.