谈到JavaFX或者说GUI设计,就脱不开布局设计
javafx.scene.layout
包提供了一系列用于布局的类
AnchorPane
AnchorPanebuilder<B extends AnchorPaneBuilder<B>>
BorderPane
BorderPaneBuilder<B extends BorderPaneBuilder<B>>
ColumnConstraints
ConstraintsBase
FlowPane
FlowPaneBuilder<B extends FlowPaneBuilder<B>>
GridPane
GridPaneBuilder<B etends GridPaneBuilder<B>>
HBox
HBoxBuilder<B extends HBoxBuilder<B>>
Pane
PaneBuilder<B extends RegionBuilder<B>>
RowConstraintsBuilder<B extends StackPaneBuilder<B>>
TilePane
TilePaneBuilder<B extends TilePaneBuilder<B>>
VBox
VBoxBuilder<B extends VBoxBuilder<B>>
下面我们讲的所有类都来自于javafx.scene.layout
包(布局包)
在javafx.scene.layout
包下,有一个特殊的类javafx.scene.layout.Region
类
Region
的英文释义:『区域』、『范围』;可以容纳其它结点并被CSS装饰
JavaFX的布局控件和界面元素控件都是继承自javafx.scene.Region
javafx.scene.layout.Pane
类继承自javafx.scene.layout.Pane
类
java.lang.Object
javafx.scene.Node
javafx.scene.Parent
javafx.scene.layout.Region
javafx.scene.layout.Pane
javafx.scnen.layout.Pane
类是其它控件布局的父类,可以将Pane
看成一个绝对布局控件,当我们将某个控件放置在Pane
当中时,需要指定它的位置(layoutX
、layoutY
),而当我们将几个控件拖拽到Pane
中会自动生成layoutX
、layoutY
Pane root = new Pane();
Scene scene = new Scene(root);
通常我们不直接使用Pane
类而是使用它的子类
BorderPane
提供了五个放置结点的区域:top
、bottom
、left
、right
、和 center
;这些区域的大小是自定义的,你可以不定义它,BorderPane
就不回给该区域分配空间
默认情况下,如果窗口比所有区域所需空间还大,多余的空间将被分配给中间区域;如果窗口比所需空间小,区域可能会重叠;重叠是由区域设置的顺序决定的
StackPane
类的地方在一个背到前面的单栈的内容节点
HBox
水平排列空间,不换行
VBox
垂直排列空间,不换行
FlowPane
综合类HBox
、VBox
的特点,既可以水平,也可以垂直排列
GridPane
类似于HTML的table
布局
还有一些,这里仅作为初步认识
既然JavaFX的一个场景中单独的元素叫节点(node),这些结点决定了JavaFX用分层次的树状结构来表示应用用户接口;它即能处理输入也能渲染输出(重申,scene是每个JavaFX应用的起点,它是分层的结点树)
除了根结点外,每一个节点都有一个父结点并且有0到多个子节点(还记得吗?在初始化一个scene时要给构造方法传递一个root结点)
getChildren()
方法在Parent
类中定义,返回该节点的所有孩子节点的列表
protected ObservableList getChildren() {
return children;
}
children
属于VetoableListDecorator
类,向上转型自ObservableList
接口
public interface ObservableList<E> extends List<E>, Observable
StackPane
对象可以直接使用getChildren().add()
添加新的子结点
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello JavaFX!");
Button btn = new Button();
btn.setText("Hello World");
StackPane root = new StackPane();
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
}
Pane
对象的效果是这样的
BorderPane
就什么也看不见了
必须通过setPadding()
方法设置padding
public final void setPadding(Insets value) { padding.set(value); }
private ObjectProperty padding = new StyleableObjectProperty(Insets.EMPTY) {
// Keep track of the last valid value for the sake of
// rollback in case padding is set to null. Note that
// Richard really does not like this pattern because
// it essentially means that binding the padding property
// is not possible since a binding expression could very
// easily produce an intermediate null value.
// Also note that because padding is set virtually everywhere via CSS, and CSS
// requires a property object in order to set it, there is no benefit to having
// lazy initialization here.
private Insets lastValidValue = Insets.EMPTY;
@Override public Object getBean() { return Region.this; }
@Override public String getName() { return "padding"; }
@Override public CssMetaData getCssMetaData() {
return StyleableProperties.PADDING;
}
@Override public void invalidated() {
final Insets newValue = get();
if (newValue == null) {
// rollback
if (isBound()) {
unbind();
}
set(lastValidValue);
throw new NullPointerException("cannot set padding to null");
} else if (!newValue.equals(lastValidValue)) {
lastValidValue = newValue;
insets.fireValueChanged();
}
}
};
通过setXXX(XXX为对应方位)
设置对应方位的元素结点
/** 把getChildren().add(btn)改成setCenter(btn) */
再举一例(BorderPane)
package application;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("BorderPane Test");
BorderPane bp = new BorderPane();
bp.setPadding(new Insets(10, 20, 10, 20));
Button btnTop = new Button("Top");
bp.setTop(btnTop);
Button btnLeft = new Button("Left");
bp.setLeft(btnLeft);
Button btnCenter = new Button("Center");
bp.setCenter(btnCenter);
Button btnRight = new Button("Right");
bp.setRight(btnRight);
Button btnBottom = new Button("Bottom");
bp.setBottom(btnBottom);
Scene scene = new Scene(bp, 300, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}