我需要一个带有自定义图标的
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());
归根结底,我真正想要的是:
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()
)
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