JavaFX - привязка ползунка к свойству отключения кнопки - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь включить кнопку, только если ползунок выходит за новое значение (или позицию).

Ниже показано окно с исходной ситуацией:

enter image description here

As soon I start to drag the Thumb the Button is activated, even the Thumb's not over new value (activated even between values):

enter image description here

If I abort the drag operation (release mouse button) and the Thumb returns to the initial position (or value), the Button don't disabled.

enter image description here

The code:

private void configSldFontSize() {
    
    sldFontSize.valueProperty().addListener((ov, oldValue, newValue) -> {

        if (oldValue == newValue) {
            btnApply.setDisable(true);
        } else {
            btnApply.setDisable(false);
        }

    });

}

Configuration error maybe ?

private void setUpSlrFontSize() {

    sldFontSize.setMin(0);
    sldFontSize.setMax(FontSize.values().length - 1);
    sldFontSize.setValue(viewFactory.getFontSize().ordinal());
    sldFontSize.setMajorTickUnit(1);
    sldFontSize.setMinorTickCount(0);
    sldFontSize.setBlockIncrement(1);
    sldFontSize.setSnapToTicks(true);
    sldFontSize.setShowTickMarks(true);
    sldFontSize.setShowTickLabels(true);
    sldFontSize.setLabelFormatter(new StringConverter() {

        @Override
        public Double fromString(String arg0) {
            return null;
        }

        @Override
        public String toString(Double obj) {
            int i = obj.intValue();
            return FontSize.values()[i].toString();
        }

    });

}

======= SMALL CODE IMPLEMENTATION TO REPLICATE CONDITION ==========

ATTENTION:

I'm using Java 11 (with Java 8 it's not necessary, I guess). So it's may be necessary to include following line in "Run Configurations".

enter image description here

In Package Explorer: right mouse button on "Main.Java => Run As => Run Configurations...", select "(x) = Arguments" tab and put the line as image below, CHANGING THE PATH TO YOUR JAVAFX LIB FOLDER.

введите описание изображения здесь

КОД Основной. java

