Java Swing-带Synth的自定义按钮

Java Swing-带Synth的自定义按钮,java,swing,jbutton,look-and-feel,synth,Java,Swing,Jbutton,Look And Feel,Synth,我正在使用Synth进行UI项目,并希望实现一些自定义按钮。按钮需要使用synth XML设置文件中的样式设置-例如,字体颜色因不同状态(鼠标悬停、按下等)而不同 我一直坚持的问题是,有些按钮需要额外的子组件,例如,有些按钮需要多个标签。我希望子组件拾取与标准按钮子组件相同的样式设置 我觉得我应该能够扩展JButton并重写/extendpaintComponent来调用一些子组件的绘图方法。不过,我对该方法的几个方面有点不确定:例如,要传递给paintComponent的参数;以及如何确保子组

我正在使用Synth进行UI项目,并希望实现一些自定义按钮。按钮需要使用synth XML设置文件中的样式设置-例如,字体颜色因不同状态(鼠标悬停、按下等)而不同

我一直坚持的问题是,有些按钮需要额外的子组件,例如,有些按钮需要多个标签。我希望子组件拾取与标准按钮子组件相同的样式设置

我觉得我应该能够扩展
JButton
并重写/extend
paintComponent
来调用一些子组件的绘图方法。不过,我对该方法的几个方面有点不确定:例如,要传递给
paintComponent
的参数;以及如何确保子组件获得正确的Synth样式设置(特别是wrt.the states)

旁白:我曾尝试扩展
JPanel
,但在这种方法中遇到了一些困难(请参见此处:)

编辑:因此,我发现可以将子组件添加到按钮并使其正确渲染。看起来,即使
JButton.getLayout()
返回null,按钮仍将使用
overlayout
,除非调用
JButton.setLayout()
。调用
JButton.setLayout(null)
会阻止使用overlayout,所以我就是这样处理布局的


我正在研究几种不同的方法来更新子控件的样式,稍后将报告这些方法。

因此,如果它对其他人有用,我最后采用了以下方法:

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;
    }
}
我找到了两种实现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)似乎是最好的


还有垃圾神建议的实现自定义UI委托的方法(扩展
BasicButtonUI
),但如果您采用这种方法,我认为您必须重新实现SynthButtonUI的大部分功能。

绘制由组件的UI委托处理。请参阅@mKorbel's,在您之前的主题中引用。我知道UI代理处理绘图,但由于(据我所知)基本上不可能扩展Synth UI代理,因此我希望有不止一种方法来剥这只猫的皮。