2016-08-17 11 views
1

私はScroll-and Tilepanes atmの周りを頭で囲んでいます。汚れたハックなしで解決できない問題が発生しました。ScrollPaneでTilePaneを使用したレスポンシブなUIデザイン

私は8つのタイルを持つ水平タイルパネルを持っていて、4つのタイルを持つ2つのタイルを持つように設定しました。 そのTilePane私はHBoxに入れました。なぜなら、私がStackPaneに配置すると、タイルペインのサイズが伸びて、私の列が無効になるからです。 prefColumns/Rowsを設定すると、実際の列数/行数を設定しようとするのではなく、TilePaneのサイズが再計算されるというのはちょっと変わったことです。

とにかく、HBoxを直接ScrollPaneに配置すると、2行目のタイルが途切れてもスクロールバーが表示されないため、HBoxを直接ScrollPaneに配置することはできません。私がScrollPaneに入れたStackpaneでそのHBoxを再び設定することは、そのトリックを行います。ウィンドウの幅をあまり小さくするまで、タイルペインはタイルを新たに配置しなければならず、3つ以上の行が表示されます。

は、ここで基本的なプログラムの開発です:

public class Main extends Application { 

    @Override 
    public void start(Stage stage) { 

     TilePane tilePane = new TilePane(); 
     tilePane.setPadding(new Insets(5)); 
     tilePane.setVgap(4); 
     tilePane.setHgap(4); 
     tilePane.setPrefColumns(4); 
     tilePane.setStyle("-fx-background-color: lightblue;"); 

     HBox tiles[] = new HBox[8]; 
     for (int i = 0; i < 8; i++) { 
      tiles[i] = new HBox(new Label("This is node #" + i)); 
      tiles[i].setStyle("-fx-border-color: black;"); 
      tiles[i].setPadding(new Insets(50)); 
      tilePane.getChildren().add(tiles[i]); 
     } 

     HBox hbox = new HBox(); 
     hbox.setAlignment(Pos.CENTER); 
     hbox.setStyle("-fx-background-color: blue;"); 
     hbox.getChildren().add(tilePane); 

     StackPane stack = new StackPane(); 
     stack.getChildren().add(hbox); 

     ScrollPane sp = new ScrollPane(); 
     sp.setFitToHeight(true); 
     sp.setFitToWidth(true); 
     sp.setContent(stack); 

     stage.setScene(new Scene(sp, 800, 600)); 
     stage.show(); 
    } 

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

私は私の希望の動作を実現するために管理し、本当に汚いハックのそのより。 TilePaneを含むHBoxの高さと幅にリスナーを追加し、幅が小さくなって列が削除され、新しい行が追加されたために高さが変更されたと仮定しました。それを可能にするために、私はVBoxにHBoxを入れて、ScrollPaneの高さを増やさないようにしました。幅については、別の列を表示するスペースがある場合(最大4)、単純に計算します。ここで

は変更されている:

public class Main extends Application { 

    private boolean notFirstPassHeight; 
    private boolean notFirstPassWidth; 

    @Override 
    public void start(Stage stage) { 

     TilePane tilePane = new TilePane(); 
     tilePane.setPadding(new Insets(5)); 
     tilePane.setVgap(4); 
     tilePane.setHgap(4); 
     tilePane.setPrefColumns(4); 
     tilePane.setStyle("-fx-background-color: lightblue;"); 
     // I took the value from ScenicView 
     tilePane.prefTileWidthProperty().set(182); 

     HBox tiles[] = new HBox[8]; 
     for (int i = 0; i < 8; i++) { 
      tiles[i] = new HBox(new Label("This is node #" + i)); 
      tiles[i].setStyle("-fx-border-color: black;"); 
      tiles[i].setPadding(new Insets(50)); 
      tilePane.getChildren().add(tiles[i]); 
     } 

     ScrollPane sp = new ScrollPane(); 
     sp.setFitToHeight(true); 
     sp.setFitToWidth(true); 

     StackPane stack = new StackPane(); 

     VBox vbox = new VBox(); 
     vbox.setStyle("-fx-background-color: red"); 

     HBox hbox = new HBox(); 
     hbox.setAlignment(Pos.CENTER); 
     hbox.setStyle("-fx-background-color: blue;"); 
     hbox.getChildren().add(tilePane); 

     notFirstPassHeight = false; 
     notFirstPassWidth = false; 
     hbox.heightProperty().addListener((observable, oldValue, newValue) -> { 
      if (oldValue.doubleValue() < newValue.doubleValue() && notFirstPassHeight) { 
       tilePane.setPrefColumns(tilePane.getPrefColumns() - 1); 
       stack.requestLayout(); 
      } 
      notFirstPassHeight = true; 
     }); 
     hbox.widthProperty().addListener((observable, oldValue, newValue) -> { 
      if (oldValue.doubleValue() < newValue.doubleValue() && notFirstPassWidth && tilePane.getPrefColumns() <= 3 
        && (newValue.doubleValue()/(tilePane.getPrefColumns() + 1)) > tilePane.getPrefTileWidth()) { 
       tilePane.setPrefColumns(tilePane.getPrefColumns() + 1); 
       stack.requestLayout(); 
      } 
      notFirstPassWidth = true; 
     }); 

     vbox.getChildren().add(hbox); 

     stack.getChildren().add(vbox); 

     sp.setContent(stack); 
     stage.setScene(new Scene(sp, 800, 600)); 
     stage.show(); 
    } 

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

} 

しかし、このアプローチはTilepaneのタイルの幅1.Know

に私を必要とします。

2.私の計算が正確であるように、タイル間のパディングとギャップを考慮してください。これは私の例では行いません。

あなたが私に尋ねると、それはまったく良いアプローチではありません。そのような基本的なことのためのプロセスが複雑すぎる。 ScrollPaneでTilePanesを使用して、完全なサイズ変更と目的の動作を達成するためのより簡単な方法が必要です。

+0

「ダーティハック」(2番目)の例で機能するようにしたいと考えています。私はフルスクリーンでそれを持っていると言うと2行ala 4列を持って、アプリケーションが動的に行を追加し、幅が小さくなると、列を減らすようにサイズが変更された場合。基本的には、アプリケーションの高さを優先して縦方向のスクロールバーを表示し、サイズ変更の余地がなくなったらスクロールバーのみを表示するようにします(1列まで)。私は自分自身を説明することができればと思っています.2番目の例は、私がしたいことをしています。 – 404KnowledgeNotFound

+0

ああ、OK、 'GridPane'はあなたが望むものではありません。私に実験をさせてください... –

答えて

1

TilePaneの列および/または行の優先番号を設定すると、そのタイルペインの値がおよびprefHeightの計算が決まります。あなたは列の最大数を強制したい場合は、あなただけの計算prefWidthからmaxWidthを等しくする必要があります:あなたは、これはその(限りタイルペインが何かに置かれるよう意味

tilePane.setMaxWidth(Region.USE_PREF_SIZE); 

でこれを行うことができますそれはレイアウトを管理します)、それは決まった数の列を許可するように計算されたpref幅より広いことはありません。もちろんそれはそれより小さくてもよい。 (あなたは、列の最小数ではなく、列の最大数を必要に応じて、あなたがsetMinWidthと同じトリックを使用することができます。)

スクロールペインのfitToHeightfitToWidthプロパティは、trueの場合、(高さのサイズを変更しようとしますそれぞれの幅)がスクロールペインのビューポートの高さ(幅)に等しくなるようにします。これらの操作はコンテンツの好ましい高さ(幅)よりも優先されますが、最小の高さ(幅)を尊重しようとします。

setFitToWidth(true)setFitToHeight(true)の両方を呼び出すのは間違いです。ほとんどの場合、スクロールペインのビューポートと同じサイズにするだけです。

ここで、タイルペインの最大幅をプレフの幅に合わせて、タイルペインの幅をスクロールペインのビューポートの幅に固定します(ウィンドウの幅を縮小するとビューポートの幅を縮小し、より多くの列を作成します)。行の数が十分に大きくなると垂直スクロールバーが追加され、ビューポートがすべてのノードの優先幅の最小値として計算される最小の幅よりも水平方向に縮小される場合にのみ水平スクロールバーが追加されます含まれています)。

