如何设置/记住JavaFX 8 WebView中的滚动条缩略图位置?

时间:2015-07-07 09:31:40

标签: java webview webkit javafx-8

我对JavaFX 8 WebView及其滚动条有疑问。

我想重新加载HTML文档并记住当前的垂直滚动条位置。不幸的是,每当我重新加载文档时,滚动条就会移动到其初始位置。如何强制滚动条记住它的位置?

我试图解决这个问题:

通过WebView#lookup(String id)(请参阅1),可以访问WebView实例的垂直和水平ScrollBar实例。这允许我通过ScrollBar#getValue()获取当前滚动条值,即拇指位置。不幸的是,通过ScrollBar#setValue(double value)设置值并没有达到预期的效果。滚动条的拇指位置保持不变。

此外,我怀疑JavaFX滚动条没有呈现。相反,似乎显示了具有类似样式的WebKit滚动条。至少通过 Scenic View 进行简短的场景图分析给了我这样的印象。

这是一个JavaFX错误吗?有没有办法达到预期的行为?

以下示例程序演示了 setValue() - 问题:

import java.util.Set;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

/**
 * ScrollBar bug in JavaFX 8 WebView?
 * 
 * @author Michael Hoffer <info@michaelhoffer.de>
 */
public class WebViewAndItsScrollBars extends Application {

    @Override
    public void start(Stage primaryStage) {

        // create webview and load content
        WebView view = new WebView();
        view.getEngine().load(
                "https://docs.oracle.com/javase/8/javafx/"
                + "api/javafx/scene/control/ScrollBar.html");

        // vertical scrollbar of the webview
        ScrollBar vScrollBar = getVScrollBar(view);

        // change scrollbar value, i.e., thumb position via button
        Button btn = new Button();
        btn.setText("Move ScrollBar");
        btn.setOnAction((ActionEvent event) -> {
            if (vScrollBar != null) {
                double value = 2000;
                System.out.println(">> current value: " + vScrollBar.getValue());
                System.out.println(">> setting scrollbar value to " + value);
                vScrollBar.setValue(value);
            }
        });

        // create root layout
        VBox root = new VBox();
        root.setAlignment(Pos.CENTER);
        root.getChildren().add(view);
        root.getChildren().add(btn);

        // setup and show stage
        Scene scene = new Scene(root, 1024, 600);
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    /**
     * Returns the vertical scrollbar of the webview.
     *
     * @param webView webview
     * @return vertical scrollbar of the webview or {@code null} if no vertical
     * scrollbar exists
     */
    private ScrollBar getVScrollBar(WebView webView) {

        Set<Node> scrolls = webView.lookupAll(".scroll-bar");
        for (Node scrollNode : scrolls) {
            if (ScrollBar.class.isInstance(scrollNode)) {
                ScrollBar scroll = (ScrollBar) scrollNode;
                if (scroll.getOrientation() == Orientation.VERTICAL) {
                    return scroll;
                }
            }
        }
        return null;
    }
}

相关问题:How to hide scrollbars in the JavaFX WebView

1 个答案:

答案 0 :(得分:7)

我找到了解决方案:

使用JavaScript可以实现所需的行为。大多数代码示例都是通过WebView#getEngine()#loadContent(String content)将JavaScript代码直接注入到内容中。但是,对于URL,这不起作用。但是Web引擎提供了一种直接执行JavaScript的方法:

webView.getEngine().executeScript("// javascript code");

以下是我用于控制滚动条的方法:

    /**
     * Scrolls to the specified position.
     * @param view web view that shall be scrolled
     * @param x horizontal scroll value
     * @param y vertical scroll value
     */
    public void scrollTo(WebView view, int x, int y) {
        view.getEngine().executeScript("window.scrollTo(" + x + ", " + y + ")");
    }

    /**
     * Returns the vertical scroll value, i.e. thumb position.
     * This is equivalent to {@link javafx.scene.control.ScrollBar#getValue().
     * @param view
     * @return vertical scroll value
     */
    public int getVScrollValue(WebView view) {
        return (Integer) view.getEngine().executeScript("document.body.scrollTop");
    }

