JavaFX-带有StackPane的ScrollPane-当viewportBounds更改时未布局StackPane的子级 [英] JavaFX - ScrollPane with StackPane - StackPane's children not layouted when viewportBounds change

查看:108
本文介绍了JavaFX-带有StackPane的ScrollPane-当viewportBounds更改时未布局StackPane的子级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So the main issue what i have is when clicking on a ScrollBar Button. The Viewport of the Scrollpane changes, but not the children (Node) of the pane. I have either to request the focus on the pane or click on the icon in the taskmenu, that the Viewport content get's refreshed. Swing does this automatically when you move the scrollbars.

是否存在另一种方法来使此功能如上所述并通过代码运行? 调用requestFocus()在我看来很奇怪.顺便说一句:每次遇到麻烦时,它都会突出显示.

Is there another way to get this functionality working as described above and by code? The call requestFocus() seems strange to me. By the way: it highlights everytime that bothers.

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

Here is what i got so far:

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);
} }

出于说明目的:

未按下滚动条按钮

按两次滚动条按钮

推荐答案

感谢Stackoverflow撰写这篇出色的文章: JavaFX ScrollPane在滚动时更新viewportBounds

Thanks Stackoverflow for this great article: JavaFX ScrollPane update viewportBounds on scroll

因此,我能够找到所需的解决方案. 见下文:

With that i was able to found the solution i needed. See below:

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先生的解决方案,但我尝试将这两个用例联系起来.

Unfortunately i wasn't able to upvote Mr. James_D's solution, but i try to link these both use cases.

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

Hope this one help others also. Cheers!

这篇关于JavaFX-带有StackPane的ScrollPane-当viewportBounds更改时未布局StackPane的子级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