{"id":"gui-basics-text-input","slug":"text-input","title":"Text fields and text areas","text":"Labels and buttons show text that the program chose. For text that the user writes, JavaFX has **text fields** and **text areas**.\n\n### TextField\n\nA **TextField** is a box for one line of text. The catalog search of a library:\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.TextField;\nimport javafx.scene.layout.FlowPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Label what = new Label(\"Find a book:\");\n        TextField search = new TextField();\n        search.setPromptText(\"Title or author\");\n        Button go = new Button(\"Search\");\n\n        FlowPane bar = new FlowPane(what, search, go);\n        stage.setScene(new Scene(bar));\n        stage.setTitle(\"City Library\");\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\":\"City Library\",\"scene\":{\"root\":{\"n\":1,\"type\":\"FlowPane\",\"children\":[{\"n\":2,\"type\":\"Label\",\"text\":\"Find a book:\"},{\"n\":3,\"type\":\"TextField\",\"text\":\"\",\"promptText\":\"Title or author\"},{\"n\":4,\"type\":\"Button\",\"text\":\"Search\"}]}}}],\"problems\":[]},\"outline\":\"Window \\\"City Library\\\"\\n  FlowPane\\n    Label \\\"Find a book:\\\"\\n    TextField \\\"\\\", prompt \\\"Title or author\\\"\\n    Button \\\"Search\\\"\"}\n```\n\n- `new TextField()` makes an empty field. `new TextField(\"Dune\")` would start with the text Dune in it.\n- `setPromptText(\"Title or author\")` sets the field's **prompt text**: a hint, shown in gray while the field is empty (JavaFX's own look also hides it while the field has the keyboard focus). It isn't the field's text: `getText()` never returns it.\n- In the window as text, a text field shows its text in quotes (here it's empty, `\"\"`), and then its prompt text.\n\n### Clicks and typing in examples\n\nAn example can have an `events` block after it: clicks and typing that Java Arena does after `start`, as if you had done them in the drawn window. The drawing then shows the window after them. Here, someone types The Hobbit into the search field:\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.TextField;\nimport javafx.scene.layout.FlowPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Label what = new Label(\"Find a book:\");\n        TextField search = new TextField();\n        search.setPromptText(\"Title or author\");\n        Button go = new Button(\"Search\");\n\n        FlowPane bar = new FlowPane(what, search, go);\n        stage.setScene(new Scene(bar));\n        stage.setTitle(\"City Library\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n```\n\n```window\n{\"events\":[\"type TextField 1 \\\"The Hobbit\\\"\"],\"window\":{\"windows\":[{\"title\":\"City Library\",\"scene\":{\"root\":{\"n\":1,\"type\":\"FlowPane\",\"children\":[{\"n\":2,\"type\":\"Label\",\"text\":\"Find a book:\"},{\"n\":3,\"type\":\"TextField\",\"text\":\"The Hobbit\",\"promptText\":\"Title or author\"},{\"n\":4,\"type\":\"Button\",\"text\":\"Search\"}]}}}],\"problems\":[]},\"outline\":\"Window \\\"City Library\\\"\\n  FlowPane\\n    Label \\\"Find a book:\\\"\\n    TextField \\\"The Hobbit\\\", prompt \\\"Title or author\\\"\\n    Button \\\"Search\\\"\"}\n```\n\n`type TextField 1 \"The Hobbit\"` means: type The Hobbit into the first text field of the window. Challenges use the same lines to click and type in your window, and the task card shows them in words: Type \"The Hobbit\" in text field 1.\n\n### TextArea\n\nA **TextArea** holds several lines of text. A `\\n` in its text starts a new line, as it does in a String you print. `setWrapText(true)` makes a line that is too long for the area go on in the next line, instead of running past the area's edge:\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.FlowPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Label about = new Label(\"A note for the librarian:\");\n        TextArea note = new TextArea(\"Page 112 is torn.\\nThe cover is fine.\");\n        note.setWrapText(true);\n\n        FlowPane form = new FlowPane(about, note);\n        stage.setScene(new Scene(form));\n        stage.setTitle(\"Return a book\");\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\":\"Return a book\",\"scene\":{\"root\":{\"n\":1,\"type\":\"FlowPane\",\"children\":[{\"n\":2,\"type\":\"Label\",\"text\":\"A note for the librarian:\"},{\"n\":3,\"type\":\"TextArea\",\"text\":\"Page 112 is torn.\\nThe cover is fine.\",\"wrapText\":true}]}}}],\"problems\":[]},\"outline\":\"Window \\\"Return a book\\\"\\n  FlowPane\\n    Label \\\"A note for the librarian:\\\"\\n    TextArea \\\"Page 112 is torn.\\\\nThe cover is fine.\\\" (wraps text)\"}\n```\n\nIn the window as text, the line breaks of a text are written `\\n`, and `(wraps text)` marks the area that wraps.\n\n### Reading and changing the text\n\nText fields and text areas share these methods:\n\n| method | what it does |\n| --- | --- |\n| `getText()` | returns the text that's in it now |\n| `setText(text)` | replaces the text |\n| `appendText(text)` | adds to the end of the text |\n| `clear()` | empties it |\n| `getLength()` | returns the number of characters in the text |\n| `setEditable(false)` | the user can read the text, but no longer change it |\n\nA window for renewing a loan, with the program filling in what it already knows:\n\n```java\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.control.TextField;\nimport javafx.scene.layout.FlowPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        TextField card = new TextField();\n        card.setText(\"10442211\");\n        card.setEditable(false);\n        System.out.println(\"The card number has \" + card.getLength() + \" digits\");\n\n        TextArea history = new TextArea(\"Borrowed on May 2\");\n        history.appendText(\"\\nRenewed on May 23\");\n        System.out.println(history.getText());\n\n        FlowPane form = new FlowPane(card, history);\n        stage.setScene(new Scene(form));\n        stage.setTitle(\"Renew a loan\");\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\":\"Renew a loan\",\"scene\":{\"root\":{\"n\":1,\"type\":\"FlowPane\",\"children\":[{\"n\":2,\"type\":\"TextField\",\"text\":\"10442211\",\"editable\":false},{\"n\":3,\"type\":\"TextArea\",\"text\":\"Borrowed on May 2\\nRenewed on May 23\"}]}}}],\"problems\":[]},\"outline\":\"Window \\\"Renew a loan\\\"\\n  FlowPane\\n    TextField \\\"10442211\\\" (not editable)\\n    TextArea \\\"Borrowed on May 2\\\\nRenewed on May 23\\\"\"}\n```\n\n```output\nThe card number has 8 digits\nBorrowed on May 2\nRenewed on May 23\n```\n\nThe card number can't be changed in the window: the window as text marks that field `(not editable)`.\n\n### When to read what the user typed\n\n`start` runs before the user does anything. So `getText()` in `start` returns the text that the program put into the field, never what the user types later:\n\n```java\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextField;\nimport javafx.scene.layout.FlowPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        TextField name = new TextField();\n        name.setPromptText(\"Your name\");\n        FlowPane form = new FlowPane(new Label(\"Name:\"), name);\n        System.out.println(\"In start, the field holds [\" + name.getText() + \"]\");\n\n        stage.setScene(new Scene(form));\n        stage.setTitle(\"New member\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n```\n\n```window\n{\"events\":[\"type TextField 1 \\\"Grace\\\"\"],\"window\":{\"windows\":[{\"title\":\"New member\",\"scene\":{\"root\":{\"n\":1,\"type\":\"FlowPane\",\"children\":[{\"n\":2,\"type\":\"Label\",\"text\":\"Name:\"},{\"n\":3,\"type\":\"TextField\",\"text\":\"Grace\",\"promptText\":\"Your name\"}]}}}],\"problems\":[]},\"outline\":\"Window \\\"New member\\\"\\n  FlowPane\\n    Label \\\"Name:\\\"\\n    TextField \\\"Grace\\\", prompt \\\"Your name\\\"\"}\n```\n\n```output\nIn start, the field holds []\n```\n\nThe window shows Grace in the field, but `start` printed an empty text: when it ran, nobody had typed yet. To use what the user typed, a program needs code that runs after the typing, for example when the user clicks a button. That's what module 49 is about. In this module, the windows show their fields, and you can type into them.\n\n### PasswordField\n\nA **PasswordField** is a TextField that shows a dot in place of each character typed, for passwords and PIN codes. It has the same methods, and `getText()` returns what was really typed. It's in `javafx.scene.control` with the others.\n","task":"A library's window for renewing a loan. Build it: the title is `Renew a loan`, and the root is a FlowPane that holds, in this order:\n\n- the label `Card number`\n- an empty text field with the prompt text `8 digits`\n- the label `Book`\n- an empty text field with the prompt text `Title`\n- the button `Renew`\n\nNo spacing, padding or sizes. The window it should show is drawn below.\n","kind":"code","seed":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Button;\nimport javafx.scene.control.Label;\nimport javafx.scene.layout.FlowPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        FlowPane form = new FlowPane();\n\n        stage.setScene(new Scene(form));\n        stage.setTitle(\"Renew a loan\");\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.Button;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TextField;\nimport javafx.scene.layout.FlowPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        TextField card = new TextField();\n        card.setPromptText(\"8 digits\");\n        TextField book = new TextField();\n        book.setPromptText(\"Title\");\n\n        FlowPane form = new FlowPane();\n        form.getChildren().addAll(new Label(\"Card number\"), card, new Label(\"Book\"), book, new Button(\"Renew\"));\n\n        stage.setScene(new Scene(form));\n        stage.setTitle(\"Renew a loan\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","hints":["TextField needs its import: `import javafx.scene.control.TextField;`. Make each field, then give it its prompt text with `setPromptText(\"8 digits\")`.","Keep each field in a variable, so you can set its prompt text before adding it: `form.getChildren().addAll(new Label(\"Card number\"), card, ...);`."],"tests":[{"name":"Test 1","stdin":"","expect":"","hidden":false,"events":[],"window":{"windows":[{"title":"Renew a loan","scene":{"root":{"n":1,"type":"FlowPane","children":[{"n":2,"type":"Label","text":"Card number"},{"n":3,"type":"TextField","text":"","promptText":"8 digits"},{"n":4,"type":"Label","text":"Book"},{"n":5,"type":"TextField","text":"","promptText":"Title"},{"n":6,"type":"Button","text":"Renew"}]}}}],"problems":[]},"outline":"Window \"Renew a loan\"\n  FlowPane\n    Label \"Card number\"\n    TextField \"\", prompt \"8 digits\"\n    Label \"Book\"\n    TextField \"\", prompt \"Title\"\n    Button \"Renew\""},{"name":"Test 2","stdin":"","expect":"","hidden":true,"events":["type TextField 1 \"10442211\"","type TextField 2 \"Middlemarch\""],"window":{"windows":[{"title":"Renew a loan","scene":{"root":{"n":1,"type":"FlowPane","children":[{"n":2,"type":"Label","text":"Card number"},{"n":3,"type":"TextField","text":"10442211","promptText":"8 digits"},{"n":4,"type":"Label","text":"Book"},{"n":5,"type":"TextField","text":"Middlemarch","promptText":"Title"},{"n":6,"type":"Button","text":"Renew"}]}}}],"problems":[]},"outline":"Window \"Renew a loan\"\n  FlowPane\n    Label \"Card number\"\n    TextField \"10442211\", prompt \"8 digits\"\n    Label \"Book\"\n    TextField \"Middlemarch\", prompt \"Title\"\n    Button \"Renew\""}],"require":[],"forbid":[],"more":[{"task":"The returns desk tries out the methods of text fields and text areas. What does the program print?\n","kind":"predict","seed":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.control.TextArea;\nimport javafx.scene.control.TextField;\nimport javafx.scene.layout.FlowPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        TextField title = new TextField(\"Dune\");\n        title.setPromptText(\"Title\");\n        title.appendText(\" Messiah\");\n        System.out.println(title.getText() + \" \" + title.getLength());\n        title.clear();\n        System.out.println(\"[\" + title.getText() + \"] \" + title.getPromptText());\n\n        TextArea note = new TextArea(\"Due on Friday\");\n        note.appendText(\"\\nRenewed once\");\n        note.setText(note.getText().toUpperCase());\n        System.out.println(note.getText().split(\"\\n\")[1]);\n\n        stage.setScene(new Scene(new FlowPane(title, note)));\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.TextArea;\nimport javafx.scene.control.TextField;\nimport javafx.scene.layout.FlowPane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        TextField title = new TextField(\"Dune\");\n        title.setPromptText(\"Title\");\n        title.appendText(\" Messiah\");\n        System.out.println(title.getText() + \" \" + title.getLength());\n        title.clear();\n        System.out.println(\"[\" + title.getText() + \"] \" + title.getPromptText());\n\n        TextArea note = new TextArea(\"Due on Friday\");\n        note.appendText(\"\\nRenewed once\");\n        note.setText(note.getText().toUpperCase());\n        System.out.println(note.getText().split(\"\\n\")[1]);\n\n        stage.setScene(new Scene(new FlowPane(title, note)));\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","hints":["`appendText` adds to the end, so the field holds `Dune Messiah`: 12 characters, the space too. `clear()` empties the text, but the prompt text stays.","The area's text has two lines. `setText` replaces it with the same text in capital letters, and `split(\"\\n\")[1]` is its second line."],"tests":[{"name":"Output","stdin":"","expect":"Dune Messiah 12\n[] Title\nRENEWED ONCE","hidden":false}],"require":[],"forbid":[],"lines":["Dune Messiah 12","[] Title","RENEWED ONCE"]},{"task":"The renewals desk shows a member's details from the file `member.txt`. Its first line is the member's name, and its second line the card number. Build the window: the title is `Renewals`, and the root is a FlowPane that holds, in this order:\n\n- the label `Member`\n- a text field holding the name, not editable\n- the label `Card`\n- a text field holding the card number, not editable\n- the label `PIN`\n- an empty PasswordField with the prompt text `4 digits`\n\nNo spacing, padding or sizes. 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.PasswordField;\nimport javafx.scene.control.TextField;\nimport javafx.scene.layout.FlowPane;\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(\"member.txt\"));\n        FlowPane form = new FlowPane();\n\n        stage.setScene(new Scene(form));\n        stage.setTitle(\"Renewals\");\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.PasswordField;\nimport javafx.scene.control.TextField;\nimport javafx.scene.layout.FlowPane;\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(\"member.txt\"));\n        FlowPane form = new FlowPane();\n\n        TextField name = new TextField(lines.get(0));\n        name.setEditable(false);\n        TextField card = new TextField(lines.get(1));\n        card.setEditable(false);\n        PasswordField pin = new PasswordField();\n        pin.setPromptText(\"4 digits\");\n        form.getChildren().addAll(new Label(\"Member\"), name, new Label(\"Card\"), card, new Label(\"PIN\"), pin);\n\n        stage.setScene(new Scene(form));\n        stage.setTitle(\"Renewals\");\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 name and `lines.get(1)` the card number. `new TextField(lines.get(0))` makes a field that starts with that text.","Call `setEditable(false)` on both text fields, and `setPromptText(\"4 digits\")` on the PasswordField. Then add the six nodes in the order of the task."],"tests":[{"name":"Test 1","stdin":"","files":{"member.txt":"Ada Okafor\n10442211\n"},"expect":"","hidden":false,"events":[],"window":{"windows":[{"title":"Renewals","scene":{"root":{"n":1,"type":"FlowPane","children":[{"n":2,"type":"Label","text":"Member"},{"n":3,"type":"TextField","text":"Ada Okafor","editable":false},{"n":4,"type":"Label","text":"Card"},{"n":5,"type":"TextField","text":"10442211","editable":false},{"n":6,"type":"Label","text":"PIN"},{"n":7,"type":"PasswordField","text":"","promptText":"4 digits"}]}}}],"problems":[]},"outline":"Window \"Renewals\"\n  FlowPane\n    Label \"Member\"\n    TextField \"Ada Okafor\" (not editable)\n    Label \"Card\"\n    TextField \"10442211\" (not editable)\n    Label \"PIN\"\n    PasswordField \"\", prompt \"4 digits\""},{"name":"Test 2","stdin":"","files":{"member.txt":"Linus Berg\n20871356\n"},"expect":"","hidden":true,"events":["type PasswordField 1 \"4321\""],"window":{"windows":[{"title":"Renewals","scene":{"root":{"n":1,"type":"FlowPane","children":[{"n":2,"type":"Label","text":"Member"},{"n":3,"type":"TextField","text":"Linus Berg","editable":false},{"n":4,"type":"Label","text":"Card"},{"n":5,"type":"TextField","text":"20871356","editable":false},{"n":6,"type":"Label","text":"PIN"},{"n":7,"type":"PasswordField","text":"4321","promptText":"4 digits"}]}}}],"problems":[]},"outline":"Window \"Renewals\"\n  FlowPane\n    Label \"Member\"\n    TextField \"Linus Berg\" (not editable)\n    Label \"Card\"\n    TextField \"20871356\" (not editable)\n    Label \"PIN\"\n    PasswordField \"4321\", prompt \"4 digits\""}],"require":[],"forbid":[]}]}