Swing - 带合成器的自定义按钮

发布于 2024-12-10 14:03:42 字数 765 浏览 0 评论 0原文

我正在开发一个使用 Synth 作为 UI 的项目,并且想要实现一些自定义按钮。这些按钮需要使用合成 XML 设置文件中的样式设置 - 例如,不同状态(MOUSE_OVER、PRESSED 等)的字体颜色不同。

我遇到的问题是,某些按钮需要有额外的子组件 - 例如,有些按钮需要多个标签。我希望子组件采用与标准按钮子组件相同的样式设置。

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

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

编辑:所以,我发现可以向按钮添加子组件并让它们正确呈现。看来,即使 JButton.getLayout() 返回 null,该按钮仍将使用 OverlayLayout,除非您调用 JButton.setLayout()。调用 JButton.setLayout(null) 确实会阻止使用 OverlayLayout,所以这就是我处理布局的方式。

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

I am working on a project using Synth for the UI and want to implement some custom buttons. The buttons need to make use of style settings from a synth XML settings file - e.g. font colors which are different for different states (MOUSE_OVER, PRESSED, etc).

The problem I'm stuck on is that some of the buttons need to have extra sub-components - e.g. some need more than one label. I want the sub-components to pick up the same style settings as the standard button sub-components.

I feel like I ought to be able to just extend JButton and override/extend paintComponent to call the draw methods of some child components. I'm a bit unsure about a few aspects of that approach though: e.g. what parameters to pass to paintComponent; and how to ensure the sub-components get the correct Synth style settings (particularly wrt. the states).

An aside: I have tried extending JPanel but have run into some difficulties with that approach (see here: JPanel states for Synth).

EDIT: So, I've discovered that it is possible to add sub-components to buttons and have them render correctly. It seems that even though JButton.getLayout() returns null, the button will use an OverlayLayout unless you call JButton.setLayout(). Calling JButton.setLayout(null) does prevent the OverlayLayout being used, so that's how I'm handling the layout.

I'm looking into a couple of different approaches to updating the styles for the child controls, will report back on those later.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空城仅有旧梦在 2024-12-17 14:03:42

因此,如果对其他人有用,这是我最终采用的方法:

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) 似乎是最好的。

还有由trashgod 建议的实现自定义UI 委托(扩展BasicButtonUI)的方法,但如果您采用该路线,我认为您将不得不重新实现SynthButtonUI 的大部分内容。

So, in case it's of use to anyone else here's the approach I took in the end:

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;
    }
}

I found 2 approaches to how to implement the updateStyles() method: (A) change the name of the component to use a different named style, or (B) copy the style settings from the button to the sub-components. Approach (A) is pretty straightforward, approach (B) works as follows:

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.
    }
}

Approach (A) is probably better if you're changing more than a couple of style settings with each different state, although it could get unwieldy if you have different styles for a lot of different states. If you're only changing a couple of style settings (e.g. in my case I only care about colours, at least for now) then approach (B) seems best.

There's also the approach suggested by trashgod of implementing a custom UI delegate (extending BasicButtonUI) but if you take that route I think you'll have to re-implement much of SynthButtonUI.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文