    /**
     * Returns the horizontal scroll value, i.e. thumb position.
     * This is equivalent to {@link javafx.scene.control.ScrollBar#getValue()}.
     * @param view
     * @return horizontal scroll value
     */
    public int getHScrollValue(WebView view) {
        return (Integer) view.getEngine().executeScript("document.body.scrollLeft");
    }

    /**
     * Returns the maximum vertical scroll value. 
     * This is equivalent to {@link javafx.scene.control.ScrollBar#getMax()}.
     * @param view 
     * @return vertical scroll max
     */
    public int getVScrollMax(WebView view) {
        return (Integer) view.getEngine().executeScript("document.body.scrollWidth");
    }

    /**
     * Returns the maximum horizontal scroll value. 
     * This is equivalent to {@link javafx.scene.control.ScrollBar#getMax()}.
     * @param view 
     * @return horizontal scroll max
     */
    public int getHScrollMax(WebView view) {
        return (Integer) view.getEngine().executeScript("document.body.scrollHeight");
    }

以下是问题代码的工作版本:

import java.util.Set;
import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

/**
 * ScrollBar bug in JavaFX 8 WebView?
 *
 * @author Michael Hoffer &lt;info@michaelhoffer.de&gt;
 */
public class WebViewAndItsScrollBars extends Application {

    @Override
    public void start(Stage primaryStage) {

        // create webview and load content
        WebView view = new WebView();

        view.getEngine().load(
                "https://docs.oracle.com/javase/8/javafx/"
                + "api/javafx/scene/control/ScrollBar.html");

        // change scrollbar value, i.e., thumb position via button
        Button btn = new Button();
        btn.setText("Move ScrollBar");
        btn.setOnAction((ActionEvent event) -> {

            int value = 2000;
            System.out.println(">> current value: " + getVScrollValue(view));
            System.out.println(">> setting scrollbar value to " + value);
            scrollTo(view, 0, value);

        });

        // create root layout
        VBox root = new VBox();
        root.setAlignment(Pos.CENTER);
        root.getChildren().add(view);
        root.getChildren().add(btn);

        // setup and show stage
        Scene scene = new Scene(root, 1024, 600);
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    /**
     * Scrolls to the specified position.
     * @param view web view that shall be scrolled
     * @param x horizontal scroll value
     * @param y vertical scroll value
     */
    public void scrollTo(WebView view, int x, int y) {
        view.getEngine().executeScript("window.scrollTo(" + x + ", " + y + ")");
    }

    /**
     * Returns the vertical scroll value, i.e. thumb position.
     * This is equivalent to {@link javafx.scene.control.ScrollBar#getValue().
     * @param view
     * @return vertical scroll value
     */
    public int getVScrollValue(WebView view) {
        return (Integer) view.getEngine().executeScript("document.body.scrollTop");
    }

    /**
     * Returns the horizontal scroll value, i.e. thumb position.
     * This is equivalent to {@link javafx.scene.control.ScrollBar#getValue()}.
     * @param view
     * @return horizontal scroll value
     */
    public int getHScrollValue(WebView view) {
        return (Integer) view.getEngine().executeScript("document.body.scrollLeft");
    }

    /**
     * Returns the maximum vertical scroll value. 
     * This is equivalent to {@link javafx.scene.control.ScrollBar#getMax()}.
     * @param view 
     * @return vertical scroll max
     */
    public int getVScrollMax(WebView view) {
        return (Integer) view.getEngine().executeScript("document.body.scrollWidth");
    }

    /**
     * Returns the maximum horizontal scroll value. 
     * This is equivalent to {@link javafx.scene.control.ScrollBar#getMax()}.
     * @param view 
     * @return horizontal scroll max
     */
    public int getHScrollMax(WebView view) {
        return (Integer) view.getEngine().executeScript("document.body.scrollHeight");
    }
}