Статьи

Панели макета JavaFX 2.0 — GridPane

GridPane , без сомнения, самая мощная и гибкая панель макетов в JavaFX 2.0.
Он размещает GridBagLayout дочерних GridBagLayout в гибкой сетке столбцов и строк и очень похож на Swing GridBagLayout или модель таблицы HTML. Такой подход делает эту панель очень подходящей для любых форм (например, контактных форм на веб-сайте).

У вас есть возможность …

  • применить любой Node к ячейке (указанной столбцом и строкой) в GridPane
  • позволить Node охватывать несколько столбцов / строк
  • выровнять Node в ячейке, к которой он был применен
  • установить горизонтальный или вертикальный рост для Node
  • и применить поле для хранения вокруг Node в ячейке.

Гибкость GridPane также распространяется на очень гибкий API. Вы можете использовать методы статического класса, такие как setColumnIndex(node, index) или setRowSpan(node, value) , или вы можете использовать gridpane.add(node, column, row, columnSpan, rowSpan) методы экземпляра, такие как gridpane.add(node, column, row, columnSpan, rowSpan) .

Замечания:

  • Вам не нужно устанавливать максимальное количество столбцов или строк в GridPane поскольку оно будет расти автоматически.
  • Размер одного столбца автоматически определяется самым широким Node в этом столбце, высота каждой строки определяется самым высоким Node в строке.

Последнее примечание, вероятно, является наиболее важным фактом о GridPane поскольку его необходимо учитывать для столбца / строки и диапазона столбца / диапазона каждого отдельного Node , чтобы получить нужный макет.
Для более сложных макетов очень хорошая идея нарисовать макет на листе бумаги и нарисовать все линии для столбцов и строк. Это облегчит разработку, потому что вы можете прямо видеть, в какую ячейку вы должны поместить каждый Node и сколько строк или столбцов они должны охватывать.

Давайте посмотрим на первый простой пример:

GridPane — Пример 1

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
 
/**
 * Created on: 23.06.2012
 * @author Sebastian Damm
 */
public class GridPaneExample extends Application
{
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        GridPane gridPane = new GridPane();
        gridPane.setPadding(new Insets(40, 0, 0, 50));
        gridPane.setHgap(5); gridPane.setVgap(5);
         
        Scene scene = new Scene(gridPane, 300, 150);
         
        Label lbUser = new Label('Username:');
        GridPane.setHalignment(lbUser, HPos.RIGHT);
        TextField tfUser = new TextField();
         
        Label lbPass = new Label('Password:');
        GridPane.setHalignment(lbPass, HPos.RIGHT);
        PasswordField tfPass = new PasswordField();
         
        Button btLogin = new Button('Login');
        GridPane.setMargin(btLogin, new Insets(10, 0, 0, 0));
 
        gridPane.add(lbUser, 0, 0);
        gridPane.add(tfUser, 1, 0);
        gridPane.add(lbPass, 0, 1);
        gridPane.add(tfPass, 1, 1);
        gridPane.add(btLogin, 1, 2);
         
        primaryStage.setTitle('GridPaneExample 1');
        primaryStage.setScene(scene);
        primaryStage.show();
    }
     
    public static void main(String[] args)
    {   Application.launch(args);   }
}

Здесь вы можете увидеть небольшую форму входа с двумя надписями и двумя текстовыми полями для имени пользователя и пароля. Кроме того, есть кнопка «Войти».
В строках 21-23 мы создаем GridPane и применяем некоторые отступы. Кроме того, вы можете указать горизонтальный и вертикальный разрыв, который будет сохраняться между каждым Node Далее взглянем на строку 28: выравнивание Node внутри границ ячейки, в которую он был помещен, можно установить с помощью методов статического класса GridPane.setHalignment(Node node, HPos pos) , соответственно GridPane.setValignment(Node node, VPos pos) .
В строке 36 вы можете увидеть, как разместить отдельное поле вокруг одного Node , используя метод GridPane.setMargin(Node node, Insets insets) .
Наконец, в строках с 38 по 42 мы добавляем каждый Node в GridPane и указываем столбец и строку Node .

Ваше приложение должно выглядеть так:

В следующем примере вы увидите, почему нам нужно установить диапазон столбцов и диапазон строк каждого Node в более сложных макетах. Посмотрите на этот код:

GridPane — Пример 2. Форма пользователя

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.paint.RadialGradientBuilder;
import javafx.scene.paint.Stop;
import javafx.stage.Stage;
 
/**
 * Created on: 23.06.2012
 * @author Sebastian Damm
 */
