JavaFX - 将滑块绑定到按钮的禁用 属性
JavaFX - Binding Slider to Button's Disable Property
我试图仅在 Slider 的 Thumb 超过新值(或位置)时启用 Button。
下面是window的初始状态:
只要我开始拖动 Thumb,按钮就会被激活,即使 Thumb 还没有超过新值(即使在值之间也被激活):
如果我中止拖动操作(释放鼠标按钮)和 Thumb returns 到初始位置(或值),按钮不会被禁用。
代码:
private void configSldFontSize() {
sldFontSize.valueProperty().addListener((ov, oldValue, newValue) -> {
if (oldValue == newValue) {
btnApply.setDisable(true);
} else {
btnApply.setDisable(false);
}
});
}
可能是配置错误?
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<Double>() {
@Override
public Double fromString(String arg0) {
return null;
}
@Override
public String toString(Double obj) {
int i = obj.intValue();
return FontSize.values()[i].toString();
}
});
}
======= 复制条件的小代码实现 ==========
注意:
我正在使用 Java 11(我想 Java 8 没有必要)。因此可能有必要在“运行 配置”中包含以下行。
在 Package Explorer 中:鼠标右键点击“Main.Java => 运行 As => 运行 配置...”,select “(x) = Arguments" 选项卡并将行如下图所示,正在更改您的 JAVAFX LIB 文件夹的路径。
代码
Main.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);
}
}
当您移动滑块时,每次鼠标移动时值都会发生变化。
所以比较 oldValue
和 newValue
来自 listener 是行不通的。你需要另一个策略。
您可以在初始化时保存默认值,并在释放鼠标时将当前值与默认值进行比较:
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);
}
}
一般来说,您可以创建一个单独的 属性 来表示您希望从滑块获得的实际值,然后向该 属性 注册一个侦听器。请注意,更改侦听器仅在值实际更改时才会收到通知,因此侦听器中的 if (oldValue==newValue)
将始终为 false。
在这种情况下,由于感兴趣的值只是将滑块值转换为 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));
为了更精确,您可以实现舍入而不是简单地转换等。您可能还想保存“最后应用的值”并在决定是否 disable/enable 按钮时与它进行比较,等等
将所有这些放在一起你会得到类似的东西:
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);
}
}
我试图仅在 Slider 的 Thumb 超过新值(或位置)时启用 Button。
下面是window的初始状态:
只要我开始拖动 Thumb,按钮就会被激活,即使 Thumb 还没有超过新值(即使在值之间也被激活):
如果我中止拖动操作(释放鼠标按钮)和 Thumb returns 到初始位置(或值),按钮不会被禁用。
代码:
private void configSldFontSize() {
sldFontSize.valueProperty().addListener((ov, oldValue, newValue) -> {
if (oldValue == newValue) {
btnApply.setDisable(true);
} else {
btnApply.setDisable(false);
}
});
}
可能是配置错误?
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<Double>() {
@Override
public Double fromString(String arg0) {
return null;
}
@Override
public String toString(Double obj) {
int i = obj.intValue();
return FontSize.values()[i].toString();
}
});
}
======= 复制条件的小代码实现 ==========
注意:
我正在使用 Java 11(我想 Java 8 没有必要)。因此可能有必要在“运行 配置”中包含以下行。
在 Package Explorer 中:鼠标右键点击“Main.Java => 运行 As => 运行 配置...”,select “(x) = Arguments" 选项卡并将行如下图所示,正在更改您的 JAVAFX LIB 文件夹的路径。
代码 Main.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);
}
}
当您移动滑块时,每次鼠标移动时值都会发生变化。
oldValue
和 newValue
来自 listener 是行不通的。你需要另一个策略。
您可以在初始化时保存默认值,并在释放鼠标时将当前值与默认值进行比较:
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);
}
}
一般来说,您可以创建一个单独的 属性 来表示您希望从滑块获得的实际值,然后向该 属性 注册一个侦听器。请注意,更改侦听器仅在值实际更改时才会收到通知,因此侦听器中的 if (oldValue==newValue)
将始终为 false。
在这种情况下,由于感兴趣的值只是将滑块值转换为 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));
为了更精确,您可以实现舍入而不是简单地转换等。您可能还想保存“最后应用的值”并在决定是否 disable/enable 按钮时与它进行比较,等等
将所有这些放在一起你会得到类似的东西:
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);
}
}