1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaFX 画面サイズが一定以下の場合はスクロールバーを出し、一定以上の場合は中のnodeをなるべく最大化する

Posted at

今回のゴール

JavaFxをしようしてGUIアプリを作成する際にListViewを使用しましたが、以下のような要望がありました。

  1. ListViewはなるべく大きく表示したい
    • → windowの大きさに連動して大きさが自動的に変化する
  2. windowサイズがある一定を下回った場合は、ListViewの大きさ変更をやめ、かつ、windowのスクロール表示にしたい。

そんな要望を満たすのに、それなりに苦労したので結果のメモ。

最終的に目指した動きはこんな感じ。
青枠部分がListViewで、ボタンのある位置よりも画面サイズが小さくなった場合にスクロールバーが登場し、横に部品があることを示す、といった具合。
目指す姿fxml.gif

環境

java1.8
JavaFX Scene Builder 2.0

まずは結果から

最終的な部品の構成は以下の通りで実現できた。

  • ScrollPane
    • AnchorPane
      • TextField
      • Button
      • ListView

スクリーンショット 2020-07-09 13.20.23.png

各部品の設定要点

ScrollPane

  • Properties - Hbar/Vbar PolicyAS_NEEDEDとする。
  • Layout - Fit To Width/Heightをtrue(:heavy_check_mark:)とする。

AnchorPane

  • Layout - Min Width/Heightを、スクロールバーの表示を開始させたいwindowサイズに設定する。

ListView

  • Layout - Anchor Pane Constrainsの4辺について全て固定値として設定する。

実現までの道のりステップバイステップ

Windowサイズに連動するListViewの設定

以下の組み合わせにより、「Windowサイズに連動してListViewの大きさが変化する」を実現できる。

AnchorPaneとListView

使用するのはAnchorPane
AnchorPaneとは

AnchorPane allows the edges of child nodes to be anchored to an offset from the anchor pane's edges.

中に含まれたnodeについて、親であるAnchorPaneの端からの距離を固定することができる、とのこと。

SceneBuliderでAnchorPaneの子要素にControlを追加すると、LayoutにAnchor Pane Constraintsが表示される。
スクリーンショット 2020-07-09 12.58.15.png

この4つのテキストボックスに入力した値(距離)で個要素の端とAnchorPaneの端とが固定される。
下の値のみ固定したのがこれ。
下のみ固定.gif

一辺のみを固定すると、コントロールの大きさは変更されず、表示位置が変更される。

上下を固定したのがこれ。
上下固定.gif

上下を固定すると、コントロールの大きさよりも上下からの距離が優先され、コントロールの大きさが伸び縮みするのがわかる。

今回、ListViewの大きさをなるべく大きく表示させるためには、AnchorPaneに内包させるListViewについて、Anchor Pane Constraintsの4つの辺全てについて、固定値とすれば良いことがわかった。

ScrollPane内のAnchorPane

ScrollPaneにはFitTo[Width|Height]Propertyがある。
SceneBuilderではこのプロパティを
LayoutFit To WidthFit To Heightで設定する。

このFit To Width/Heightの意味をドキュメントで確認すると

public final BooleanProperty fitToWidthProperty

If true and if the contained node is a Resizable, then the node will be kept resized to match the width of the ScrollPane's viewport. If the contained node is not a Resizable, this value is ignored.

(適当な訳)

trueのとき、中に含まれるnodeがRisizableであれば、nodeはScrollPaneのviewportの幅に連動して大きさが変化する。含まれるnodeがResizableでなければこの値は無視される。

ということで、ScrollPaneの中にAnchorPaneを入れ、Fit To Width/Heighttrueにすることで、ScrollPane(今回の場合はWindowサイズ)の大きさを変化に連動してAnchorPaneの大きさが変化するようになった。
(AnchorPaneは、というか、JavaFXのコントロールは全てResizeable)

Windowの大きさが一定以下だった場合の措置

次は「一定の幅よりもWindowの大きさが小さくなった場合は、スクロールバーを表示する」。

ScrollPaneのFitTo[Width|Height]Propertytrueとした場合、内部のnodeの大きさはScrollPaneの大きさに連動して変化するが、内部のnodeのMin [Width|Height]Max [Width|Height]を超えては大きさは変化しない様子。

そこで、ScrollPaneの中のAnchorPaneのMin Widthに、Buttonが隠れない大きさを設定すると、、、できた。

結果として出来上がったfxml

目指す姿.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<ScrollPane fitToHeight="true" fitToWidth="true" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
  <content>
    <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="343.0" prefWidth="486.0">
         <children>
            <TextField layoutX="14.0" layoutY="7.0" prefHeight="27.0" prefWidth="247.0" />
            <ListView layoutX="-4.0" layoutY="41.0" prefHeight="357.0" prefWidth="598.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="40.0" />
            <Button layoutX="272.0" layoutY="7.0" mnemonicParsing="false" text="Button" />
         </children></AnchorPane>
  </content>
</ScrollPane>
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?