如何使用动画使JavaFX滑块旋钮仅移动到刻度线?

如何使用动画使JavaFX滑块旋钮仅移动到刻度线?,javafx,slider,Javafx,Slider,继续讨论这个问题,, 我添加了一个“播放”按钮和一个时间线,这样当用户单击“播放”按钮时,滑块的旋钮会重复前进到下一个刻度线,直到它到达滑块的末端或用户单击“停止”按钮。不幸的是,动画运行的时间越长,旋钮在刻度线之间移动的次数就越多(是的,setSnapToTicks是真的)。而且,滑块的值不是我所期望的。理想情况下,它应该是“-60,-59,-58等。”但时间轴一次以小分数移动滑块旋钮(例如,-55.188833335)。我在这个问题上绞尽脑汁已经很久了。这是我的密码: public clas

继续讨论这个问题,, 我添加了一个“播放”按钮和一个时间线,这样当用户单击“播放”按钮时,滑块的旋钮会重复前进到下一个刻度线,直到它到达滑块的末端或用户单击“停止”按钮。不幸的是,动画运行的时间越长,旋钮在刻度线之间移动的次数就越多(是的,
setSnapToTicks
是真的)。而且,滑块的值不是我所期望的。理想情况下,它应该是“-60,-59,-58等。”但时间轴一次以小分数移动滑块旋钮(例如,-55.188833335)。我在这个问题上绞尽脑汁已经很久了。这是我的密码:

