2014-09-29 90 views
4

JavaFX 8.0有这个bug,我不知道如何解决它。
示例:http://i.imgur.com/tavh6XA.png拖动后ScrollPane内容变得模糊

如果我拖动ScrollPane,它的内容会变得模糊,但如果将其拖回,内容将恢复其清晰度。如果我不修改coords,内容看起来相当不错。

有没有人解决这个问题?

示例代码:

@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(); 
} 
+0

我有同样的问题,除非没有自定义布局X/Y。看起来把ScrollPane放在swt.FXCanvas里面会导致这个问题。试过sw/es2/d3d棱镜引擎,但它们没有区别。 – AqD 2014-10-06 08:07:52

回答

1

建议采取的方式 - 使用内置的布局管理器+施胶提示

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

示例代码,而不模糊

当我跑我的机器上修改的样本不通过结合进行布局,而是它的布局只使用布局管理器,我没有观察和模糊值(WIN 7, JavaFX 8u20)。我也不需要修改默认的节点缓存提示。

notblurry

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

我也注意到,默认的布局管理轮双COORDS整数COORDS。是否有可能使数字绑定以这种方式工作?

结合整数坐标

整数坐标是有点简化。有时你需要坐标为x.5(详见How to draw a crisp, opaque hairline in JavaFX 2.2?)。这是一个细节,你不需要担心通常使用标准布局窗格,因为它们默认会处理干净的贴紧。

Java 8的标准绑定例程中没有任何类型的层或函数。您可以使用失效侦听器或更改侦听器并基于它们进行更新(而不是绑定),也可以开发自定义绑定轮到适当的价值。有关这些选项的更多信息,请参阅Oracle JavaFX属性教程的"Exploring Observable, ObservableValue, InvalidationListener, and ChangeListener" and "Using the Low-Level Binding API"部分。

布局提示

做布局的首选方式是(从最简单到更复杂):

  1. 使用布局管理器。
  2. 绑定或更改侦听器(通常)对于非常简单的布局调整即可。
  3. 覆盖layoutChildren()在家长任何谦虚自定义和复杂的东西。

layoutChildren()

大部分的自定义布局计算

在内置的JavaFX控件和布局管理器被压倒layoutChildren()而不是通过绑定处理。您可以查看JavaFX source code并研究这些如何实施。这是了解如何使用layoutChildren所必需的(因为我没有在任何地方看到它的完整记录)。凌驾布局孩子是一个先进和棘手的做得不错。为了让您的布局算法预测的质量效果,您需要手动考虑之类的东西填充插图,像素贴紧,准确地测量子组件的大小等

+0

谢谢你的回答!嗯,是的,我也注意到,默认的布局管理器将双重坐标转换为整数坐标。是否有可能使数字绑定以这种方式工作? – turikhay 2014-10-07 09:28:18

+0

布局属性不是模糊的唯一原因。例如,请参阅https://imagizer.imageshack.us/v2/440x90q90/r/538/ER33eK.png。 ControlsFX PopOver不包含更改其子级布局的代码,唯一可疑的原因是动画。 – AqD 2014-10-10 13:28:58

2

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

PS:高速缓存属性也被设置为true TitledPane,它具有相同的问题,因为JavaFX的8.

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

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

缓存被禁用可能会降低性能,但我没有noticic任何放缓。

2
import com.sun.javafx.scene.control.skin.ScrollPaneSkin; 
import java.lang.reflect.Field; 
import javafx.scene.Node; 
import javafx.scene.control.ScrollPane; 
import javafx.scene.layout.StackPane; 

public class FieldUtils { 

    public static void fixBlurryText(Node node) { 
     try { 
      Field field = ScrollPaneSkin.class.getDeclaredField("viewRect"); 
      field.setAccessible(true); 

      ScrollPane scrollPane = (ScrollPane) node.lookup(".scroll-pane"); 

      StackPane stackPane = (StackPane) field.get(scrollPane.getSkin()); 
      stackPane.setCache(false); 

     } catch (NoSuchFieldException | SecurityException | IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
  • 谢谢AqD为搞清楚了这一点。
  • 我用AqD的答案来写这个小工具。我遇到的问题是在PopOver中使用TextAreas。所以这只是在节点深处找到stackPane并关闭缓存。
  • 注意:因为这个问题只发生在PopOver内部,所以在显示PopOver之后我不得不调用这个方法(因为否则节点还不存在,也没有任何胆量)。
  • 如果您遇到WebView问题,请将其忘记。 WebView没有滚动窗格(并且据我所知,没有使用setCache的字段),我不知道如何解决这个问题。
  • 希望这将有助于某人,即使这个问题是从3年前。

    blurry text before and after

1

如果我申请以下样式到滚动,模糊消失。

.scroll-pane { 
     -fx-background-color: -fx-box-border,-fx-background; 
     -fx-background-insets: 0, 1; 
     -fx-padding: 1.0; 
} 

这只是jfxrt.jar中caspian.css的风格。

我怀疑“-fx-background-insets:-1.4,0,1;”从“.scroll-pane:focused”负责非整数偏移量。因此造成模糊。所以我从ScrollPane的完整里海风格开始工作。消除背景后,一切都保持清晰。我试图尽可能减少sytle代码,并得到上面提出的解决方案。