Swing - пользовательские кнопки с синтезатором - PullRequest
2 голосов
/ 17 октября 2011

Я работаю над проектом, использующим Synth для пользовательского интерфейса, и хочу реализовать несколько пользовательских кнопок.Кнопки должны использовать настройки стиля из файла настроек синтезатора XML - например, цвета шрифта, которые различны для разных состояний (MOUSE_OVER, PRESSED и т. Д.).

Проблема, с которой я застрял, заключается в том, что некоторые изкнопки должны иметь дополнительные подкомпоненты - например, для некоторых требуется более одной метки.Я хочу, чтобы подкомпоненты выбирали те же настройки стиля, что и стандартные подкомпоненты кнопок.

Мне кажется, что я должен иметь возможность просто расширить JButton и переопределить / расширить paintComponent для вызоваметоды рисования некоторых дочерних компонентов.Хотя я немного не уверен в некоторых аспектах этого подхода: например, какие параметры передать paintComponent;и как убедиться, что подкомпоненты получают правильные настройки стиля Synth (особенно в отношении состояний).

В сторону: я попытался расширить JPanel, но столкнулся с некоторыми трудностями при таком подходе (см. здесь: JPanel сообщает для Synth ).

РЕДАКТИРОВАТЬ: Итак, я обнаружил, что можно добавлять подкомпоненты к кнопкам и правильно отображать их.Кажется, что даже если JButton.getLayout() возвращает ноль, кнопка будет использовать OverlayLayout, если вы не наберете JButton.setLayout().Вызов JButton.setLayout(null) не позволяет использовать OverlayLayout, поэтому я так и работаю с макетом.

Я рассматриваю несколько различных подходов к обновлению стилей для дочерних элементов управления и сообщу о нихте позже.

1 Ответ

1 голос
/ 19 октября 2011

Итак, на случай, если он кому-нибудь пригодится, вот подход, который я выбрал в итоге:

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.

...