Итак, на случай, если он кому-нибудь пригодится, вот подход, который я выбрал в итоге:
class CustomButton extends JButton {
CustomButton() {
// ... normal button init
// Enable absolute positioning of sub-components.
setLayout(null);
updateStyles();
getModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
updateStyles();
}
});
}
private void updateStyles() {
// See below for implementation.
}
private int getSynthComponentState() {
// This is basically a copy of SynthButtonUI.getComponentState(JComponent)
int state = SynthConstants.ENABLED;
if (!isEnabled()) {
state = SynthConstants.DISABLED;
}
if (model.isPressed()) {
if (model.isArmed()) {
state = SynthConstants.PRESSED;
} else {
state = SynthConstants.MOUSE_OVER;
}
}
if (model.isRollover()) {
state |= SynthConstants.MOUSE_OVER;
}
if (model.isSelected()) {
state |= SynthConstants.SELECTED;
}
if (isFocusOwner() && isFocusPainted()) {
state |= SynthConstants.FOCUSED;
}
if (isDefaultButton()) {
state |= SynthConstants.DEFAULT;
}
return state;
}
}
Я нашел 2 подхода к реализации метода updateStyles (): (A) изменить имя компонента, чтобы использовать другой именованный стиль, или (B) скопировать настройки стиля с кнопки на подкомпоненты. Подход (A) довольно прост, подход (B) работает следующим образом:
private void updateStyles() {
SynthStyle ss = SynthLookAndFeel.getStyle(this, Region.BUTTON);
SynthContext sc = new SynthContext(this, Region.BUTTON, ss, getSynthComponentState());
for (Component c : getComponents()) {
c.setFont(ss.getFont(sc));
c.setBackground(ss.getColor(sc, ColorType.BACKGROUND));
c.setForeground(ss.getColor(sc, ColorType.FOREGROUND));
// ... and so on if you have other style elements to be changed.
}
}
Подход (A), вероятно, лучше, если вы изменяете более двух настроек стиля для каждого отдельного состояния, хотя он может оказаться громоздким, если у вас разные стили для множества разных состояний. Если вы изменяете только пару настроек стиля (например, в моем случае я забочусь только о цветах, по крайней мере, на данный момент), тогда подход (B) кажется наилучшим.
Существует также подход, предложенный trashgod для реализации пользовательского делегата пользовательского интерфейса (расширение BasicButtonUI
), но если вы выберете этот путь, я думаю, вам придется заново реализовать большую часть SynthButtonUI.