2014-09-29 85 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代碼,並得到上面提出的解決方案。