我们可以通过修改JavaFX中Minor的MajorTicks和Slider来创建预先创建的次要和主要标记。但我想让用户只能选择2, 4, 8, 16, 32
之类的预先配置的值。我们snapToTicks解决了一个问题,但
如何仅启用特定刻度线或禁用其他刻度线?
我可能只会从valueProperty过滤掉所需的值,但是有没有更智能的解决方案或本地执行方式?
由于JavaFX 2.2中存在一个错误,因此无法在SliderClass中格式化标签,因此您需要使用JavaFX 8.这些值仍然可能会被错误地计算出来。
我为JavaFX 2.2添加了修改版本
FunctionalSlider.java
公共类FunctionalSlider扩展Slider { private ReadOnlyDoubleWrapper functionValue = new ReadOnlyDoubleWrapper();
public FunctionalSlider() {
this.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
functionValue.set(Math.pow(2, getValue()));
}
});
this.setLabelFormatter(new StringConverter<Double>() {
@Override
public Double fromString(String string) {
return 0.0;
}
@Override
public String toString(Double object) {
return String.format("%1$.0f", Math.pow(2, object));
}
});
}
public double getFunctionValue() {
return functionValue.get();
}
public ReadOnlyDoubleProperty functionValueProperty() {
return functionValue.getReadOnlyProperty();
}
}
FunctionalSliderSample
public class FunctionalSliderSample extends Application {
private final ListView<String> startLog = new ListView<String>();
private final ListView<String> endLog = new ListView<String>();
@Override public void start(Stage stage) throws Exception {
Pane logsPane = createLogsPane();
Slider slider = createMonitoredSlider();
VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.setPadding(new Insets(10));
layout.getChildren().setAll(
slider,
logsPane
);
VBox.setVgrow(logsPane, Priority.ALWAYS);
stage.setTitle("Slider Value Change Logger");
stage.setScene(new Scene(layout));
stage.show();
}
private Slider createMonitoredSlider() {
final FunctionalSlider slider = new FunctionalSlider();
slider.setMin(0);
slider.setValue(1);
slider.setMax(5);
slider.setMajorTickUnit(1);
slider.setMinorTickCount(0);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setSnapToTicks(true);
slider.setMinHeight(Slider.USE_PREF_SIZE);
slider.valueChangingProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
slider.setValue(Math.round(slider.getValue()));
String valueString = String.format("%1$.0f", slider.getFunctionValue());
if (slider.valueChangingProperty().get()) {
startLog.getItems().add(valueString);
}
else {
endLog.getItems().add(valueString);
}
}
});
return slider;
}
private HBox createLogsPane() {
HBox logs = new HBox(10);
logs.getChildren().addAll(
createLabeledLog("Start", startLog),
createLabeledLog("End", endLog)
);
return logs;
}
public Pane createLabeledLog(String logName, ListView<String> log) {
Label label = new Label(logName);
label.setLabelFor(log);
VBox logPane = new VBox(5);
logPane.getChildren().setAll(
label,
log
);
logPane.setAlignment(Pos.TOP_LEFT);
return logPane;
}
public static void main(String[] args) { launch(args); }
}
答案 0 :(得分:2)
以下是基于早期示例代码的答案:JavaFX 2.2: Hooking Slider Drag n Drop Events。
示例使用FunctionalSlider
类扩展Slider,该类以DoubleFunction为参数。 DoubleFunction
使用滑块labelFormatter创建自定义刻度标签的应用。 DoubleFunction
还为functionValue
属性提供值,该属性表示在给定刻度标记处评估的函数的值。该代码使用Java 8。
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.util.StringConverter;
import java.util.function.DoubleFunction;
class FunctionalSlider extends Slider {
private ReadOnlyDoubleWrapper functionValue = new ReadOnlyDoubleWrapper();
public FunctionalSlider(DoubleFunction<Double> function) {
valueProperty().addListener(observable ->
functionValue.set(
function.apply(getValue())
)
);
setLabelFormatter(new StringConverter<Double>() {
@Override
public String toString(Double x) {
return String.format(
"%1$.0f",
function.apply(x)
);
}
@Override
public Double fromString(String s) {
return null;
}
});
}
public double getFunctionValue() {
return functionValue.get();
}
public ReadOnlyDoubleProperty functionValueProperty() {
return functionValue.getReadOnlyProperty();
}
}
public class FunctionalSliderSample extends Application {
private final ListView<String> startLog = new ListView<>();
private final ListView<String> endLog = new ListView<>();
@Override public void start(Stage stage) throws Exception {
Pane logsPane = createLogsPane();
Slider slider = createMonitoredSlider();
VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.setPadding(new Insets(10));
layout.getChildren().setAll(
slider,
logsPane
);
VBox.setVgrow(logsPane, Priority.ALWAYS);
stage.setTitle("Slider Value Change Logger");
stage.setScene(new Scene(layout));
stage.show();
}
private Slider createMonitoredSlider() {
final FunctionalSlider slider = new FunctionalSlider(
x -> Math.pow(2, x)
);
slider.setMin(0);
slider.setValue(1);
slider.setMax(5);
slider.setMajorTickUnit(1);
slider.setMinorTickCount(0);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setSnapToTicks(true);
slider.setMinHeight(Slider.USE_PREF_SIZE);
slider.valueChangingProperty().addListener(observable -> {
slider.setValue(Math.round(slider.getValue()));
String valueString = String.format(
"%1$.2f",
slider.getFunctionValue()
);
if (slider.valueChangingProperty().get()) {
startLog.getItems().add(
valueString
);
} else {
endLog.getItems().add(
valueString
);
}
});
return slider;
}
private HBox createLogsPane() {
HBox logs = new HBox(10);
logs.getChildren().addAll(
createLabeledLog("Start", startLog),
createLabeledLog("End", endLog)
);
return logs;
}
public Pane createLabeledLog(String logName, ListView<String> log) {
Label label = new Label(logName);
label.setLabelFor(log);
VBox logPane = new VBox(5);
logPane.getChildren().setAll(
label,
log
);
logPane.setAlignment(Pos.TOP_LEFT);
return logPane;
}
public static void main(String[] args) { launch(args); }
}