diff --git a/tutorials/assets/DaDuke.png b/tutorials/assets/DaDuke.png deleted file mode 100644 index d893658717..0000000000 Binary files a/tutorials/assets/DaDuke.png and /dev/null differ diff --git a/tutorials/assets/DaUser.png b/tutorials/assets/DaUser.png deleted file mode 100644 index 3c82f45461..0000000000 Binary files a/tutorials/assets/DaUser.png and /dev/null differ diff --git a/tutorials/assets/DialogBoxController.png b/tutorials/assets/DialogBoxController.png deleted file mode 100644 index 1870dcbc0b..0000000000 Binary files a/tutorials/assets/DialogBoxController.png and /dev/null differ diff --git a/tutorials/assets/DialogBoxesIteration2.png b/tutorials/assets/DialogBoxesIteration2.png deleted file mode 100644 index 31e8f39e3e..0000000000 Binary files a/tutorials/assets/DialogBoxesIteration2.png and /dev/null differ diff --git a/tutorials/assets/DialogBoxesIteration3.png b/tutorials/assets/DialogBoxesIteration3.png deleted file mode 100644 index aea148d668..0000000000 Binary files a/tutorials/assets/DialogBoxesIteration3.png and /dev/null differ diff --git a/tutorials/assets/DukeMockup.png b/tutorials/assets/DukeMockup.png deleted file mode 100644 index adf8ba42ac..0000000000 Binary files a/tutorials/assets/DukeMockup.png and /dev/null differ diff --git a/tutorials/assets/DukeSceneGraph.png b/tutorials/assets/DukeSceneGraph.png deleted file mode 100644 index 17bfe0d4f9..0000000000 Binary files a/tutorials/assets/DukeSceneGraph.png and /dev/null differ diff --git a/tutorials/assets/DukeSceneGraph.puml b/tutorials/assets/DukeSceneGraph.puml deleted file mode 100644 index ea7937255a..0000000000 --- a/tutorials/assets/DukeSceneGraph.puml +++ /dev/null @@ -1,24 +0,0 @@ -@startuml -hide members -hide circle -skinparam shadowing false -skinparam ClassFontSize 16 -skinparam ClassFontName Arial - -class Stage -class AnchorPane -class ScrollPane -class VBox -class ImageView -class Label - -AnchorPane -up-> Stage -ScrollPane -up-> AnchorPane - -TextField -up-> AnchorPane -Button -up-> AnchorPane - -VBox -up-> ScrollPane -ImageView -up-> VBox -Label -up-> VBox -@enduml diff --git a/tutorials/assets/EchoNotScrolling.png b/tutorials/assets/EchoNotScrolling.png deleted file mode 100644 index b56395ce88..0000000000 Binary files a/tutorials/assets/EchoNotScrolling.png and /dev/null differ diff --git a/tutorials/assets/FinalLayout.png b/tutorials/assets/FinalLayout.png deleted file mode 100644 index 5e2ec75d02..0000000000 Binary files a/tutorials/assets/FinalLayout.png and /dev/null differ diff --git a/tutorials/assets/GradleIcon.png b/tutorials/assets/GradleIcon.png deleted file mode 100644 index 61b0ad4da2..0000000000 Binary files a/tutorials/assets/GradleIcon.png and /dev/null differ diff --git a/tutorials/assets/HelloWorld.png b/tutorials/assets/HelloWorld.png deleted file mode 100644 index 3066d4a2e3..0000000000 Binary files a/tutorials/assets/HelloWorld.png and /dev/null differ diff --git a/tutorials/assets/ImportGradle.png b/tutorials/assets/ImportGradle.png deleted file mode 100644 index fca5c48df7..0000000000 Binary files a/tutorials/assets/ImportGradle.png and /dev/null differ diff --git a/tutorials/assets/JavaFxHierarchy.png b/tutorials/assets/JavaFxHierarchy.png deleted file mode 100644 index 87228d5c64..0000000000 Binary files a/tutorials/assets/JavaFxHierarchy.png and /dev/null differ diff --git a/tutorials/assets/JavaFxHierarchy.puml b/tutorials/assets/JavaFxHierarchy.puml deleted file mode 100644 index 77c8c00185..0000000000 --- a/tutorials/assets/JavaFxHierarchy.puml +++ /dev/null @@ -1,22 +0,0 @@ -@startuml -hide members -hide circle -skinparam shadowing false -skinparam ClassFontSize 16 -skinparam ClassFontName Arial - -Class Stage -Class Scene -Class "Root Node" as RN -Class Node -Class "Node" as Node1 -Class "Node" as Node2 -Class "Node" as Node3 - -Scene -up-> Stage : > must have one -RN -up-> Scene : > must have one -Node -up-> RN : > can have zero or more -Node1 -up-> Node -Node2 -up-> Node -Node3 -up-> Node -@enduml diff --git a/tutorials/assets/MainWindowController.png b/tutorials/assets/MainWindowController.png deleted file mode 100644 index 54f48f12b1..0000000000 Binary files a/tutorials/assets/MainWindowController.png and /dev/null differ diff --git a/tutorials/assets/MockupButton.png b/tutorials/assets/MockupButton.png deleted file mode 100644 index 352fb86ef9..0000000000 Binary files a/tutorials/assets/MockupButton.png and /dev/null differ diff --git a/tutorials/assets/MockupImageView.png b/tutorials/assets/MockupImageView.png deleted file mode 100644 index e580196ecf..0000000000 Binary files a/tutorials/assets/MockupImageView.png and /dev/null differ diff --git a/tutorials/assets/MockupLabel.png b/tutorials/assets/MockupLabel.png deleted file mode 100644 index 0980c3c50c..0000000000 Binary files a/tutorials/assets/MockupLabel.png and /dev/null differ diff --git a/tutorials/assets/MockupScrollPane.png b/tutorials/assets/MockupScrollPane.png deleted file mode 100644 index a29de75abb..0000000000 Binary files a/tutorials/assets/MockupScrollPane.png and /dev/null differ diff --git a/tutorials/assets/MockupTextField.png b/tutorials/assets/MockupTextField.png deleted file mode 100644 index a8cfded3bb..0000000000 Binary files a/tutorials/assets/MockupTextField.png and /dev/null differ diff --git a/tutorials/assets/NewEmptyProject.png b/tutorials/assets/NewEmptyProject.png deleted file mode 100644 index 94e076c206..0000000000 Binary files a/tutorials/assets/NewEmptyProject.png and /dev/null differ diff --git a/tutorials/assets/RawLayout.png b/tutorials/assets/RawLayout.png deleted file mode 100644 index 02183af4de..0000000000 Binary files a/tutorials/assets/RawLayout.png and /dev/null differ diff --git a/tutorials/assets/SceneBuilder.png b/tutorials/assets/SceneBuilder.png deleted file mode 100644 index 106484f594..0000000000 Binary files a/tutorials/assets/SceneBuilder.png and /dev/null differ diff --git a/tutorials/gradleTutorial.md b/tutorials/gradleTutorial.md deleted file mode 100644 index 08292b118d..0000000000 --- a/tutorials/gradleTutorial.md +++ /dev/null @@ -1,170 +0,0 @@ -# Gradle Tutorial - -Gradle is a _build automation tool_ used to automate build processes. There are many ways of integrating Gradle into a project. In this guide, we will be using the _Gradle wrapper_. - -* [Introduction](#introduction) -* [Adding Gradle Support to Your Project](#adding-gradle-support-to-your-project) -* [Adding Plugins](#adding-plugins) - * [CheckStyle](#checkstyle) - * [Shadow](#shadow) -* [Adding Dependencies](#adding-dependencies) - * [JUnit](#junit) -* [Further Reading](#further-reading) - -## Introduction - -As a developer, you write a _build file_ that describes the project. A build file mainly consists of _plugins_, _tasks_ and _properties_. - -* **Plugins** extend the functionality of Gradle. For example, the `java` plugin adds support for `Java` projects. - -* **Tasks** are reusable blocks of logic. For example, the task `clean` simply deletes the project build directory. Tasks can be composed of other tasks or be dependent on another task. - -* **Properties** change the behavior of tasks. For instance, `mainClassName` of the `application` plugin is a compulsory property which tells Gradle which class is the entrypoint to your application. - As Gradle favors [_convention over configuration_](https://en.wikipedia.org/wiki/Convention_over_configuration), there is not much to you need to configure if you follow the recommended directory structure. - -## Adding Gradle Support to Your Project - -1. Pull the branch named `gradle`. Merge it to the `master` branch. This will add the Gradle wrapper to your project. - ``` - git checkout --track origin/gradle - git checkout master - git merge gradle - ``` -1. Open the `build.gradle` file in an editor. Update the following code block to point to the main class (i.e., the one containing the `main` method) of your application. The code below assumes your main class is `seedu.duke.Duke` - ```groovy - application { - mainClassName = "seedu.duke.Duke" - } - ``` -1. To check if Gradle has been added to the project correctly, open a terminal window, navigate to the root directory of your project and run the command `gradlew run`. This should result in Gradle running the main method of your project. - -:bulb: Simply run the command `gradlew {taskName}` in the terminal and Gradle will run the task! Here are some example commands: -* `gradlew tasks` (or `gradlew tasks --all`): shows a list of tasks available -* `gradlew run`: runs the main class of your project - -:bulb: Some plugins may add more helpful tasks so be sure to check their documentation! - -#### Using Gradle from within Intellij - -1. After adding support for Gradle, Intellij might automatically ask you (via a pop-up at the bottom right corner of the Window) whether to import the project as a Gradle project. In that case, go ahead and say yes. - -1. If the above didn't happen, import the Gradle project by `Help > Find Action > Import Gradle Project`. - ![Import Gradle](assets/ImportGradle.png) - -1. If the above didn't work either, close Intellij, delete the Intellij project files (i.e., `.idea` folder and `*.iml` files), and set up the project again, but instead of choosing `Create project from existing sources`, choose `Import project from external model` -> `Gradle`. - -After this, IntelliJ IDEA will identify your project as a Gradle project and you will gain access to the `Gradle Toolbar`. Through the toolbar, you run Gradle tasks and view your project's dependencies. - -You can click on the Gradle icon in the Gradle toolbar and create a new run configuration for running Gradle tasks without needing to type a `gradlew` command. - -![Gradle icon](assets/GradleIcon.png) - -## Adding Plugins - -Gradle plugins are reusable units of build logic. Most common build tasks are provided as core plugins by Gradle. Given below are instructions on how to use some useful plugins: - -### CheckStyle - -To add support for _Checkstyle_ (a tool to check if your code complies with a set of style rules), which comes as a core plugin, simply add the line `id 'checkstyle'` into the `plugins` block. - -Your build file should look something like this now: -```groovy -plugins { - id 'java' - id 'application' - id 'checkstyle' -} - -checkstyle { - toolVersion = '8.23' -} - -// ... -``` - -Checkstyle expects configuration files for checkstyle to be in `./config/checkstyle/` by convention. -A sample checkstyle rule configuration is provided in the branch. - -The plugin adds a few _tasks_ to your project. Run `gradlew checkstyleMain checkstyleTest` to verify that you have set up Checkstyle properly (the command will check your main code and test code against the style rules). - -**Resources**: -* [Gradle documentation for CheckStyle plugin](https://docs.gradle.org/current/userguide/checkstyle_plugin.html) - -### Shadow - -Shadow is a plugin that packages an application into an executable jar file. To use it, first add the following line to your Gradle build file: -```groovy -plugins { - //... - id 'com.github.johnrengelman.shadow' version '5.1.0' - //... -} -``` - -The plugin can be configured by setting some properties. Let's try to produce a jar file with the name in format of `{baseName}-{version}.jar`. - -Add the following block to your build file: -```groovy -shadowJar { - archiveBaseName = "duke" - archiveVersion = "0.1.3" - archiveClassifier = null - archiveAppendix = null -} -``` - -Now you can run the command `gradlew shadowJar`.It publishes an executable jar to `./build/libs/`. You should be able to able to execute the created jar file by double-clicking it or using the command `java -jar {jarName}`? - -**Resources**: -* [Gradle documentation for Shadow plugin](https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow) -* [Gradle documentation for JUnit](https://docs.gradle.org/current/userguide/java_testing.html#using_junit5) -* [More about the Shadow plugin](https://imperceptiblethoughts.com/shadow/introduction/) - -## Adding Dependencies - -Gradle can automate the management of dependencies to third-party libraries. Given below are some examples. - -### JUnit - -JUnit is a testing framework for Java. It allows developers to write tests and run them. To manage JUnit dependency via Gradle, add the following to your build file: - -```groovy -dependencies { - testImplementation 'org.junit.jupiter:junit-jupiter:5.5.0' -} -``` - -Then, configure Gradle to use JUnit by adding the following block to your build file: - -```groovy -test { - useJUnitPlatform() -} -``` -By convention, java tests belong in `src/test/java` folder. Create a new `test/java` folder in under `src`. -``` -src -├─main -│ └─java -│ └─seedu/duke/Duke.java -└─test - └─java - └─seedu/duke/DukeTest.java -``` - -If you have imported your Gradle project into IntelliJ IDEA, you will notice that IDEA is able to mark the test directory as the _Test root_ (colored in green by default) automatically. - -You can now write a test (e.g., `test/java/seedu/duke/DukeTest.java`) and run it with `gradlew test`. - -**Resources**: -* [Gradle documentation for JUnit](https://docs.gradle.org/current/userguide/java_testing.html#using_junit5) - -## Further Reading - -Now that you have a general idea of how to accomplish basic tasks with Gradle, here's a list of material you can read to further your understanding. - -* [Official Gradle Documentation](https://docs.gradle.org/current/userguide/userguide.html) - ----------------------------------------------------------------------------------------- -**Authors:** -* Initial Version: Jeffry Lum diff --git a/tutorials/javaFxTutorialPart1.md b/tutorials/javaFxTutorialPart1.md deleted file mode 100644 index 6400dfa154..0000000000 --- a/tutorials/javaFxTutorialPart1.md +++ /dev/null @@ -1,117 +0,0 @@ -# JavaFX Tutorial Part 1 – Introduction - -## JavaFX lifecycle of an application - -Imagine yourself as a director of a play. First you provision the props that you will feature in your play. These can be hand props for your actors to interact with or even set dressings just to liven up the background. You then decide where to layout the props for every scene. With a proper script in hand, you can finally approach a theatre and request for a stage. There on, it’s just a matter of pulling the curtains on your masterpiece. - -![Hierarchy of Objects in JavaFX](assets/JavaFxHierarchy.png) - -A JavaFX application is like a play you are directing. Instead of creating props, you create `Nodes` (`Nodes` are the fundamental building blocks of a JavaFX application), and place them onto a `Scene` (a scene is a graph of `Node`s). Then, you set your `Scene` on a `Stage` provided by JavaFX. When you call `Stage#show()` method, JavaFX renders a window with your `Stage` on it. - -## Setting up Java FX - -### If you are not using Gradle - -1. Download the [JavaFX 11 SDK](https://gluonhq.com/products/javafx/) and unzip it. - -1. Import the `libs` folder from the SDK into your project (note: `JAVAFX_HOME` is the directory in which you have unzipped the JavaFX SDK). - - `File` > `Project Structure` > `Libraries` > `+` > `Java` > `{JAVAFX_HOME}/lib` - -1. From `Run` > `Edit Configurations`, add the following line into your `VM options` for each of the `main` classes. - - `--module-path {JAVAFX_HOME}/lib --add-modules javafx.controls,javafx.fxml`
- e.g., `--module-path C:/javafx-sdk-11.0.2/lib --add-modules javafx.controls,javafx.fxml` - -### If you are using Gradle - -Update your `build.gradle` to include the following lines: -```groovy -repositories { - mavenCentral() -} - -dependencies { - String javaFxVersion = '11' - - implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win' - implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac' - implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux' - implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win' - implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac' - implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux' - implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win' - implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac' - implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux' - implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win' - implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac' - implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux' -} -``` - -## Writing your first program - -As customary, let’s start off with a simple “Hello World” program. Modify your `Duke` class to extend `javafx.application.Application`. This requires you to override the `Application#start()` method and provide a concrete implementation. Notice that the method signature for `Application#start()` has a parameter `Stage`. This is the _primary stage_ that JavaFX provides. - -```java -import javafx.application.Application; -import javafx.scene.Scene; -import javafx.scene.control.Label; -import javafx.stage.Stage; - -public class Duke extends Application { - - // ... - - @Override - public void start(Stage stage) { - Label helloWorld = new Label("Hello World!"); // Creating a new Label control - Scene scene = new Scene(helloWorld); // Setting the scene to be our Label - - stage.setScene(scene); // Setting the stage to show our screen - stage.show(); // Render the stage. - } -} -``` - -Note how we have created a `Label` to contain the text that we want to show. We then create the `Scene` and set its content. Finally, we set the stage and show it. - -Next, we create another Java class, `Launcher`, as an entry point to our application. -The `Launcher` class is reproduced below in its entirety. - -```java -import javafx.application.Application; - -/** - * A launcher class to workaround classpath issues. - */ -public class Launcher { - public static void main(String[] args) { - Application.launch(Duke.class, args); - } -} -``` - -Run `Launcher` and you should see something like this: - -![Hello World](assets/HelloWorld.png) - -Congratulations! You have created your first GUI application! - -## Exercises - -1. We mentioned that `Node`s are the fundamental building blocks of JavaFX and used a `Label` as our root node in the HelloWorld application. - 1. What are some of the other types of `Node`s? - 1. How does JavaFX group them? - -1. `Node`s can be interacted with like Plain Old Java Objects (POJO). - 1. What properties of a `Label` can you change programmatically? - 1. Try changing the `Label` to have a font of Arial at size 50. - -1. You’ve learnt that a `Stage` can be thought of as a window. - 1. Can you have more than one `Stage` an application? - 1. Try creating another stage and showing it! What happens? - --------------------------------------------------------------------------------- -**Authors:** -* Initial Version: Jeffry Lum diff --git a/tutorials/javaFxTutorialPart2.md b/tutorials/javaFxTutorialPart2.md deleted file mode 100644 index f24a0cd6ad..0000000000 --- a/tutorials/javaFxTutorialPart2.md +++ /dev/null @@ -1,158 +0,0 @@ -# JavaFX Tutorial Part 2 - Creating a GUI for Duke - -In this tutorial, we will be creating a GUI for Duke from scratch based on the following mockup. - -![Mockup for Duke](assets/DukeMockup.png) - -## JavaFX controls - -Controls are reusable UI elements. Refer to the [JavaFX's official documentation](https://openjfx.io/javadoc/11/javafx.controls/javafx/scene/control/package-summary.html) for a list of controls available. -From the mockup above, can you identify the controls that we will need to use? - -Mockup | Control ------- | :---: | -![ImageView](assets/MockupImageView.png) | ImageView -![Label](assets/MockupLabel.png) | Label -![Button](assets/MockupButton.png) | Button -![TextField](assets/MockupTextField.png) | TextField -![ScrollPane](assets/MockupScrollPane.png) | ScrollPane - -## Designing the Layout - -Now that we know what controls we need to implement our UI, let’s start programming! We quickly run into a problem: how do we show all of them on the screen at once? - -Each scene is initialized with a root `Node`. In the previous tutorial, our root `Node` was a `Label`. -What happens when we need to display more than one `Node` on the `Scene`? For that, we need to understand the JavaFX hierarchy. Recall from the previous tutorial: - -![Hierarchy of Objects in JavaFX](assets/JavaFxHierarchy.png) - -From the diagram, you see that the root `Node` can contain many other `Nodes` and similarly, each of those `Nodes` can contain many other `Nodes`. This means that if we can find a _container_ to set as our root `Node`, we can place all our other `Nodes` in it. - -But how do we get the exact layout we want in the UI? JavaFX provides that functionality in the form of **layout panes** in `javafx.scene.layouts`. Each layout pane follows a _layout policy_ to decide how to arrange its children. For example, the `VBox` lays out its children in a single vertical column and its counterpart, the `HBox` lays out its children in a single horizontal row. - -:bulb: A comprehensive list of layouts and how they behave is available here from the [official documentation](https://openjfx.io/javadoc/11/javafx.graphics/javafx/scene/layout/package-summary.html). - -One way to obtain the layout in the mockup is as follows. - -![Duke's layout](assets/DukeSceneGraph.png) - -To get that layout, we create a new `AnchorPane` and add our controls to it. Similarly, we create a new `VBox` to hold the contents of the `ScrollPane`. The code should look something like this: - -```java -import javafx.application.Application; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.TextField; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.VBox; -import javafx.stage.Stage; - - -public class Duke extends Application { - - private ScrollPane scrollPane; - private VBox dialogContainer; - private TextField userInput; - private Button sendButton; - private Scene scene; - - public static void main(String[] args) { - // ... - } - - @Override - public void start(Stage stage) { - //Step 1. Setting up required components - - //The container for the content of the chat to scroll. - scrollPane = new ScrollPane(); - dialogContainer = new VBox(); - scrollPane.setContent(dialogContainer); - - userInput = new TextField(); - sendButton = new Button("Send"); - - AnchorPane mainLayout = new AnchorPane(); - mainLayout.getChildren().addAll(scrollPane, userInput, sendButton); - - scene = new Scene(mainLayout); - - stage.setScene(scene); - stage.show(); - - // more code to be added here later - } -} -``` - -Run the application and you should see something like this: - -![Duke's raw layout](assets/RawLayout.png) - -That is not what we were expecting, what did we forget to do? - -## Styling the Controls - -Almost every JavaFX object offer properties that you can set to customize its look and feel. For example, the `Stage` allows you to set its preferred size and title. Again, refer to the official JavaFX documentation for a comprehensive list of properties that you can modify. Here’s how you can get the application to look like the mockup: - -Add the following code to the bottom of the `start` method. You'll have to add `import javafx.scene.layout.Region;` to the imports too. - -```java - @Override - public void start(Stage stage) { - //Step 1. Formatting the window to look as expected. - - //... - - //Step 2. Formatting the window to look as expected - stage.setTitle("Duke"); - stage.setResizable(false); - stage.setMinHeight(600.0); - stage.setMinWidth(400.0); - - mainLayout.setPrefSize(400.0, 600.0); - - scrollPane.setPrefSize(385, 535); - scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS); - - scrollPane.setVvalue(1.0); - scrollPane.setFitToWidth(true); - - // You will need to import `javafx.scene.layout.Region` for this. - dialogContainer.setPrefHeight(Region.USE_COMPUTED_SIZE); - - userInput.setPrefWidth(325.0); - - sendButton.setPrefWidth(55.0); - - AnchorPane.setTopAnchor(scrollPane, 1.0); - - AnchorPane.setBottomAnchor(sendButton, 1.0); - AnchorPane.setRightAnchor(sendButton, 1.0); - - AnchorPane.setLeftAnchor(userInput , 1.0); - AnchorPane.setBottomAnchor(userInput, 1.0); - - // more code to be added here later - } -``` - -Run the application again. It should now look like this: - -![Duke's Final layout](assets/FinalLayout.png) - -## Exercises - -1. In the tutorial, we used an `AnchorPane` to achieve the desired layout. - 1. Can you find other ways to obtain a similar layout? - 1. What are the advantages and disadvantages of your layout? - -1. Try interacting with the application - 1. What happens when you press the `Enter` key or left-click the send button? - 1. Why? - --------------------------------------------------------------------------------- -**Authors:** -* Initial Version: Jeffry Lum diff --git a/tutorials/javaFxTutorialPart3.md b/tutorials/javaFxTutorialPart3.md deleted file mode 100644 index a9e1bdddd3..0000000000 --- a/tutorials/javaFxTutorialPart3.md +++ /dev/null @@ -1,243 +0,0 @@ -# JavaFX Tutorial 3 – Interacting with the user - -Picking up from where we left off last tutorial, we have successfully achieved the desired layout. Now let’s make the application respond to user input. - -Rather than to do everything in one try, let’s iterate and build up towards our final goal. - -## Iteration 1 – Echoing the User - -JavaFX has an _event-driven architecture style_. As such, we programmatically define _handler_ methods to execute as a response to certain _events_. When an event is detected, JavaFX will call the respective handlers. - -For Duke, there are two events that we want to respond to, namely the user pressing `Enter` in the `TextField` and left-clicking the `Button`. These are the `onAction` event for the `TextField` and the `onMouseClicked` event for the `Button`. - -For now, let’s have the application add a new `Label` with the text from the `TextField`. Update the `Main` class as follows. You'll need to add an `import javafx.scene.control.Label;` too. -```java -@Override -public void start(Stage stage) { - // Step 1 code here - - //Step 2 code here - - //Step 3. Add functionality to handle user input. - sendButton.setOnMouseClicked((event) -> { - dialogContainer.getChildren().add(getDialogLabel(userInput.getText())); - userInput.clear(); - }); - - userInput.setOnAction((event) -> { - dialogContainer.getChildren().add(getDialogLabel(userInput.getText())); - userInput.clear(); - }); -} - -/** - * Iteration 1: - * Creates a label with the specified text and adds it to the dialog container. - * @param text String containing text to add - * @return a label with the specified text that has word wrap enabled. - */ -private Label getDialogLabel(String text) { - // You will need to import `javafx.scene.control.Label`. - Label textToAdd = new Label(text); - textToAdd.setWrapText(true); - - return textToAdd; -} -``` - -Run the program and give it a whirl! - -![Echo not scrolling as intended](assets/EchoNotScrolling.png) - -At first glance everything appears to work perfectly. However, when the `VBox` stretches beyond the confines of the `ScrollPane`, the `ScrollPane` does not scroll down automatically as expected. We can remedy this by attaching a handler on the `VBox` to react to its own size changing and scrolling the `ScrollPane` down. - -Update the `start` method as shown below. - -```java -public void start(Stage stage) { - // current code ... - - //Scroll down to the end every time dialogContainer's height changes. - dialogContainer.heightProperty().addListener((observable) -> scrollPane.setVvalue(1.0)); -} -``` - -Verify that the `ScrollPane` scrolls as intended. - -## Iteration 2 – Adding Dialog Boxes - -In the mockup of the UI, notice that the dialog boxes are composed of two different controls (`ImageView` and `Label`) and reused multiple times. In situations like this, it is often beneficial to create our own custom control. - -Let’s create our custom control `DialogBox`: -```java -import javafx.geometry.Pos; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; - -public class DialogBox extends HBox { - - private Label text; - private ImageView displayPicture; - - public DialogBox(Label l, ImageView iv) { - text = l; - displayPicture = iv; - - text.setWrapText(true); - displayPicture.setFitWidth(100.0); - displayPicture.setFitHeight(100.0); - - this.setAlignment(Pos.TOP_RIGHT); - this.getChildren().addAll(text, displayPicture); - } -} -``` - -We use the code in our main class just like any other control. Here are the steps to update the code to use the custom control in `Main.java`. - -First, add these imports: -```java -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -``` - -Next, add two images to the `main/resources/images` folder. -For this tutorial, we have two images `DaUser.png` and `DaDuke.png` to represent the user avatar and Duke's avatar respectively but you can use any image you want. - -Image|Filename ----|--- -![DaDuke](assets/DaUser.png) | `DaUser.png` -![DaUser](assets/DaDuke.png) | `DaDuke.png` - - -```java -public class Duke extends Application { - // ... - private Image user = new Image(this.getClass().getResourceAsStream("/images/DaUser.png")); - private Image duke = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png")); - // ... -} -``` - -Add a new method to handle user input: -```java -/** - * Iteration 2: - * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to - * the dialog container. Clears the user input after processing. - */ -private void handleUserInput() { - Label userText = new Label(userInput.getText()); - Label dukeText = new Label(getResponse(userInput.getText())); - dialogContainer.getChildren().addAll( - new DialogBox(userText, new ImageView(user)), - new DialogBox(dukeText, new ImageView(duke)) - ); - userInput.clear(); -} - -/** - * You should have your own function to generate a response to user input. - * Replace this stub with your completed method. - */ -private String getResponse(String input) { - return "Duke heard: " + input; -} -``` - -Update the event handler code in the `start` method to use the new `handleUserInput` method: -```java - -@Override -public void start(Stage stage) { - //... - - //Part 3. Add functionality to handle user input. - sendButton.setOnMouseClicked((event) -> { - handleUserInput(); - }); - - userInput.setOnAction((event) -> { - handleUserInput(); - }); -} -``` - -Run the program and see how it works. - -![DialogBoxes Iteration 2](assets/DialogBoxesIteration2.png) - -## Iteration 3 – Adding custom behavior to DialogBox - -One additional benefit of defining a custom control is that we can add behavior specific to our `DialogBox`. Let’s add a method to flip a dialog box such that the image on the left to differentiate between user input and Duke’s output. - -```java -/** - * Flips the dialog box such that the ImageView is on the left and text on the right. - */ -private void flip() { - this.setAlignment(Pos.TOP_LEFT); - ObservableList tmp = FXCollections.observableArrayList(this.getChildren()); - FXCollections.reverse(tmp); - this.getChildren().setAll(tmp); -} - -public static DialogBox getUserDialog(Label l, ImageView iv) { - return new DialogBox(l, iv); -} - -public static DialogBox getDukeDialog(Label l, ImageView iv) { - var db = new DialogBox(l, iv); - db.flip(); - return db; -} -``` - -You'll need to update the imports as follows: -```java -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; -``` - -Now, we can go back to the `Main` class and change the event handler to use our new `DialogBox`. - -```java -private void handleUserInput() { - Label userText = new Label(userInput.getText()); - Label dukeText = new Label(getResponse(userInput.getText())); - dialogContainer.getChildren().addAll( - DialogBox.getUserDialog(userText, new ImageView(user)), - DialogBox.getDukeDialog(dukeText, new ImageView(duke)) - ); - userInput.clear(); -} -``` - -Run the application and play around with it. - -![DialogBoxes Iteration 3](assets/DialogBoxesIteration3.png) - -Congratulations! -You have successfully implemented a fully functional GUI for Duke! - -## Exercises - -1. While the GUI looks similar to the mockup, there are still parts that need to be refined. Try your hand at some of these tasks: - * Add padding between each DialogBox - * Add padding between each ImageView and its Label - * Clip the ImageView into a circle - * Add background color to each dialog box - -1. After attempting the changes, reflect critically on the following: - * What was the development workflow like? - * Is the code base well-organized? - --------------------------------------------------------------------------------- -**Authors:** -* Initial Version: Jeffry Lum diff --git a/tutorials/javaFxTutorialPart4.md b/tutorials/javaFxTutorialPart4.md deleted file mode 100644 index 616d308f07..0000000000 --- a/tutorials/javaFxTutorialPart4.md +++ /dev/null @@ -1,293 +0,0 @@ -# JavaFX Tutorial 4 – FXML - -While we have produced a fully functional prototype, there are a few major problems with our application. - -1. The process of visually enhancing the GUI is long and painful: - * Does the `TextField` need to be 330px or 325px wide? - * How much padding is enough padding to look good? - - Every small change requires us to rebuild and run the application. - -1. Components are heavily dependent on each other: - Why does `Main` need to know that `DialogBox` needs a `Label`? - What happens if we change the `Label` to a custom `ColoredLabel` in the future? - - We need to minimize the amount of information each control needs to know about another. - Otherwise, making changes in the future will break existing features. - -1. The code is untidy and long: - Why is all the code in one place? - - The `Main` class attempts to do it all. - Code for visual tweaks, listeners and even utility methods are all in one file. - This makes it difficult to find and make changes to existing code. - -FXML is a XML-based language that allows us to define our user interface. Properties of JavaFX objects can be defined in the FXML file. For example: -```xml - -``` - -The FXML snippet define a TextField similar to the one that we programmatically defined previous in Tutorial 2. Notice how concise FXML is compared to the plain Java version. - -Let's return to Duke and convert it to use FXML instead. - -# Rebuilding the Scene using FXML - -Scene Builder is a tool developed by Oracle and currently maintained by Gluon. It is a What-You-See-Is-What-You-Get GUI creation tool. [Download](https://gluonhq.com/products/scene-builder/#download) the appropriate version for your OS and install it. - -Create the following files in `src/main/resources/view`: - -**MainWindow.fxml** -```xml - - - - - - - - - - - -