public class Main extends Application {
@Override
public void start(Stage primaryStage) {
    try {
        VBox root = new VBox();
        
        Button btnApply = new Button("Apply");
        btnApply.setDisable(true);
        
        Slider sldFontSize = new Slider();
        sldFontSize.setMin(0);
        sldFontSize.setMax(2);
        sldFontSize.setValue(1);
        sldFontSize.setMajorTickUnit(1);
        sldFontSize.setMinorTickCount(0);
        sldFontSize.setBlockIncrement(1);
        sldFontSize.setSnapToTicks(true);
        sldFontSize.setShowTickMarks(true);
        sldFontSize.setShowTickLabels(true);
        
        sldFontSize.valueProperty().addListener((ov, oldValue, newValue) -> {

            if (oldValue == newValue) {
                btnApply.setDisable(true);
            } else {
                btnApply.setDisable(false);
            }

        });
        
        root.getChildren().addAll(sldFontSize, btnApply);
        
        Scene scene = new Scene(root,200,100);
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        
        primaryStage.setScene(scene);
        primaryStage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

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

}

Ответы [ 2 ]

1 голос
/ 03 августа 2020

В общем, вы можете создать отдельное свойство, которое представляет фактическое значение, которое вы хотите от ползунка, а затем зарегистрировать слушателя с этим свойством. Обратите внимание, что слушатели изменений получают уведомление только тогда, когда значение действительно изменяется, поэтому if (oldValue==newValue) в вашем слушателе всегда будет ложным.

В этом случае, поскольку интересующее значение является просто результатом приведения значения ползунка к int, вы можете просто привязать IntegerProperty к значению ползунка:

        IntegerProperty intValue = new SimpleIntegerProperty();
        intValue.bind(sldFontSize.valueProperty());

        intValue.addListener((ov, oldValue, newValue) -> btnApply.setDisable(false));

В общем, создайте настраиваемую привязку или зарегистрируйте прослушиватель с sldFontSize.valueProperty(), который обновляет другое ваше свойство. Например, используя ваш FontSize, который, я думаю, является enum:

ObjectProperty<FontSize> fontSizeProperty = new SimpleObjectProperty<>();
fontSizeProperty.bind(Bindings.createObjectBinding(
    () -> FontSize.value()[(int) sldFontSize.getValue()],
    sldFontSize.valueProperty()));
fontSizeProperty.addListener((obs, oldFontSize, newFontSize) -> btnApply.setDisable(false));

Для большей точности вы можете реализовать округление вместо простого преобразования, et c. Вы также можете сохранить «последнее примененное значение» и сравнить с ним при принятии решения, следует ли отключать / включать кнопку, и т. Д. c.

Собрав все это вместе, вы получите что-то вроде:

public class Main extends Application {
    
    @Override
    public void start(Stage primaryStage) {
        try {
            VBox root = new VBox();
            
            IntegerProperty lastSavedFontSize = new SimpleIntegerProperty(1);
            IntegerProperty sldIntValue = new SimpleIntegerProperty();

            Button btnApply = new Button("Apply");
            btnApply.setOnAction(e -> lastSavedFontSize.set(sldIntValue.get()));
            btnApply.disableProperty().bind(sldIntValue.isEqualTo(lastSavedFontSize));

            Slider sldFontSize = new Slider();
            sldFontSize.setMin(0);
            sldFontSize.setMax(2);
            sldFontSize.setValue(lastSavedFontSize.get());
            sldFontSize.setMajorTickUnit(1);
            sldFontSize.setMinorTickCount(0);
            sldFontSize.setBlockIncrement(1);
            sldFontSize.setSnapToTicks(true);
            sldFontSize.setShowTickMarks(true);
            sldFontSize.setShowTickLabels(true);
            
            sldIntValue.bind(Bindings.createIntegerBinding(
                    () ->(int) Math.round(sldFontSize.getValue()), 
                    sldFontSize.valueProperty()));


            root.getChildren().addAll(sldFontSize, btnApply);

            Scene scene = new Scene(root, 200, 100);

            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

Другой подход - использовать valueChangingProperty() ползунка. Это логическое свойство истинно тогда и только тогда, когда пользователь в настоящее время находится в процессе изменения значения. Обратите внимание, что в некоторых случаях valueChangingProperty() может стать ложным до того, как будет установлено окончательное значение ползунка, поэтому безопаснее всего прослушивать оба свойства. Вот версия, использующая этот подход:

public class Main extends Application {
    
    @Override
    public void start(Stage primaryStage) {
        try {
            VBox root = new VBox();
            
            IntegerProperty lastSavedFontSize = new SimpleIntegerProperty(1);

            Button btnApply = new Button("Apply");
            btnApply.setDisable(true);  


            Slider sldFontSize = new Slider();
            sldFontSize.setMin(0);
            sldFontSize.setMax(2);
            sldFontSize.setValue(lastSavedFontSize.get());
            sldFontSize.setMajorTickUnit(1);
            sldFontSize.setMinorTickCount(0);
            sldFontSize.setBlockIncrement(1);
            sldFontSize.setSnapToTicks(true);
            sldFontSize.setShowTickMarks(true);
            sldFontSize.setShowTickLabels(true);

            btnApply.setOnAction(e -> {
                // apply change, and do
                lastSavedFontSize.set((int) sldFontSize.getValue());
            });
            
            ChangeListener<Object> sliderListener = (obs, oldV, newV) -> {
                if (!sldFontSize.isValueChanging()) {
                    btnApply.setDisable((int)sldFontSize.getValue() == lastSavedFontSize.get());
                }
            };

            sldFontSize.valueProperty().addListener(sliderListener);
            sldFontSize.valueChangingProperty().addListener(sliderListener);
            lastSavedFontSize.addListener(sliderListener);

            root.getChildren().addAll(sldFontSize, btnApply);

            Scene scene = new Scene(root, 200, 100);

            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
0 голосов
/ 03 августа 2020

Когда вы перемещаете ползунок, значение изменяется при каждом движении мыши. введите описание изображения здесь Таким образом, сравнение oldValue и newValue от слушателя не будет работать. Вам нужна другая стратегия.

Вы можете сохранить значение по умолчанию при инициализации и сравнить текущее значение со значением по умолчанию, когда мышь отпущена:

sldFontSize.setOnMouseReleased(event -> btnApply.setDisable(sldFontSize.getValue() == defaultValue));

Полный код:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Slider;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Sample extends Application {

    @Override
    public void start(Stage primaryStage) {
        try {
            VBox root = new VBox();

            Button btnApply = new Button("Apply");
            btnApply.setDisable(true);

            Slider sldFontSize = new Slider();
            sldFontSize.setMin(0);
            sldFontSize.setMax(2);
            sldFontSize.setValue(1);
            sldFontSize.setMajorTickUnit(1);
            sldFontSize.setMinorTickCount(0);
            sldFontSize.setBlockIncrement(1);
            sldFontSize.setSnapToTicks(true);
            sldFontSize.setShowTickMarks(true);
            sldFontSize.setShowTickLabels(true);

            double defaultValue = sldFontSize.getValue();
            sldFontSize.setOnMouseReleased(event -> btnApply.setDisable(sldFontSize.getValue() == defaultValue));

            root.getChildren().addAll(sldFontSize, btnApply);
            Scene scene = new Scene(root, 200, 100);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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