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)
我尝试了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)
希望它会帮助别人。
我检查了内部皮肤代码并找到了一种解决方法,但并不漂亮。问题出在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)
禁用缓存可能会降低性能,但我没有注意到任何减速。
推荐方法 - 使用内置布局管理器 + 大小调整提示
我建议除非需要,否则不要设置节点的布局值。相反,如果您使用标准布局容器,那么它(应该)默认将任何非整数布局坐标捕捉到整数值,从而允许系统的干净布局,而不会因分数布局值的抗锯齿而导致文本和线条产生潜在的模糊。不要直接在屏幕像素网格上对齐。
没有模糊性的示例代码
当我在我的机器上运行修改后的示例时,该示例不通过绑定执行布局,而是仅使用布局管理器进行布局,我没有观察到值和模糊值(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”部分。
布局提示
进行布局的首选方法是(从最简单到更复杂):
layoutChildren()父级。在layoutChildren()
内置 JavaFX 控件和布局管理器中的大多数自定义布局计算都是通过覆盖layoutChildren()而不是通过绑定来处理的。您可以查看JavaFX 源代码并研究它们是如何实现的。这是了解如何使用layoutChildren所必需的(因为我还没有在任何地方看到它的完整记录)。重写layoutChildren 有点高级,而且很难做好。为了从布局算法中获得可预测的质量结果,您需要手动考虑填充插图、像素捕捉、准确测量子组件的大小等问题。
| 归档时间: |
|
| 查看次数: |
2381 次 |
| 最近记录: |