public class GridPaneExample2 extends Application
{
    private final Paint background = RadialGradientBuilder.create()
            .stops(new Stop(0d, Color.TURQUOISE), new Stop(1, Color.web('3A5998')))
            .centerX(0.5d).centerY(0.5d).build();
    private final String LABEL_STYLE = '-fx-text-fill: white; -fx-font-size: 14;'
            + '-fx-effect: dropshadow(one-pass-box, black, 5, 0, 1, 1);';
     
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        Scene scene = new Scene(createGridPane(), 370, 250, background);
        primaryStage.setTitle('GridPaneExample 2 - User form');
        primaryStage.setScene(scene);
        primaryStage.show();
    }
     
    private GridPane createGridPane()
    {
        GridPane gridPane = new GridPane();
        gridPane.setPadding(new Insets(20, 0, 20, 20));
        gridPane.setHgap(7); gridPane.setVgap(7);
         
        Label lbFirstName = new Label('First Name:');
        lbFirstName.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbFirstName, HPos.RIGHT);
        TextField tfFirstName = new TextField();
         
        Label lbLastName = new Label('Last Name:');
        lbLastName.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbLastName, HPos.RIGHT);
        TextField tfLastName = new TextField();
         
        Label lbCity = new Label('City:');
        lbCity.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbCity, HPos.RIGHT);
        TextField tfCity = new TextField();
         
        Label lbStreetNr = new Label('Street/Nr.:');
        lbStreetNr.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbStreetNr, HPos.RIGHT);
        TextField tfStreet = new TextField();
        tfStreet.setPrefColumnCount(14);
        GridPane.setColumnSpan(tfStreet, 2);
        TextField tfNumber = new TextField();
        tfNumber.setPrefColumnCount(3);
         
        Label lbNotes = new Label('Notes:');
        lbNotes.setStyle(LABEL_STYLE);
        GridPane.setHalignment(lbNotes, HPos.RIGHT);
        TextArea taNotes = new TextArea();
        taNotes.setPrefColumnCount(5);
        taNotes.setPrefRowCount(5);
        GridPane.setColumnSpan(taNotes, 3);
        GridPane.setRowSpan(taNotes, 2);   
         
        ImageView imageView = new ImageView(new Image(getClass()
                .getResourceAsStream('person.png'), 0, 65, true, true));
        GridPane.setHalignment(imageView, HPos.LEFT);
        GridPane.setColumnSpan(imageView, 2);
        GridPane.setRowSpan(imageView, 3);
         
//        gridPane.setGridLinesVisible(true);
         
        gridPane.add(lbFirstName, 0, 0); gridPane.add(tfFirstName, 1, 0);
        gridPane.add(imageView, 2, 0); gridPane.add(lbLastName, 0, 1);
        gridPane.add(tfLastName, 1, 1); gridPane.add(lbCity, 0, 2);
        gridPane.add(tfCity, 1, 2); gridPane.add(lbStreetNr, 0, 3);
        gridPane.add(tfStreet, 1, 3); gridPane.add(tfNumber, 3, 3);
        gridPane.add(lbNotes, 0, 4); gridPane.add(taNotes, 1, 4);
         
        return gridPane;
    }
     
    public static void main(String[] args)
    {   Application.launch(args);   }
}

В этом примере мы создаем форму пользователя с разными входами и изображением. Чтобы приложение выглядело немного лучше, я создал RadialGradient для фона Scene и применил белый цвет шрифта и небольшую тень для каждой метки.

Приложение должно выглядеть так:

По сравнению с предыдущим примером первое различие возникает в строке 64.
С GridPane.setColumnSpan(tfStreet, 2); я говорю этому TextField чтобы занять два столбца. Это необходимо, потому что я хочу, чтобы это текстовое поле было немного шире (см. Строку 63), чем другие текстовые поля. В противном случае второй столбец будет таким же широким, как это текстовое поле, и, следовательно, растянет меньшие.
TextArea (начиная со строки 71) и ImageView (строка 77) охватывают несколько столбцов и строк.
Далее, посмотрите на строку 83. Если вы удалите строки комментариев и запустите приложение, оно должно выглядеть так:

Как видите, этот метод делает видимыми все линии сетки (включая горизонтальный и вертикальный промежуток между каждым Node что может быть очень полезно, если ваши Nodes выровнены так, как вы этого хотите.
Я не знаю, сколько раз мне хотелось такого метода за то время, пока я изучал Swing и GridBagLayout и GridBagLayout пари, что я не единственный;)

Наконец, удалите все строки, в которых указаны столбцы или строки (строки 64, 74, 75, 80, 81). Это поможет вам понять необходимость диапазона столбца и диапазона строки.

