{"id":"gui-basics-border-pane","slug":"border-pane","title":"BorderPane: five regions","text":"A FlowPane lets its children flow. Many windows have a fixed frame instead: a title or a toolbar along the top, a line of status at the bottom, a menu on one side, and the main thing in the middle. **BorderPane** is that frame. It has five regions: **top**, **right**, **bottom**, **left** and **center**.\n\n### A recipe card\n\n```java\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Button;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.layout.BorderPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        BorderPane card = new BorderPane();\n        card.setTop(new Label(\"Lentil soup\"));\n        card.setLeft(new Label(\"Serves 4\"));\n        card.setCenter(new TextArea(\"Fry the onion.\\nAdd the lentils and the stock.\\nSimmer for 25 minutes.\"));\n        card.setRight(new Label(\"45 min\"));\n        card.setBottom(new Button(\"Print\"));\n\n        stage.setScene(new Scene(card));\n        stage.setTitle(\"Recipe card\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n```\n\n```window\n{\"events\":[],\"window\":{\"windows\":[{\"title\":\"Recipe card\",\"scene\":{\"root\":{\"n\":1,\"type\":\"BorderPane\",\"top\":{\"n\":2,\"type\":\"Label\",\"text\":\"Lentil soup\"},\"left\":{\"n\":3,\"type\":\"Label\",\"text\":\"Serves 4\"},\"center\":{\"n\":4,\"type\":\"TextArea\",\"text\":\"Fry the onion.\\nAdd the lentils and the stock.\\nSimmer for 25 minutes.\"},\"right\":{\"n\":5,\"type\":\"Label\",\"text\":\"45 min\"},\"bottom\":{\"n\":6,\"type\":\"Button\",\"text\":\"Print\"}}}}],\"problems\":[]},\"outline\":\"Window \\\"Recipe card\\\"\\n  BorderPane\\n    top: Label \\\"Lentil soup\\\"\\n    left: Label \\\"Serves 4\\\"\\n    center: TextArea \\\"Fry the onion.\\\\nAdd the lentils and the stock.\\\\nSimmer for 25 minutes.\\\"\\n    right: Label \\\"45 min\\\"\\n    bottom: Button \\\"Print\\\"\"}\n```\n\n- `setTop`, `setRight`, `setBottom`, `setLeft` and `setCenter` each put one node into a region. A region holds one node at most (step 6 puts a layout full of nodes there).\n- The top and bottom regions run across the whole width. The left and right regions sit between them, at the sides, and the center gets all the room that's left.\n- In the window as text, each node of a BorderPane starts with its region: `top: Label \"Lentil soup\"`. The regions are always listed in the same order, top, left, center, right, bottom, whatever order the code set them in.\n\n`new BorderPane(node)` makes a BorderPane with that node in the center.\n\n### Empty regions\n\nA region that is never set stays empty, and an empty region takes no room. A card with only a title and the method:\n\n```java\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.layout.BorderPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        BorderPane card = new BorderPane();\n        card.setTop(new Label(\"Toast\"));\n        card.setCenter(new TextArea(\"Toast the bread.\\nButter it while it's hot.\"));\n\n        stage.setScene(new Scene(card));\n        stage.setTitle(\"Recipe card\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n```\n\n```window\n{\"events\":[],\"window\":{\"windows\":[{\"title\":\"Recipe card\",\"scene\":{\"root\":{\"n\":1,\"type\":\"BorderPane\",\"top\":{\"n\":2,\"type\":\"Label\",\"text\":\"Toast\"},\"center\":{\"n\":3,\"type\":\"TextArea\",\"text\":\"Toast the bread.\\nButter it while it's hot.\"}}}}],\"problems\":[]},\"outline\":\"Window \\\"Recipe card\\\"\\n  BorderPane\\n    top: Label \\\"Toast\\\"\\n    center: TextArea \\\"Toast the bread.\\\\nButter it while it's hot.\\\"\"}\n```\n\nThe window as text lists only the regions that hold something.\n\n### Replacing what's in a region\n\nSetting a region again replaces its node: the old node leaves the window. `setCenter(null)` empties the center. `getTop()`, `getCenter()` and the others return the node in a region, as a `Node` (or `null` for an empty region), and `card.getChildren()` is the list of the nodes in all the regions together:\n\n```java\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.layout.BorderPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        BorderPane card = new BorderPane();\n        Label draft = new Label(\"Pea soup\");\n        card.setTop(draft);\n        card.setCenter(new TextArea(\"Boil the peas.\"));\n        card.setTop(new Label(\"Pea and mint soup\"));\n        System.out.println(\"The draft title is in the window: \" + (draft.getParent() != null));\n        System.out.println(\"Nodes in the card: \" + card.getChildren().size());\n\n        stage.setScene(new Scene(card));\n        stage.setTitle(\"Recipe card\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n```\n\n```window\n{\"events\":[],\"window\":{\"windows\":[{\"title\":\"Recipe card\",\"scene\":{\"root\":{\"n\":1,\"type\":\"BorderPane\",\"top\":{\"n\":2,\"type\":\"Label\",\"text\":\"Pea and mint soup\"},\"center\":{\"n\":3,\"type\":\"TextArea\",\"text\":\"Boil the peas.\"}}}}],\"problems\":[]},\"outline\":\"Window \\\"Recipe card\\\"\\n  BorderPane\\n    top: Label \\\"Pea and mint soup\\\"\\n    center: TextArea \\\"Boil the peas.\\\"\"}\n```\n\n```output\nThe draft title is in the window: false\nNodes in the card: 2\n```\n\n`getParent()` returns the node that holds a node, or `null` for a node that isn't in any. The draft title has none any more: the second `setTop` replaced it, so the card holds two nodes, the new title and the method.\n\n### Fonts\n\nA label's text can be bigger, or in another kind of letters. `setFont` takes a **Font**, from the package `javafx.scene.text`: `Font.font(\"Serif\", 22)` is the Serif family, 22 points high. Every computer that runs JavaFX has its four own families: `System` (the one JavaFX uses unless told otherwise), `Serif`, `SansSerif` and `Monospaced`. Other family names, such as `Arial`, work only on computers that have that family, so this course uses only these four.\n\n```java\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.layout.BorderPane;\nimport javafx.scene.text.Font;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Label dish = new Label(\"Lentil soup\");\n        dish.setFont(Font.font(\"Serif\", 22));\n        Label time = new Label(\"45 min\");\n        time.setFont(Font.font(\"Monospaced\", 13));\n\n        BorderPane card = new BorderPane();\n        card.setTop(dish);\n        card.setCenter(new TextArea(\"Fry the onion.\\nAdd the lentils and the stock.\"));\n        card.setRight(time);\n\n        stage.setScene(new Scene(card));\n        stage.setTitle(\"Recipe card\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n```\n\n```window\n{\"events\":[],\"window\":{\"windows\":[{\"title\":\"Recipe card\",\"scene\":{\"root\":{\"n\":1,\"type\":\"BorderPane\",\"top\":{\"n\":2,\"type\":\"Label\",\"text\":\"Lentil soup\",\"font\":{\"family\":\"Serif\",\"size\":22}},\"center\":{\"n\":3,\"type\":\"TextArea\",\"text\":\"Fry the onion.\\nAdd the lentils and the stock.\"},\"right\":{\"n\":4,\"type\":\"Label\",\"text\":\"45 min\",\"font\":{\"family\":\"Monospaced\",\"size\":13}}}}}],\"problems\":[]},\"outline\":\"Window \\\"Recipe card\\\"\\n  BorderPane\\n    top: Label \\\"Lentil soup\\\", font Serif 22\\n    center: TextArea \\\"Fry the onion.\\\\nAdd the lentils and the stock.\\\"\\n    right: Label \\\"45 min\\\", font Monospaced 13\"}\n```\n\nThe window as text shows a font only when it isn't the normal one: `font Serif 22`. Buttons, text fields and text areas have `setFont` too.\n","task":"A card for a mushroom risotto. Fill in the three blanks, so that the dish's name is in the top region, the method in the center and the servings at the bottom. The window it should show is drawn below.\n","kind":"fill","seed":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.layout.BorderPane;\nimport javafx.scene.text.Font;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Label dish = new Label(\"Mushroom risotto\");\n        dish.setFont(Font.font(\"Serif\", 20));\n        TextArea method = new TextArea(\"Soften the onion.\\nStir in the rice, then the stock.\");\n        Label serves = new Label(\"Serves 2\");\n\n        BorderPane card = new BorderPane();\n        card.[[setTop]](dish);\n        card.[[setCenter]](method);\n        card.[[setBottom]](serves);\n\n        stage.setScene(new Scene(card));\n        stage.setTitle(\"Recipe card\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","solution":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.layout.BorderPane;\nimport javafx.scene.text.Font;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Label dish = new Label(\"Mushroom risotto\");\n        dish.setFont(Font.font(\"Serif\", 20));\n        TextArea method = new TextArea(\"Soften the onion.\\nStir in the rice, then the stock.\");\n        Label serves = new Label(\"Serves 2\");\n\n        BorderPane card = new BorderPane();\n        card.setTop(dish);\n        card.setCenter(method);\n        card.setBottom(serves);\n\n        stage.setScene(new Scene(card));\n        stage.setTitle(\"Recipe card\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","hints":["Each region has its own method: `setTop`, `setRight`, `setBottom`, `setLeft` and `setCenter`.","The name goes to `setTop`, the method to `setCenter` and the servings to `setBottom`."],"tests":[{"name":"Window","stdin":"","expect":"","hidden":false,"events":[],"window":{"windows":[{"title":"Recipe card","scene":{"root":{"n":1,"type":"BorderPane","top":{"n":2,"type":"Label","text":"Mushroom risotto","font":{"family":"Serif","size":20}},"center":{"n":3,"type":"TextArea","text":"Soften the onion.\nStir in the rice, then the stock."},"bottom":{"n":4,"type":"Label","text":"Serves 2"}}}}],"problems":[]},"outline":"Window \"Recipe card\"\n  BorderPane\n    top: Label \"Mushroom risotto\", font Serif 20\n    center: TextArea \"Soften the onion.\\nStir in the rice, then the stock.\"\n    bottom: Label \"Serves 2\""}],"require":[],"forbid":[],"more":[{"task":"A card for a leek pie changes its mind a few times. `card.getChildren()` is the list of nodes in all of a BorderPane's regions, and `getTop()` returns a Node, which the program casts to a Label (module 36). What does the program print?\n","kind":"predict","seed":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.layout.BorderPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        BorderPane card = new BorderPane();\n        Label dish = new Label(\"Leek pie\");\n        card.setTop(dish);\n        card.setBottom(new Label(\"Serves 6\"));\n        card.setLeft(new Label(\"Vegetarian\"));\n        System.out.println(card.getChildren().size());\n\n        card.setTop(new Label(\"Leek and potato pie\"));\n        System.out.println(card.getChildren().size() + \" \" + (dish.getParent() == null));\n\n        card.setLeft(null);\n        card.setCenter(dish);\n        Label top = (Label) card.getTop();\n        System.out.println(card.getChildren().size() + \" \" + top.getText());\n\n        stage.setScene(new Scene(card));\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","solution":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.layout.BorderPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        BorderPane card = new BorderPane();\n        Label dish = new Label(\"Leek pie\");\n        card.setTop(dish);\n        card.setBottom(new Label(\"Serves 6\"));\n        card.setLeft(new Label(\"Vegetarian\"));\n        System.out.println(card.getChildren().size());\n\n        card.setTop(new Label(\"Leek and potato pie\"));\n        System.out.println(card.getChildren().size() + \" \" + (dish.getParent() == null));\n\n        card.setLeft(null);\n        card.setCenter(dish);\n        Label top = (Label) card.getTop();\n        System.out.println(card.getChildren().size() + \" \" + top.getText());\n\n        stage.setScene(new Scene(card));\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","hints":["Three regions are set at first. Setting the top again replaces `dish`, so the card still holds three nodes, and `dish` is in none of them.","`setLeft(null)` empties the left region, and `setCenter(dish)` puts `dish` back in, now in the center. The top region still holds the second label."],"tests":[{"name":"Output","stdin":"","expect":"3\n3 true\n3 Leek and potato pie","hidden":false}],"require":[],"forbid":[],"lines":["3","3 true","3 Leek and potato pie"]},{"task":"The recipe app reads a card from the file `recipe.txt`. Its first line is the dish, its second line how long the dish takes, and every line after that is a step of the method. A recipe has at least two steps. Build the window: the title is `Recipe card`, and the root is a BorderPane with:\n\n- top: a label with the dish, in the font `Font.font(\"Serif\", 20)`\n- right: a label with the time\n- center: a TextArea holding the steps, each on its own line (`\\n` between them, none after the last)\n- bottom: a label with the number of steps, like `3 steps`\n\nThe left region stays empty. The text area doesn't wrap its lines, and it stays editable. For the file shown below, the window should look like the drawing under it.\n","kind":"code","seed":"import java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.List;\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.layout.BorderPane;\nimport javafx.scene.text.Font;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) throws Exception {\n        List<String> lines = Files.readAllLines(Paths.get(\"recipe.txt\"));\n        BorderPane card = new BorderPane();\n\n        stage.setScene(new Scene(card));\n        stage.setTitle(\"Recipe card\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","solution":"import java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.List;\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.layout.BorderPane;\nimport javafx.scene.text.Font;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) throws Exception {\n        List<String> lines = Files.readAllLines(Paths.get(\"recipe.txt\"));\n        BorderPane card = new BorderPane();\n\n        Label dish = new Label(lines.get(0));\n        dish.setFont(Font.font(\"Serif\", 20));\n        card.setTop(dish);\n        card.setRight(new Label(lines.get(1)));\n\n        String steps = \"\";\n        for (int i = 2; i < lines.size(); i++) {\n            if (i > 2) {\n                steps = steps + \"\\n\";\n            }\n            steps = steps + lines.get(i);\n        }\n        card.setCenter(new TextArea(steps));\n        card.setBottom(new Label((lines.size() - 2) + \" steps\"));\n\n        stage.setScene(new Scene(card));\n        stage.setTitle(\"Recipe card\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","hints":["`lines.get(0)` is the dish and `lines.get(1)` the time. The steps are the lines from index 2 on: a loop from 2 to `lines.size() - 1`.","Build the area's text in a String with a loop that adds `\\n` before every step but the first. The number of steps is `lines.size() - 2`."],"tests":[{"name":"Test 1","stdin":"","files":{"recipe.txt":"Lemon pancakes\n30 min\nWhisk the flour, the eggs and the milk.\nGrate in the lemon zest.\nFry a ladle of batter at a time.\n"},"expect":"","hidden":false,"events":[],"window":{"windows":[{"title":"Recipe card","scene":{"root":{"n":1,"type":"BorderPane","top":{"n":2,"type":"Label","text":"Lemon pancakes","font":{"family":"Serif","size":20}},"center":{"n":3,"type":"TextArea","text":"Whisk the flour, the eggs and the milk.\nGrate in the lemon zest.\nFry a ladle of batter at a time."},"right":{"n":4,"type":"Label","text":"30 min"},"bottom":{"n":5,"type":"Label","text":"3 steps"}}}}],"problems":[]},"outline":"Window \"Recipe card\"\n  BorderPane\n    top: Label \"Lemon pancakes\", font Serif 20\n    center: TextArea \"Whisk the flour, the eggs and the milk.\\nGrate in the lemon zest.\\nFry a ladle of batter at a time.\"\n    right: Label \"30 min\"\n    bottom: Label \"3 steps\""},{"name":"Test 2","stdin":"","files":{"recipe.txt":"Green salad\n10 min\nWash the leaves.\nShake the dressing in a jar.\n"},"expect":"","hidden":true,"events":[],"window":{"windows":[{"title":"Recipe card","scene":{"root":{"n":1,"type":"BorderPane","top":{"n":2,"type":"Label","text":"Green salad","font":{"family":"Serif","size":20}},"center":{"n":3,"type":"TextArea","text":"Wash the leaves.\nShake the dressing in a jar."},"right":{"n":4,"type":"Label","text":"10 min"},"bottom":{"n":5,"type":"Label","text":"2 steps"}}}}],"problems":[]},"outline":"Window \"Recipe card\"\n  BorderPane\n    top: Label \"Green salad\", font Serif 20\n    center: TextArea \"Wash the leaves.\\nShake the dressing in a jar.\"\n    right: Label \"10 min\"\n    bottom: Label \"2 steps\""},{"name":"Test 3","stdin":"","files":{"recipe.txt":"Bean chili\n1 hour\nFry the onion and the garlic.\nAdd the spices.\nAdd the beans and the tomatoes.\nSimmer for 40 minutes.\nServe with rice.\n"},"expect":"","hidden":true,"events":["type TextArea 1 \"\\nTop with yogurt.\""],"window":{"windows":[{"title":"Recipe card","scene":{"root":{"n":1,"type":"BorderPane","top":{"n":2,"type":"Label","text":"Bean chili","font":{"family":"Serif","size":20}},"center":{"n":3,"type":"TextArea","text":"Fry the onion and the garlic.\nAdd the spices.\nAdd the beans and the tomatoes.\nSimmer for 40 minutes.\nServe with rice.\nTop with yogurt."},"right":{"n":4,"type":"Label","text":"1 hour"},"bottom":{"n":5,"type":"Label","text":"5 steps"}}}}],"problems":[]},"outline":"Window \"Recipe card\"\n  BorderPane\n    top: Label \"Bean chili\", font Serif 20\n    center: TextArea \"Fry the onion and the garlic.\\nAdd the spices.\\nAdd the beans and the tomatoes.\\nSimmer for 40 minutes.\\nServe with rice.\\nTop with yogurt.\"\n    right: Label \"1 hour\"\n    bottom: Label \"5 steps\""}],"require":[],"forbid":[]}]}