Java 拖动后滚动窗格内容变得模糊

Java 拖动后滚动窗格内容变得模糊,java,javafx-8,Java,Javafx 8,JavaFX8.0有这个bug,我不知道如何解决它。 例如: 如果我拖动滚动窗格,其内容会变得模糊,但如果我将其向后拖动,内容会恢复其清晰度。如果我不修改coords,内容看起来很好 有人解决了这个问题吗 示例代码: @覆盖 公众假期开始(阶段){ 窗格=新窗格(); 场景=新场景(窗格,500500); pane.prefWidthProperty().bind(scene.widthProperty()); pane.prefHeightProperty().bind(scene.heig

JavaFX8.0有这个bug,我不知道如何解决它。
例如:

如果我拖动滚动窗格,其内容会变得模糊,但如果我将其向后拖动,内容会恢复其清晰度。如果我不修改coords,内容看起来很好

有人解决了这个问题吗

示例代码:

@覆盖
公众假期开始(阶段){
窗格=新窗格();
场景=新场景(窗格,500500);
pane.prefWidthProperty().bind(scene.widthProperty());
pane.prefHeightProperty().bind(scene.heightProperty());
ScrollPane scroll=新建ScrollPane();
//中央滚动窗格
scroll.layoutXProperty().bind(pane.widthProperty().divide(2)、subtract(scroll.widthProperty().divide(2));
scroll.layoutYProperty();
scroll.setPrefSize(200200);
ListView列表=新建ListView();
滚动设置内容(列表);
list.getItems().addAll(“调整窗口大小”,“并查看此列表如何变得模糊”);
//标签表示ScrolPane的x,y坐标及其比率。
TextField size=新的TextField();
尺寸、宽度(500);
size.textProperty().bind(
scroll.layoutXProperty()文件
.asString(“x:%s;”)。concat(
scroll.layoutYProperty()
.asString(“y:%s;”);
pane.getChildren().addAll(大小,滚动);
舞台场景;
stage.show();
}

我检查了内部皮肤代码,发现了一个解决方案,但并不漂亮。问题出在com.sun.javafx.scene.control.skin.ScrollPaneSkin内部,它调用viewRect.setCache(true)。禁用缓存似乎可以解决此问题

PS:TitledPane中的cache属性也设置为true,这与JavaFX8中的问题相同

ScrollPane2.java

<!-- language: lang-java -->

import javafx.scene.control.ScrollPane;
import javafx.scene.control.Skin;

public class ScrollPane2 extends ScrollPane
{
    @Override
    protected Skin<?> createDefaultSkin()
    {
        return new ScrollPaneSkin2(this);
    }
}
<!-- language: lang-java -->
import java.lang.reflect.Field;

import javafx.scene.control.ScrollPane;
import javafx.scene.layout.StackPane;

import com.sun.javafx.scene.control.skin.ScrollPaneSkin;

class ScrollPaneSkin2 extends ScrollPaneSkin
{
    private static Field viewRectField;

    static
    {
        try
        {
            viewRectField = ScrollPaneSkin.class.getDeclaredField("viewRect");
            viewRectField.setAccessible(true);
        }
        catch (ReflectiveOperationException e)
        {
            throw new RuntimeException(e);
        }
    }

    private StackPane viewRect;

    public ScrollPaneSkin2(final ScrollPane scrollpane)
    {
        super(scrollpane);
        try
        {
            this.viewRect = (StackPane) viewRectField.get(this);
        }
        catch (ReflectiveOperationException e)
        {
            throw new RuntimeException(e);
        }
        this.viewRect.setCache(false);
    }
}

导入javafx.scene.control.ScrollPane;
导入javafx.scene.control.Skin;
公共类ScrollPane2扩展了ScrollPane
{
@凌驾
受保护的皮肤createDefaultSkin()
{
返回新的滚动窗格kin2(此);
}
}
滚动窗格kin2.java

<!-- language: lang-java -->

import javafx.scene.control.ScrollPane;
import javafx.scene.control.Skin;

public class ScrollPane2 extends ScrollPane
{
    @Override
    protected Skin<?> createDefaultSkin()
    {
        return new ScrollPaneSkin2(this);
    }
}
<!-- language: lang-java -->
import java.lang.reflect.Field;

import javafx.scene.control.ScrollPane;
import javafx.scene.layout.StackPane;

import com.sun.javafx.scene.control.skin.ScrollPaneSkin;

class ScrollPaneSkin2 extends ScrollPaneSkin
{
    private static Field viewRectField;

    static
    {
        try
        {
            viewRectField = ScrollPaneSkin.class.getDeclaredField("viewRect");
            viewRectField.setAccessible(true);
        }
        catch (ReflectiveOperationException e)
        {
            throw new RuntimeException(e);
        }
    }

    private StackPane viewRect;

    public ScrollPaneSkin2(final ScrollPane scrollpane)
    {
        super(scrollpane);
        try
        {
            this.viewRect = (StackPane) viewRectField.get(this);
        }
        catch (ReflectiveOperationException e)
        {
            throw new RuntimeException(e);
        }
        this.viewRect.setCache(false);
    }
}

导入java.lang.reflect.Field;
导入javafx.scene.control.ScrollPane;
导入javafx.scene.layout.StackPane;
导入com.sun.javafx.scene.control.skin.ScrollPaneSkin;
类ScrollPaneSkin2扩展了ScrollPaneSkin
{
私有静态字段viewRectField;
静止的
{
尝试
{
viewRectField=ScrollPaneSkin.class.getDeclaredField(“viewRect”);
viewRectField.setAccessible(true);
}
捕捉(反射操作异常e)
{
抛出新的运行时异常(e);
}
}
私有StackPane viewRect;
公共滚动窗格Kin2(最终滚动窗格)
{
超级(滚动窗格);
尝试
{
this.viewRect=(StackPane)viewRectField.get(this);
}
捕捉(反射操作异常e)
{
抛出新的运行时异常(e);
}
this.viewRect.setCache(false);
}
}

禁用缓存可能会降低性能,但我没有注意到任何降低。

推荐方法-使用内置布局管理器+大小调整提示

除非需要,否则我建议不要设置节点的布局值。相反,如果使用标准布局容器,则默认情况下,它(应)将任何非整数布局坐标捕捉为整数值,从而使系统的布局清晰,而不会因分数布局值的消除混叠而导致模糊,这会导致文本和行不直接在屏幕像素网格上对齐

没有模糊性的示例代码

当我在我的机器上运行一个修改过的示例时,它不通过绑定执行布局,而是只使用布局管理器进行布局,我没有观察和模糊值(win 7,JavaFX 8u20)。我也不需要修改默认的节点缓存提示

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

public class NonBlurryPane extends Application {

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

    @Override
    public void start(Stage stage) {
        VBox pane = new VBox();

        pane.setPrefSize(500, 500);

        Scene scene = new Scene(pane);

        ScrollPane scroll = new ScrollPane();
        StackPane scrollContainer = new StackPane(scroll);
        VBox.setVgrow(scrollContainer, Priority.ALWAYS);

        // Center ScrollPane
        scroll.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
        scroll.setPrefSize(200, 200);
        scroll.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);

        ListView<String> list = new ListView<>();
        scroll.setContent(list);

        list.getItems().addAll("Resize the window", "and see how this list", "does NOT become blurry");

        // Label indicates x, y coords of ScrolPane and their ratio.
        TextField size = new TextField();
        size.setMaxWidth(Double.MAX_VALUE);
        size.setMinHeight(Region.USE_PREF_SIZE);
        size.textProperty().bind(
                scroll.layoutXProperty()
                        .asString("x: %s; ").concat(
                        scroll.layoutYProperty()
                                .asString("y: %s; ")).concat(
                        scroll.layoutXProperty().divide(scroll.layoutYProperty())
                                .asString("x/y: %s; ")).concat(
                        scroll.layoutYProperty().divide(scroll.layoutXProperty())
                                .asString("y/x: %s")));

        pane.getChildren().addAll(size, scrollContainer);

        stage.setScene(scene);
        stage.show();
    }
}

导入javafx.application.application;
导入javafx.scene.scene;
导入javafx.scene.control.*;
导入javafx.scene.layout.*;
导入javafx.stage.stage;
公共类非模糊窗格扩展应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公众假期开始(阶段){
VBox窗格=新的VBox();
窗格大小(500500);
场景=新场景(窗格);
ScrollPane scroll=新建ScrollPane();
StackPane scrollContainer=新的StackPane(滚动);
setVgrow(scrollContainer,Priority.ALWAYS);
//中央滚动窗格
scroll.setMinSize(Region.USE\u PREF\u SIZE,Region.USE\u PREF\u SIZE);
scroll.setPrefSize(200200);
scroll.setMaxSize(Region.USE\u PREF\u SIZE,Region.USE\u PREF\u SIZE);
ListView列表=新建ListView();
滚动设置内容(列表);
list.getItems().addAll(“调整窗口大小”,“并查看此列表如何”不会变得模糊”);
//标签表示ScrolPane的x,y坐标及其比率。
TextField size=新的TextField();
size.setMaxWidth(双倍最大值);
size.setMinHeight(Region.USE_PREF_size);
size.textProperty().bind(
scroll.layoutXProperty()文件
.asString(“x:%s;”)。concat(
scroll.layoutYProperty()
.asString(“y:%s;”)。concat(
scroll.layoutYProperty().divide(scroll.layoutYProperty())
.asString(“x/y:%s;”).concat(
scroll.layoutYProperty().divide(scroll.layoutYProperty())
.asString(“y/x:%s”);
pane.getChildren().addAll(大小,滚动容器);
舞台场景;
stage.show();
}
}
我还注意到,默认布局管理器将双坐标舍入为整数坐标。这对我来说可能吗
.scroll-pane {
       -fx-background-color: -fx-box-border,-fx-background;
       -fx-background-insets: 0, 1;
       -fx-padding: 1.0;
}
public void fixBlurryText(ScrollPane scrollPane) {
    StackPane stackPane = (StackPane) scrollPane.lookup("ScrollPane .viewport");
    stackPane.setCache(false);
}