StyleableProperty: как программно изменить значение во время выполнения? - PullRequest
0 голосов
/ 11 января 2019

Мой вариант использования:

  • настраиваемое свойство элемента управления, которое должно настраиваться с помощью css
  • свойство должно быть изменяемым во время выполнения
  • для данного экземпляра элемента управления, изменение программы не должно быть отменено при повторном применении CSS

Пользовательский StyleableProperty выглядит как идеальное соответствие для реализации требований. Ниже приведен пример, который реализует (взятый без изменений из класса Javadoc StyleablePropertyFactory ).

Все в порядке, за исключением последнего требования: на applyCss повторно применяется значение по умолчанию из таблицы стилей. Воспроизвести:

  • запустите пример, обратите внимание, что исходное «выбранное» состояние (выбранный флажок связан с ним) MyButton равно true
  • нажмите пользовательскую кнопку, обратите внимание, что «выбранный» не изменяется на «ложь» (хотя actionHandler меняет его)
  • нажмите вторую кнопку («переключатель»), обратите внимание, что выбранное состояние пользовательской кнопки меняется на false
  • Наведите указатель мыши на пользовательскую кнопку, обратите внимание, что выбранное состояние возвращается к истинному

Причину возврата к истине (значение, установленное с помощью стиля) можно проследить до applyCss, которое происходит при изменениях состояния ... которое понятно и может быть правильным в большинстве случаев, но не в моем контексте.

Итак, вопросы:

  • Я на правильном пути с использованием StyleableProperty?
  • если так, как настроить так, чтобы он не применялся повторно после изменения вручную?
  • если нет, что еще делать?
  • или, может быть, он задает совсем не те вопросы: может быть, свойства, которые можно установить с помощью css, не должны (навсегда) изменяться кодом?

Пример:

public class StyleableButtonDriver extends Application {

    /**
     * example code from class doc of StyleablePropertyFactory.
     */
    private static class MyButton extends Button {

        private static final StyleablePropertyFactory<MyButton> FACTORY 
            = new StyleablePropertyFactory<>(Button.getClassCssMetaData());

        MyButton(String labelText) {
            super(labelText);
            getStyleClass().add("my-button");
            setStyle("-my-selected: true");
        }

        // Typical JavaFX property implementation
        public ObservableValue<Boolean> selectedProperty() { return (ObservableValue<Boolean>)selected; }
        public final boolean isSelected() { return selected.getValue(); }
        public final void setSelected(boolean isSelected) { selected.setValue(isSelected); }

        // StyleableProperty implementation reduced to one line
        private final StyleableProperty<Boolean> selected =
             FACTORY.createStyleableBooleanProperty(
                    this, "selected", "-my-selected", s -> s.selected);

        @Override
        public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
            return FACTORY.getCssMetaData();
        }

        public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
            return FACTORY.getCssMetaData();
        }

    }
    private Parent createContent() {
        MyButton button = new MyButton("styleable button");
        button.setOnAction(e ->  {
            // does not work: reset on applyCss
            boolean isSelected = button.isSelected();
            button.setSelected(!isSelected);
        });

        CheckBox box = new CheckBox("button selected");
        box.selectedProperty().bind(button.selectedProperty());

        Button toggle = new Button("toggle button");
        toggle.setOnAction(e -> {
            boolean isSelected = button.isSelected();
            button.setSelected(!isSelected);
        });


        BorderPane content = new BorderPane(button);
        content.setBottom(new HBox(10, box, toggle));
        return content;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent(), 300, 200));
        //same behavior as setting the style directly
//        URL uri = getClass().getResource("xstyleable.css");
//        stage.getScene().getStylesheets().add(uri.toExternalForm());
        // not useful: would have to override all
//        Application.setUserAgentStylesheet(uri.toExternalForm());
        stage.setTitle(FXUtils.version());
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(StyleableButtonDriver.class.getName());

}

1 Ответ

0 голосов
/ 11 января 2019

Вы находитесь на правильном пути, но, поскольку вам необходимо переопределить приоритет по умолчанию для источников стилей (таблица стилей пользовательского агента <назначается программно <свойство таблицы стилей <css <<code>Node.style), вы не можете использовать SyleablePropertyFactory для создания этого свойства , Вам необходимо создать объект CssMetaData, который указывает свойство как не подлежащее сортировке, если свойство было назначено программно.

private static class MyButton extends Button {

    private static final List<CssMetaData<? extends Styleable, ?>> CLASS_CSS_METADATA;
    private static final CssMetaData<MyButton, Boolean> SELECTED;

    static {
        SELECTED = new CssMetaData<MyButton, Boolean>("-my-selected", StyleConverter.getBooleanConverter()) {

            @Override
            public boolean isSettable(MyButton styleable) {
                // not setable, if bound or set by user
                return styleable.selected.getStyleOrigin() != StyleOrigin.USER  && !styleable.selected.isBound();
            }

            @Override
            public StyleableProperty<Boolean> getStyleableProperty(MyButton styleable) {
                return styleable.selected;
            }

        };

        // copy list of button css metadata to list and add new metadata object
        List<CssMetaData<? extends Styleable, ?>> buttonData = Button.getClassCssMetaData();
        List<CssMetaData<? extends Styleable, ?>> mybuttonData = new ArrayList<>(buttonData.size()+1);
        mybuttonData.addAll(buttonData);
        mybuttonData.add(SELECTED);
        CLASS_CSS_METADATA = Collections.unmodifiableList(mybuttonData);
    }

    MyButton(String labelText) {
        super(labelText);
        getStyleClass().add("my-button");
        setStyle("-my-selected: true");
    }

    // Typical JavaFX property implementation
    public ObservableValue<Boolean> selectedProperty() { return selected; }
    public final boolean isSelected() { return selected.get(); }
    public final void setSelected(boolean isSelected) { selected.set(isSelected); }

    // StyleableProperty implementation reduced to one line
    private final SimpleStyleableBooleanProperty selected = new SimpleStyleableBooleanProperty(SELECTED, this, "selected");

    @Override
    public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
        return CLASS_CSS_METADATA;
    }

    public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
        return CLASS_CSS_METADATA;
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...