如何在属性侦听器中设置其他值?

时间:2016-01-16 17:30:00

标签: scroll javafx listener

我想加快我的ScrollPane滚动速度。我需要这样的东西:

scrollPane.vvalueProperty().addListener((observable, oldValue, newValue) -> {
            scrollPane.setVvalue(oldValue.doubleValue() + (newValue.doubleValue() - oldValue.doubleValue()) * 2);
        });

但没有stackowerflow执行和工作..

可能有办法像活动那样消费吗?

P.S。顺便说一句,为什么setOnScroll()仅在滚动达到max(top)或min(bot)位置时触发?

2 个答案:

答案 0 :(得分:2)

我真的不建议在属性已经改变时修改它,但如果你想这样做,你需要设置一个标志来抑制递归调用。这是一个例子:

import java.util.Random;

import javafx.application.Application;
import javafx.beans.property.Property;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.TilePane;
import javafx.stage.Stage;

public class ModifyScrollSpeed extends Application {

    @Override
    public void start(Stage primaryStage) {
        ScrollPane scrollPane = new ScrollPane(createContent());
        DoublingListener.register(scrollPane.vvalueProperty());

        Scene scene = new Scene(scrollPane, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    private static class DoublingListener implements ChangeListener<Number> {

        private boolean doubling ;

        private Property<Number> target ;

        private DoublingListener(Property<Number> target) {
            this.target = target ;
        }

        public static void register(Property<Number> target) {
            target.addListener(new DoublingListener(target));
        }

        @Override
        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
            if (! doubling) {
                doubling = true ;
                target.setValue(oldValue.doubleValue() + 2 * (newValue.doubleValue() - oldValue.doubleValue()));
            }
            doubling = false ;
        }

    }

    private Node createContent() {
        TilePane tilePane = new TilePane();
        Random rng = new Random();
        for (int i = 0; i < 200; i++) {
            Region region = new Region();
            region.setMinSize(40,  40);
            region.setPrefSize(40, 40);
            region.setMaxSize(40, 40);
            region.setStyle(String.format("-fx-background-color: #%02x%02x%02x;", 
                    rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)));
            tilePane.getChildren().add(region);
        }
        return tilePane ;
    }

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

我实际上没有看到任何其他方法来更改滚动窗格的增量。请注意,ScrollBar具有用于通过其unitIncrementblockIncrement属性更改增量金额的API,但ScrollPane没有等效属性。

source code for ScrollPane中有评论

/*
 * TODO The unit increment and block increment variables have been
 * removed from the public API. These are intended to be mapped to
 * the corresponding variables of the scrollbars. However, the problem
 * is that they are specified in terms of the logical corrdinate space
 * of the ScrollPane (that is, [hmin..hmax] by [vmin..vmax]. This is
 * incorrect. Scrolling is a user action and should properly be based
 * on how much of the content is visible, not on some abstract
 * coordinate space. At some later date we may add a finer-grained
 * API to allow applications to control this. Meanwhile, the skin should
 * set unit and block increments for the scroll bars to do something
 * reasonable based on the viewport size, e.g. the block increment
 * should scroll 90% of the pixel size of the viewport, and the unit
 * increment should scroll 10% of the pixel size of the viewport.
 */

滚动窗格的当前skin以此评论中描述的方式硬编码单位并阻止其滚动条(在updateHorizontalSBupdateVerticalSB方法中)的增量(即10%和90%的可见量),所以我认为没有真正的方法来实现这些目标。在Java 9中,skin类将成为一个公共类,因此至少可以将它子类化并修改此行为。

答案 1 :(得分:0)

您可以尝试这样的事情 -

private boolean scrolllChanging = false; 

private void myScroll(ObservableDoubleValue observable, Double oldValue, Double newValue) {
    if (!scrollChanging) {
        try {
            scrollChanging = true; 
            // Insert logic here. Any subsequent changes won't reach here until `scrollChanging` is set to false again. 
        } finally {
            scrollChanging = false; 
        }
    }
}

scrollPane.vvalueProperty().addListener(this::myScroll);

原谅任何次要类型的错误,我还没有编译过。