Вы можете видеть, что каждый Node занимает одну ячейку и что макет довольно запутан, потому что ширина / высота каждого столбца / строки зависит от самого широкого / самого высокого дочернего Node .

GridPane — Пример 3: метод setConstraints

Метод экземпляра add «only» предоставляет две версии: одну с Node , столбцом и строкой, а другую с дополнительным диапазоном столбца и строкой. Другие свойства, такие как выравнивание или увеличение, должны быть установлены с помощью специальных методов класса, таких как GridPane.setHalignment как в первых двух примерах.

Но есть и другой хороший способ: метод GridPane.setConstraints(...) . На данный момент (JavaFX 2.2) существует пять перегруженных версий этого метода из setConstraints(Node child, int columnIndex, int rowIndex)

для setConstraints(Node child, int columnIndex, int rowIndex, int columnspan, int rowspan, HPos halignment, VPos valignment, Priority hgrow, Priority vgrow, Insets margin) .

Это довольно похоже на GridBagConstraints в Swing, но здесь вам не нужно создавать отдельный объект и повторно использовать его для нескольких графических объектов.

Если вы примените ограничения к каждому Node как это, вы можете просто добавить Nodes в коллекции GridPane´s .

При таком подходе код второго примера выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
private GridPane createGrid()
{
    GridPane gridPane = new GridPane();
    gridPane.setPadding(new Insets(20, 0, 20, 20));
    gridPane.setHgap(7); gridPane.setVgap(7);
     
    Label lbFirstName = new Label('First Name:');
    lbFirstName.setStyle(LABEL_STYLE);
    GridPane.setConstraints(lbFirstName, 0, 0, 1, 1, HPos.RIGHT, VPos.CENTER);
    TextField tfFirstName = new TextField();
    GridPane.setConstraints(tfFirstName, 1, 0);
     
    Label lbLastName = new Label('Last Name:');
    lbLastName.setStyle(LABEL_STYLE);
    GridPane.setConstraints(lbLastName, 0, 1, 1, 1, HPos.RIGHT, VPos.CENTER);
    TextField tfLastName = new TextField();
    GridPane.setConstraints(tfLastName, 1, 1);
     
    Label lbCity = new Label('City:');
    lbCity.setStyle(LABEL_STYLE);
    GridPane.setConstraints(lbCity, 0, 2, 1, 1, HPos.RIGHT, VPos.CENTER);
     
    TextField tfCity = new TextField();
    GridPane.setConstraints(tfCity, 1, 2);
     
    Label lbStreetNr = new Label('Street/Nr.:');
    lbStreetNr.setStyle(LABEL_STYLE);
    GridPane.setConstraints(lbStreetNr, 0, 3, 1, 1, HPos.RIGHT, VPos.CENTER);
     
    TextField tfStreet = new TextField();
    tfStreet.setPrefColumnCount(14);
    GridPane.setConstraints(tfStreet, 1, 3, 2, 1);
     
    TextField tfNumber = new TextField();
    tfNumber.setPrefColumnCount(3);
    GridPane.setConstraints(tfNumber, 3, 3);
     
    Label lbNotes = new Label('Notes:');
    lbNotes.setStyle(LABEL_STYLE);
    GridPane.setConstraints(lbNotes, 0, 4, 1, 1, HPos.RIGHT, VPos.CENTER);
     
    TextArea taNotes = new TextArea();
    taNotes.setPrefColumnCount(5);
    taNotes.setPrefRowCount(5);
    GridPane.setConstraints(taNotes, 1, 4, 3, 2);
             
    ImageView imageView = new ImageView(new Image(getClass()
            .getResourceAsStream('person.png'), 0, 65, true, true));
    GridPane.setConstraints(imageView, 2, 0, 3, 3, HPos.LEFT, VPos.CENTER);
     
    gridPane.getChildren().addAll(lbFirstName, tfFirstName, imageView
            , lbLastName, tfLastName, lbCity, tfCity, lbStreetNr, tfStreet
            , tfNumber, lbNotes, taNotes);
    return gridPane;
}

Вы можете увидеть использование перегруженных setConstraints(...) и как вы можете просто добавить Nodes в GridPane в строках 51-53.

Я надеюсь, что смогу дать хорошее представление о GridPane в JavaFX 2.0. Не стесняйтесь добавлять комментарии и оставлять вопросы.

Ссылка: JavaFX 2.0 Layout Panes — GridPane от нашего партнера по JCG Себастьяна Дамма в блоге Just my 2 cents о Java .