是的,这是可能的,而且 Nimbus 实际上会监听“Nimbus.Overrides”的更改 - 只是:如果它们是,它不会卸载某些属性!instanceof UIResource
至少背景、前景、字体就是这种情况(也可能是其他属性)
在您的上下文中,您最初确实安装了 RED 的非 uiresource,有效地告诉 laf 不要再碰它 - 它符合:-)
我可以使它工作的唯一方法是在设置新的覆盖之前使背景为空,例如:
private void setExceptionState(JComponent password) {
password.setBackground(null);
UIDefaults overrides = new UIDefaults();
overrides.put("PasswordField.background", Color.RED);
password.putClientProperty("Nimbus.Overrides", overrides);
}
private void resetExceptionState(JComponent password) {
password.setBackground(null);
UIDefaults overrides = new UIDefaults();
overrides.put("PasswordField.background", Color.WHITE);
password.putClientProperty("Nimbus.Overrides", overrides);
}
更新
实际上,以上并没有回答真正的问题:
引入密码字段的新状态并设置不同的样式
Nimbus 确实允许添加自定义状态(尽管结果有些不可预测,就像 Synth 最不受喜爱的最小孩子一样;-) 要走的路是
- 实现自定义状态
- 使用 ui-defaults 注册附加状态
- 根据需要附加该状态的属性
所有这些配置都必须在LAF 安装后和第一个 JPasswordField 实例化之前完成,如果 LAF 在运行时切换,很可能(未测试)会造成问题。
protected void installCustomPasswordFieldState() {
// implement a custom state
State<JPasswordField> state = new State<JPasswordField>("Invalid") {
@Override
protected boolean isInState(JPasswordField c) {
Object invalid = c.getClientProperty("Invalid");
return Boolean.TRUE.equals(invalid);
}
};
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
// register available states
// note: couldn't find a way to grab the already available states
// so this is guesswork
defaults.put("PasswordField.States", "Enabled, Focused, Invalid");
// install the custom state
defaults.put("PasswordField.Invalid", state);
// install the properties for the custom state
// note: background has no effect
defaults.put("PasswordField[Invalid].background",
Color.RED);
javax.swing.Painter<JComponent> p = new javax.swing.Painter<JComponent>() {
@Override
public void paint(Graphics2D g, JComponent object, int width, int height) {
g.setColor(Color.RED);
// this is crude - overpainting the complete area, do better!
g.fillRect(0, 0, width, height);
}
};
// using a painter has an effect
defaults.put("PasswordField[Invalid].backgroundPainter", p);
}
// example usage, toggling
// a new property (for simplicity implemented as clientProperty
// to toggle the invalid state
Action reset = new AbstractAction("reset") {
@Override
public void actionPerformed(ActionEvent e) {
boolean isInvalid = Boolean.TRUE.equals(field.getClientProperty("Invalid"));
if (isInvalid) {
field.putClientProperty("Invalid", null);
} else {
field.putClientProperty("Invalid", Boolean.TRUE);
}
field.repaint();
}
};