拖动后ScrollPane内容变得模糊

tur*_*hay 5 java javafx-8

JavaFX 8.0有此错误,我不知道如何解决。
示例:http//i.imgur.com/tavh6XA.png

如果拖动ScrollPane,其内容将变得模糊,但是如果将其拖动回,则内容将恢复其清晰度。如果我不修改坐标,则内容看起来会很好。

有人解决了这个问题吗?

示例代码:

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

    Scene scene = new Scene(pane, 500, 500);
    pane.prefWidthProperty().bind(scene.widthProperty());
    pane.prefHeightProperty().bind(scene.heightProperty());

    ScrollPane scroll = new ScrollPane();

    // Center ScrollPane
    scroll.layoutXProperty().bind(pane.widthProperty().divide(2).subtract(scroll.widthProperty().divide(2)));
    scroll.layoutYProperty().bind(pane.heightProperty().divide(2).subtract(scroll.heightProperty().divide(2)));
    scroll.setPrefSize(200, 200);

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

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

    // Label indicates x, y coords of ScrolPane and their ratio.
    TextField size = new TextField();
    size.setPrefWidth(500);
    size.textProperty().bind(
            scroll.layoutXProperty()
            .asString("x: %s; ").concat(
                    scroll.layoutYProperty()
                    .asString("y: %s; ")));

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

    stage.setScene(scene);
    stage.show();
}
Run Code Online (Sandbox Code Playgroud)

The*_*opo 6

我尝试了thebradness的答案,但java.lang.reflect.InaccessibleObjectException可能由于Java Platform Module System而获得了(Java 10)。我宁愿寻找另一种实现反射的方法,而不是寻找使反射起作用的解决方法。

检查ScrollPaneSkin内部代码后,我注意到将viewportcss类赋予该viewRect参数。所以我可以Node#lookup通过CSS选择器来实现,而不是通过反射来实现。

这是一种更简单易读的解决方案(并且可以在JAVA 9+中运行):

public void fixBlurryText(ScrollPane scrollPane) {
    StackPane stackPane = (StackPane) scrollPane.lookup("StackPane .viewport");
    stackPane.setCache(false);
}
Run Code Online (Sandbox Code Playgroud)

希望它会帮助别人。


AqD*_*AqD 5

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

PS:TitledPane中的cache属性也设置为true,从JavaFX 8开始就有同样的问题。

滚动窗格2.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);
    }
}
Run Code Online (Sandbox Code Playgroud)

ScrollPaneSkin2.java

<!-- 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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


jew*_*sea 3

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

我建议除非需要,否则不要设置节点的布局值。相反,如果您使用标准布局容器,那么它(应该)默认将任何非整数布局坐标捕捉到整数值,从而允许系统的干净布局,而不会因分数布局值的抗锯齿而导致文本和线条产生潜在的模糊。不要直接在屏幕像素网格上对齐。

没有模糊性的示例代码

当我在我的机器上运行修改后的示例时,该示例不通过绑定执行布局,而是仅使用布局管理器进行布局,我没有观察到值和模糊值(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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我还注意到默认布局管理器将双坐标舍入为整数坐标。是否可以使数字绑定以这种方式工作?

绑定整数坐标

整数坐标有点简化。有时您需要 x.5 的坐标(有关更多详细信息,请参阅如何在 JavaFX 2.2 中绘制清晰、不透明的发际线?)。对于标准布局窗格,您通常不需要担心这个细节,因为它们默认会处理干净的捕捉。

Java 8 的标准绑定例程中不存在下取整或舍入函数。您可以使用失效侦听器或更改侦听器并基于它们进行更新(而不是绑定),或者您可以开发一个自定义绑定,将其舍入到适当的值价值。有关这些选项的更多信息,请参阅Oracle JavaFX 属性教程的“探索 Observable、ObservableValue、InvalidationListener 和 ChangeListener”和“使用低级绑定 API”部分。

布局提示

进行布局的首选方法是(从最简单到更复杂):

  1. 使用布局管理器。
  2. 对于非常简单的布局调整来说,绑定或更改侦听器(通常)就可以了。
  3. 对于任何适度定制和复杂的内容,覆盖layoutChildren()父级。

layoutChildren()

内置 JavaFX 控件和布局管理器中的大多数自定义布局计算都是通过覆盖layoutChildren()而不是通过绑定来处理的。您可以查看JavaFX 源代码并研究它们是如何实现的。这是了解如何使用layoutChildren所必需的(因为我还没有在任何地方看到它的完整记录)。重写layoutChildren 有点高级,而且很难做好。为了从布局算法中获得可预测的质量结果,您需要手动考虑填充插图、像素捕捉、准确测量子组件的大小等问题。