JavaFX - 带有StackPane的ScrollPane - 当viewportBounds发生更改时,StackPane的子项不会被覆盖

时间:2018-06-05 17:35:33

标签: javafx

所以我点击ScrollBar按钮的主要问题是。 Scrollpane的视口会更改,但不会更改窗格的子节点(Node)。 我要么在窗格上请求焦点,要么单击任务菜单中的图标,以便刷新Viewport内容。 移动滚动条时,Swing会自动执行此操作。

是否有其他方法可以使此功能按上述方式和代码运行? 调用requestFocus()对我来说似乎很奇怪。顺便说一下:它每次都会引起困扰。

这是我到目前为止所得到的:

public class ScrollPaneTest extends Application {
private ScrollPane scrollPane;
private StackPane stackPane;
private Pane pane;
private Button button;

@Override
public void start(Stage primaryStage) throws Exception {

    scrollPane = new ScrollPane();
    stackPane = new StackPane();
    pane = new Pane();
    button = new Button();

    scrollPane.setPrefHeight(400.0);
    scrollPane.setPrefWidth(600.0);

    stackPane.setPrefHeight(1000.0);
    stackPane.setPrefWidth(1000.0);

    pane.setPrefHeight(200.0);
    pane.setPrefWidth(200.0);

    button.setMnemonicParsing(false);
    button.setText("Button");

    pane.getChildren().add(button);
    stackPane.getChildren().add(pane);        

    scrollPane.setContent(stackPane);      

    scrollPane.viewportBoundsProperty().addListener(new ChangeListener() {
        @Override
        public void changed(ObservableValue observable, Object oldValue, Object newValue) {
            Bounds oldViewportBounds = (Bounds) oldValue;
            Bounds newViewportBounds = (Bounds) newValue;       

            double x = newViewportBounds.getMinX() * -1;
            double y = newViewportBounds.getMinY() * -1;

            button.setLayoutX(x);
            button.setLayoutY(y);

            // Working if focus is requested ...
            //pane.requestFocus();
            // ... or when clicked on the application icon in the taskmenu of windows

            // Doesn't work
            //pane.requestLayout();

        }
    });

    VBox vbox = new VBox();
    vbox.setPrefHeight(400.0);
    vbox.setPrefWidth(600.0);

    vbox.getChildren().add(scrollPane);

    Scene scene = new Scene(vbox);
    primaryStage.setScene(scene);
    primaryStage.show();        

}

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

出于说明目的:

Scrollbar button not pressed

Scrollbar button pressed twice

1 个答案:

答案 0 :(得分:0)

感谢Stackoverflow这篇精彩的文章: JavaFX ScrollPane update viewportBounds on scroll

随着我能够找到我需要的解决方案。 见下文:

public class ScrollPaneTest extends Application {

private ScrollPane scrollPane;
private StackPane stackPane;
private Pane pane;
private Button button;

@Override
public void start(Stage primaryStage) throws Exception {

    scrollPane = new ScrollPane();
    stackPane = new StackPane();
    pane = new Pane() {
        @Override
        protected void layoutChildren(){              
            super.layoutChildren();
            // System.out.println("layout children");  
            // more ToDo's if neccessary...
        }
    };

    // so that the Pane can be smaller than (potentionally) other Panes inside of the StackPane        
    pane.setManaged(false);
    // set the dimension of the ScrollPane
    pane.setPrefHeight(400.0);
    pane.setPrefWidth(600.0);        

    button = new Button();
    button.setLayoutX(25);
    button.setLayoutY(25);

    scrollPane.setPrefHeight(400.0);
    scrollPane.setPrefWidth(600.0);

    stackPane.setPrefHeight(1000.0);
    stackPane.setPrefWidth(1000.0);

    button.setMnemonicParsing(false);
    button.setText("Button");

    pane.getChildren().add(button);
    stackPane.getChildren().add(pane);        

    scrollPane.setContent(stackPane);

    scrollPane.hvalueProperty().addListener(new ChangeListener<Number>() {
        @Override
        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
            //System.out.println("observable " + observable + " oldValue " + oldValue + " " + "newValue " + newValue);
            double hmin = scrollPane.getHmin();
            double hmax = scrollPane.getHmax();
            double hvalue = scrollPane.getHvalue();
            double contentWidth = scrollPane.getContent().getLayoutBounds().getWidth();
            double viewportWidth = scrollPane.getViewportBounds().getWidth();

            double hoffset = 
            Math.max(0, contentWidth - viewportWidth) * (hvalue - hmin) / (hmax - hmin);

            pane.setLayoutX(hoffset);
            pane.requestLayout();                
        }
    });        

    scrollPane.vvalueProperty().addListener(new ChangeListener<Number>() {
        @Override
        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
            //System.out.println("observable " + observable + " oldValue " + oldValue + " " + "newValue " + newValue);
            double vmin = scrollPane.getVmin();
            double vmax = scrollPane.getVmax();
            double vvalue = scrollPane.getVvalue();
            double contentHeight = scrollPane.getContent().getLayoutBounds().getHeight();
            double viewportHeight = scrollPane.getViewportBounds().getHeight();

            double voffset = 
            Math.max(0, contentHeight - viewportHeight) * (vvalue - vmin) / (vmax - vmin);

            pane.setLayoutY(voffset);
            pane.requestLayout();
        }
    });

    VBox vbox = new VBox();
    vbox.setPrefHeight(400.0);
    vbox.setPrefWidth(600.0);

    vbox.getChildren().add(scrollPane);

    Scene scene = new Scene(vbox);
    primaryStage.setScene(scene);
    primaryStage.show();        

}

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

不幸的是,我无法提升James_D先生的解决方案,但我尝试将这两种用例联系起来。

希望这个人也帮助别人。干杯!