私はあなたの元のコードの以下のバージョンは、あなたが探しているものを基本的にないと思います

import javafx.application.Application; 
import javafx.geometry.Insets; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.scene.control.ScrollPane; 
import javafx.scene.layout.HBox; 
import javafx.scene.layout.Region; 
import javafx.scene.layout.TilePane; 
import javafx.stage.Stage; 

public class ScrollingTilePane extends Application { 

    @Override 
    public void start(Stage stage) { 

     TilePane tilePane = new TilePane(); 
     tilePane.setPadding(new Insets(5)); 
     tilePane.setVgap(4); 
     tilePane.setHgap(4); 
     tilePane.setPrefColumns(4); 
     tilePane.setStyle("-fx-background-color: lightblue;"); 

     // dont grow more than the preferred number of columns: 
     tilePane.setMaxWidth(Region.USE_PREF_SIZE); 

     HBox tiles[] = new HBox[8]; 
     for (int i = 0; i < 8; i++) { 
      tiles[i] = new HBox(new Label("This is node #" + i)); 
      tiles[i].setStyle("-fx-border-color: black;"); 
      tiles[i].setPadding(new Insets(50)); 
      tilePane.getChildren().add(tiles[i]); 
     } 

     HBox hbox = new HBox(); 
     hbox.setAlignment(Pos.CENTER); 
     hbox.setStyle("-fx-background-color: blue;"); 
     hbox.getChildren().add(tilePane); 

//  StackPane stack = new StackPane(); 
//  stack.getChildren().add(tilePane); 
//  stack.setStyle("-fx-background-color: blue;"); 

     ScrollPane sp = new ScrollPane(); 
//  sp.setFitToHeight(true); 
     sp.setFitToWidth(true); 
     sp.setContent(hbox); 

     stage.setScene(new Scene(sp, 800, 600)); 
     stage.show(); 
    } 

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

あなたがスクロールペインのコンテンツ外側の空間の背景色を変更する必要がある場合は、あなたが使用できることに注意してください

+0

これはうまくいきましたが、私の実際のアプリケーションでは、ScrollPaneに他の画面もあり、それらは常に水平のスクロールバーが消えることはありません。おそらくこの解決策によって引き起こされた問題ではありませんが、なぜこれが起こるのかについてのアイデアはありますか?私はlayoutBoundsとBoundsInParentが異なるSCENICVIEWに気づいた、原因は私が画面に持ってTableNavigatorsで持っているセパレータです。なぜ彼らがそれをやるのか分からない。 – 404KnowledgeNotFound

+0

同じ基本原則が適用されます。 JavaFXでのレイアウトの仕組みが分からないようです。後で時間がある場合、一般的な説明を回答に追加しますが、[Javadocs for layout](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/package-summary)をお読みください。 .html)。私が自分のコンピュータに戻ったときに掘り起こすことができる他のリソースがいくつかあります。 –

+1

しかし、内容の好ましい幅(fitToWidthがtrueの場合の最小幅)がスクロールペインに割り当てられた幅よりも大きい場合、スクロールペインには水平スクロールバーが表示されます。 –

関連する問題