public class SliderTest extends Application {
StringConverter<Double> stringConverter = new StringConverter<>() {

    @Override
    public String toString( Double object ) {
        long seconds = object.longValue();
        long minutes = TimeUnit.SECONDS.toMinutes( seconds );
        long remainingseconds = Math.abs( seconds - TimeUnit.MINUTES.toSeconds( minutes ) );
        return String.format( "%02d", minutes ) + ":" + String.format( "%02d", remainingseconds );
    }

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

@Override
public void start( Stage primaryStage ) throws Exception {
    try {
        Pane pane = new Pane();
        pane.setStyle( "-fx-background-color: black;" );

        Slider slider = new Slider( -60, 0, -60 );
        slider.setBlockIncrement( 60 );
        slider.setMajorTickUnit( 60 );
        slider.setMinorTickCount( 60 );
        slider.setShowTickLabels( true );
        slider.setShowTickMarks( true );
        slider.setSnapToTicks( true );
        slider.setLabelFormatter( stringConverter );
        slider.setPrefWidth( 1303 );

        Button playStopButton = new Button( "Play" );
        HBox buttonHBox = new HBox( playStopButton );
        buttonHBox.setAlignment( Pos.CENTER );
        Text sliderTime = new Text( "Time" );
        sliderTime.setFont( new Font( 12 ) );
        sliderTime.setFill( Color.WHITE );
        sliderTime.setText( stringConverter.toString( slider.getValue() ) );

        HBox hbox = new HBox( slider, sliderTime, buttonHBox );
        hbox.setPrefWidth( 1428 );
        hbox.setSpacing( 10 );
        hbox.setAlignment( Pos.TOP_CENTER );

        pane.getChildren().add( hbox );

        Scene scene = new Scene( pane );
        scene.getStylesheets().add( getClass().getResource( "/css/slider.css" ).toExternalForm() );
        primaryStage.setScene( scene );
        primaryStage.show();

        Timeline timeline = new Timeline(
                new KeyFrame( Duration.ZERO, new KeyValue( slider.valueProperty(), slider.getValue() ) ),
                new KeyFrame( Duration.seconds( -slider.getValue() ), new KeyValue( slider.valueProperty(), 0 ) ) );

        slider.valueProperty().addListener( ( observable, oldValue, newValue ) -> {
            slider.setValue( newValue.intValue() );
            
            System.out.println( slider.getValue() + " | " + newValue.doubleValue() );

            // Set the text to the slider's new value.
            sliderTime.setText( stringConverter.toString( slider.getValue() ) );

            if ( newValue.doubleValue() == 0 ) {
                // Reset the timeline and the text for the sliderButton.
                timeline.stop();
                timeline.getKeyFrames().clear();
                playStopButton.setText( "Stop" );
            }
        } );

        slider.setOnMousePressed( event -> {
            // On mouse down, reset the timeline.
            timeline.stop();
            timeline.getKeyFrames().clear();
        } );

        slider.setOnMouseReleased( event -> {
            // Set the new start position of the timeline.
            timeline.getKeyFrames().add(
                    new KeyFrame( Duration.ZERO, new KeyValue( slider.valueProperty(), slider.getValue() ) ) );
            timeline.getKeyFrames().add( new KeyFrame( Duration.seconds( -slider.getValue() ),
                    new KeyValue( slider.valueProperty(), 0 ) ) );

            // Play the animation only if it was playing before.
            if ( playStopButton.getText().equals( "Pause" ) ) {
                timeline.play();
            }
            // Change the image for the playStopButton to stop when the thumb is moved to zero.
            else if ( playStopButton.getText().equals( "Stop" ) && ( slider.getValue() < 0 ) ) {
                playStopButton.setText( "Play" );
            }
        } );

        playStopButton.setOnMouseClicked( event -> {
            // Ignore mouse clicks on the playStopButton when the slider is at time zero.
            if ( slider.getValue() != 0 ) {
                if ( ( timeline.getStatus() == Status.STOPPED ) || ( timeline.getStatus() == Status.PAUSED ) ) {
                    playStopButton.setText( "Pause" );
                    timeline.play();
                }
                else if ( timeline.getStatus() == Status.RUNNING ) {
                    playStopButton.setText( "Play" );
                    timeline.pause();
                }
            }
        } );
    } catch ( Exception e ) {
        e.printStackTrace();
    }
}

public static void main( String[] args ) {
    launch( args );
}
公共类SliderTest扩展应用程序{
StringConverter StringConverter=新的StringConverter(){
@凌驾
公共字符串toString(双对象){
long seconds=object.longValue();
长分钟=时间单位。秒。到分钟(秒);
long remainingseconds=Math.abs(秒-时间单位.MINUTES.toSeconds(分钟));
返回String.format(“%02d”,分钟)++”:“+String.format(“%02d”,剩余秒);
}
@凌驾
public Double fromString(字符串字符串){
返回null;
}
};
@凌驾
public void start(Stage primaryStage)引发异常{
试一试{
窗格=新窗格();
窗格.setStyle(“-fx背景色:黑色;”);
滑块=新滑块(-60,0,-60);
滑块。增量(60);
滑块。setMajorTickUnit(60);
slider.setMinorTickCount(60);
slider.setShowTickLabels(真);
滑块。设置显示标记(真);
slider.setSnapToTicks(真);
slider.setLabelFormatter(stringConverter);
滑块。设置预宽(1303);
按钮播放停止按钮=新按钮(“播放”);
HBox按钮盒=新的HBox(播放停止按钮);
按钮盒设置对齐(位置中心);
文本幻灯片时间=新文本(“时间”);
slidetime.setFont(新字体(12));
slidetime.setFill(Color.WHITE);
sliderTime.setText(stringConverter.toString(slider.getValue());
HBox HBox=新HBox(滑块、滑块时间、按钮框);
hbox.setPrefWidth(1428);
hbox.setspace(10);
hbox.设置校准(位置顶部\中心);
pane.getChildren().add(hbox);
场景=新场景(窗格);
scene.getStylesheets().add(getClass().getResource(“/css/slider.css”).toExternalForm());
初级阶段。场景(场景);
primaryStage.show();
时间线=新时间线(
新关键帧(Duration.ZERO、新KeyValue(slider.valueProperty()、slider.getValue()),
新的关键帧(Duration.seconds(-slider.getValue()),新的KeyValue(slider.valueProperty(),0));
slider.valueProperty().addListener((可观察、旧值、新值)->{
slider.setValue(newValue.intValue());
System.out.println(slider.getValue()+“|”+newValue.doubleValue());
//将文本设置为滑块的新值。
sliderTime.setText(stringConverter.toString(slider.getValue());
if(newValue.doubleValue()==0){
//重置时间线和滑块按钮的文本。
timeline.stop();
timeline.getKeyFrames().clear();
playStopButton.setText(“停止”);
}
} );
slider.setOnMousePressed(事件->{
//按下鼠标,重置时间线。
timeline.stop();
timeline.getKeyFrames().clear();
} );
slider.setOnMouseReleased(事件->{
//设置时间线的新开始位置。
timeline.getKeyFrames().add(
新关键帧(Duration.ZERO、新KeyValue(slider.valueProperty()、slider.getValue());
timeline.getKeyFrames().add(新的关键帧(持续时间.seconds(-slider.getValue()),
新的键值(slider.valueProperty(),0));
//仅当动画之前正在播放时才播放动画。
if(playStopButton.getText().equals(“暂停”)){
timeline.play();
}
//将拇指移动到零时,将playStopButton的图像更改为stop。
else if(playStopButton.getText().equals(“Stop”)&&(slider.getValue()<0)){
playStopButton.setText(“播放”);
}
} );
播放停止按钮。设置鼠标单击(事件->{
//当滑块处于时间零点时,忽略鼠标单击PlayStop按钮。
如果(slider.getValue()!=0){
如果((timeline.getStatus()==Status.STOPPED)| |(timeline.getStatus()==Status.PAUSED)){
playStopButton.setText(“暂停”);
timeline.play();
}
else if(timeline.getStatus()==Status.RUNNING){
playStopButton.setText(“播放”);
timeline.pause();
}
}
} );
}捕获(例外e){
e、 printStackTrace();
}
}
公共静态void main(字符串[]args){
发射(args);
}

问题的一部分在于我对
滑块的设置。问题的另一部分在于我对
时间线的定义。基本上,我让Java来定义滑块按钮要移动到的所有值,而不管刻度线在哪里,这不是我想要的(虽然它确实有助于平滑动画)。但在进行以下更改后,滑块按钮每秒前进到下一个刻度线,这正是我想要的。与之前相比,滑块按钮始终位于两个刻度线之间

        slider.setMajorTickUnit( 1 );

        Timeline timeline = new Timeline(
                new KeyFrame( Duration.seconds( 1 ), event -> {
                    slider.setValue( slider.getValue() + 1 );
                } ) );
        timeline.setCycleCount( Math.abs( Double.valueOf( slider.getValue() ).intValue() ) );

不太了解你想要达到的目标..点击t