Javafx Notes
Javafx Notes
Set up
- Download JavaFX: https://gluonhq.com/products/javafx/
@Override
public void start(Stage stage) throws Exception{ //overridden from the Application class
/* Stage
- first layer.
- Stage = the window.
- you can use the stage in the parameter above or create a new stage: Stage stage = new Stage();
*/
- The root node: arrange all the components.
- There are different types of root nodes.
- Basic type of root nodes is: Group.
*/
Group root = new Group();
Scene scene = new Scene(root, 600, 600, Color.BLACK); //create the scene, set the width and Hight, set the background
color
stage.setTitle("Let's go");
//add an icon:
Image icon = new Image("s.png"); //first create an image
stage.getIcons().add(icon); //add the icon
stage.setHeight(420);
stage.setWidth(420);
stage.setResizable(false); //the size now is fixed you can not resize it when the program is running
//set where the stage will appear on the computer screen: (javaFX normally set the stage in the middle)
stage.setX(50); stage.setY(50);
stage.setFullScreen(true); //then to exit the full screen when the app is running you hit esc or you can change that:
stage.setFullScreenExitHint("to exit press b");
stage.setFullScreenExitKeyCombination(KeyCombination.valueOf("b"));
Text
@Override
public void start(Stage stage) throws Exception{ //overridden from the Application class
Group root = new Group();
Scene scene = new Scene(root);
//Add a text:
Text text = new Text("gd"); //you can put in the argument the text or use setText method
text.setText("gd");
text.setFont(Font.font("Carlito",50)); //set the font and size
text.setFill(Color.GRAY); //set the text color
//Because you are using Group nodes then you need manually to place the text in the window:
text.setX(50); text.setY(50);
//now add the text to the root as a node:
root.getChildren().add(text);
stage.setScene(scene);
stage.show();
} //start method ends
Line
@Override
public void start(Stage stage) throws Exception{ //overridden from the Application class
Group root = new Group();
Scene scene = new Scene(root);
- Note: to create FXML file: right click on the package new New FXML
Document Next Enter the name (should be the same as the class of the
scene) Finish.
- Open the SceneBuilder: Right click on the FXML file Open in SceneBuilder.
- In the left of the SceneBuilder you have library which have items you can use,
and hierarchy which has the items you are using.
- Now you can hold AnchorPane from the library and drop it in the middle of
the screen, you can also resize it by holding the lower left corner.
- Note: To check if everything is added successfully you can go to the fxml file
and check.
- Now you need to use this line to create the Root node and link it with the
fxml file:
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); //the argument is the name of the FXML file
The code:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
@Override
public void start(Stage stage) throws Exception{ //overridden from the Application class
//To create the root node and to link it to the FXML file:
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); //the argument is the name of the FXML file
stage.setScene(new Scene(root));
stage.show();
} //start method ends
} //class ends
Event Handling using SceneBuilder:
- Each Event should have a method. You can create a class named controller to put the
methods inside it.
- Put in the controller class: @FXML , if u have an element in the scene
builder, this will use the FXMLLoader that exists in the start method as a
connecter between the FXML file and the controller class, to connect all the
elements found in the FXML file with the code for them in the controller
class.
- Note: the names of the elements in the fxml file or the scenebuilder should
be the same as the controller class.
Exercise:
- The project is to put a circle in the middle and four buttons, when you press a
button, the shape moves to one of the directions:
1. Add AnchorPane.
2. Add 4 buttons. The properties of the button can be changed by clicking on
the button then in the right of the screen click on properties then you can
change the button properties.
3. Add a circle.
4. Now in the Controller class, create an event handler method (should have a
void return and the parameter empty or a variable of ActionEvent class) for
each button and code inside it to move the circle.
-Note:use ActionEvent, if u want to add coding when the button is being clicked,
otherwise, the button will work normally without a method.
5. Then create a variable of Circle type and two variables for coordinates.
6. In the Controller menu in SceneBuilder, choose the controller class.
7. Connect the circle in the scenebuilder: press on the circle then go the Code
menu in the right of the screen then in the fx:id write the name of the
Circle variable you coded.
8. To connect each button with its own method: press on the button then go
to code menu in the right of the screen then On Action choice and then
select the method for each button.
- The code:
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.shape.Circle;
public class Controller {
@FXML
Exercise:
- Add a pane and add two labels inside it, give the labels text and ID.
- write a css style:
.root{
-fx-background-color:"black";
}
.label{
-fx-font-size: 20;
-fx-font-family: "Lucida Console";
-fx-text-fill: "white";
-fx-alignment:center; /* will center the labels inside their boxes, so make the box of the label from the right to left*/
}
#one{
-fx-font-size: 40;
}
FX CSS Properties:
- https://wheelercode.wordpress.com/javafx-css-properties-selectors-list/
- https://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html
Switch scenes
- Each scene needs an fxml file (because it has its own scenebuilder).
- In the FXMLLoader put the path of the fxml file for the scene that
will open first.
- This block of code for an event handler of a button that if you press
it will go to another scene:
public void switchToScene1(ActionEvent e) throws IOException {
root = FXMLLoader.load(getClass().getResource("scene1.fxml"));
/*
1- get the source of the event (button).
2- cast it to a Node type: the event only knows its source is some kind of object, however,
we registered this listener with a button, which is a Node, so we know
the actual runtime type of the source must be Button (which is a Node)
So tell the compiler we are confident we can treat this as a Node.
3- get the Scene of the node (i.e. containing the button).
4- get the window of the scene
5- cast it to a Stage type: Again, the Scene only knows it is in a Window, but we know we specifically
put it in a stage. So we can downcast the Window to a Stage.
*/
stage = (Stage)((Node)e.getSource()).getScene().getWindow(); //to make the stage variable has the value of the stage which contains the button
scene = new Scene(root);
stage.setScene(scene);
}
Exercise: Create two scenes and each scene has a button to switch to
the another one:
- Create a controller class and code in it two event handler methods
to switch the scene when pressing a button.
- Create two fxml files for two scenes, and in each one add a button
that will take you to another scene.
- Connect the controller class with each scenebuilder and connect the
methods with the buttons.
- The code:
package sample;
import java.io.IOException;
/*
1- get the source of the event.
2- cast it to a Node type: the event only knows its source is some kind of object, however,
we registered this listener with a button, which is a Node, so we know
the actual runtime type of the source must be Button (which is a Node)
So tell the compiler we are confident we can treat this as a Node.
3- get the Scene of the node (i.e. containing the button).
4- get the window of the scene
5- cast it to a Stage type: Again, the Scene only knows it is in a Window, but we know we specifically
put it in a stage. So we can downcast the Window to a Stage.
*/
stage = (Stage)((Node)e.getSource()).getScene().getWindow(); //to make the stage variable has the value of the stage which contains the button
scene = new Scene(root);
stage.setScene(scene);
}
}
Communication between Controllers
- Each scene has an fxml and a controller.
Exercise: Create two scenes, one scene for the user to enter the
name and another one to welcome by the name:
- Create a controller class for scene one and code in it an event
handler method to login.
- Create a controller class for scene two and code in it a method to
set the label to show hello and the name entered.
- Create two fxml files for two scenes, in the first one add a label and
textfield and button, in the second one add a label.
- Connect the controller classes with each scenebuilder and connect
the method login with the button and give the labels and the textfield
and the button the same ID as in the coding.
- The code:
package sample;
import com.sun.javafx.scene.SceneEventDispatcher;
import javafx.event.ActionEvent;
import javafx.fxml.FXML; package sample;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node; import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage; public class ControllerSceneTwo {
@FXML
import java.io.IOException; Label HelloUsername;
ControllerSceneTwo controllerSceneTwo =
loader.getController(); //an instance of controller for scene2 to
access display method
controllerSceneTwo.DisplayUserName(username);
}
Logout button
- Add a pane and give it an id.
- Add a button give it a name “logout”, give it an id and a on action
method.
- Set the controller.
- The code:
public class Controller {
@FXML
private Button logoutButton;
@FXML
private AnchorPane scenePane; //a pane needs a separate FXML notation.
private Stage stage;
}
}
stage.setOnCloseRequest(event -> {
event.consume(); //if you hit the cancel button in the alert then it will not close the program.
logout(stage);
});
}
ImageView: is a node used for painting images loaded with images,
image = photograph, ImageView= picture frame.
@FXML
ImageView imageView;
Button change;
Exercise: Create an age app, A textfield to enter the age and a label
to show the user if he made a mistake and change the label text,
and another label saying enter the age, and a button to submit.
}
}
CheckBox
Exercise: make a checkbox and a label, when the checkbox is pressed
the label is on.
- CheckBox: -ID –onAction
- Label: -ID
- Code:
public class Controller {
@FXML
private CheckBox CBOffOn;
@FXML
private Label labelOffOn;
DatePicker
Exercise: select a date and then show it on the label.
-DatePicker: -ID - onAction.
-Label: -ID.
-Code:
public class Controller {
@FXML
private Label label;
@FXML
private DatePicker datepicker;
ChoiceBox
Exercise: Select an item and show it on the label.
-ChoiceBox: -ID. Note: if there is no onAction then u need to implements initializable interface for the controller class.
-Label: -ID.
-Code:
public class Controller implements Initializable { //because the ChoiceBox doesn't have onAction method, so u implements this interface
@FXML
private Label label;
@FXML
private ChoiceBox<String> choiceBox;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) { //this method will override when u implements Initializable interface
and it will be invoked automatically.
choiceBox.getItems().addAll(food);
choiceBox.setOnAction(this::changeLabel);
}
-Code: @FXML
private Label label;
@FXML
private Slider slider;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) { //this method will override when u implements Initializable interface
//for the initial label to be set as the initial value of the slider:
temp =(int) slider.getValue();
label.setText(Integer.toString(temp));
slider.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observableValue, Number number, Number t1) {
temp =(int) slider.getValue();
label.setText(Integer.toString(temp));
}
});
}
}
ProgressBar
Exercise: press a button to increase the progressbar and to set the
percentage of completion of the progressbar on a label.
-ProgressBar: -ID.
-Button: -ID –onAction.
-Label: -ID.
-Code:
public class Controller implements Initializable { //because the ChoiceBox doesn't have onAction method, so u implements this interface
@FXML private Label label;
@FXML private ProgressBar progressBar;
@FXML private Button button;
private BigDecimal temp = new BigDecimal(String.format("%.2f",0.0)); //to hold the current progress, BigDecimal class gives control over rounding
behaviour.
@Override
public void initialize(URL url, ResourceBundle resourceBundle) { //this method will override when u implements Initializable interface
progressBar.setStyle("-fx-accent: red;"); //css property
}
public void press(){ //to increase the progressbar 10% when pressing a button
if (temp.doubleValue()<1){ //if the progressbar is not completed
temp = new BigDecimal(String.format("%.2f",temp.doubleValue()+0.1));; //0.1 = 10%
progressBar.setProgress(temp.doubleValue());
label.setText((int)(temp.doubleValue()*100)+"%"); //to set the percentage as an integer instead of double.
}
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle) { //this method will override when u implements
Initializable interface
/*
to use the spinner write this line of code:
- .IntegerSpinnerValueFactory coz this time it is for integers.
- in the parameters write the minimum and maximum values that can choose from the spinner
*/
SpinnerValueFactory<Integer> valueFactory = new SpinnerValueFactory.IntegerSpinnerValueFactory(1,10);
valueFactory.setValue(1); //the default value
spinner.setValueFactory(valueFactory);
spinner.valueProperty().addListener(new ChangeListener<Integer>() { //to change the value of spinner when
changing the value of spinnerValueFactory
@Override
public void changed(ObservableValue<? extends Integer> observableValue, Integer integer, Integer t1) {
label.setText(Integer.toString(spinner.getValue()));
}
});
}
}
ListView: list of items
Exercise: press the item on the list and show the item on the label.
-ListView: -ID.
-Label: -ID.
-Code:
public class Controller implements Initializable { //because the ChoiceBox doesn't have onAction method, so u implements this interface
@FXML private Label label;
@FXML private ListView<String> listView;
private String[] food= {"one","two","three"};
@Override
public void initialize(URL url, ResourceBundle resourceBundle) { //this method will override when u implements Initializable interface
listView.getItems().addAll(food); //add the items to the listview
listView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() { //to know which items is selceted
@Override
public void changed(ObservableValue<? extends String> observableValue, String s, String t1) {
label.setText(listView.getSelectionModel().getSelectedItem());
}
});
}
TreeItem<String> rootItem = new TreeItem<>("Files", new ImageView(new Image("Files_icon.png"))); //to add an icon to the file
treeView.setRoot(rootItem);
rootItem.getChildren().addAll(branchItem,branchItem1,branchItem2);
if(item!=null){
System.out.println(item.getValue());
}
}
}
MenuBar
Exercise: Create a menu bar within it there are menu which has an
items.
-MenuBar: .
-Menu: add in the MenuBar.
-MenuItem: -onAction –Accelerator (to create a shortcut for it) - add
in the menu.
-SeparatorMenuItem: a line can be added in the menu to separate
between menu items.
-CheckMenuItem: can be toggle between check and not checked
and its added in the menu.
-RadioMenuItem (create two): -Toggle Group -can be only one
selected from the toggle group, added in the menu.
-Code:
public class Controller {
@Override
public void start(Stage stage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("scene.fxml"));
Parent root = loader.load(); //this will load the object hierarchy from the FXML document.
Controller controller = loader.getController(); //to access the controller class.
Scene scene = new Scene(root);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() { //u can use this anonymoys EventHandler or a lambda expression inside the setOnKeyPressed method to do this
@Override
public void handle(KeyEvent keyEvent) {
switch (keyEvent.getCode()){
case UP: controller.moving(); break;
default: System.out.println(keyEvent.getCode()); break; //it will print the key you are pressing.
}
}
});
stage.setScene(scene);
stage.show();
}
Animations
Exercise: make some animations to a photo or a shape.
-ImageView: -Image –ID.
-Code:
public class Controller implements Initializable {
@FXML private ImageView image;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
//translate:
/*
TranslateTransition translate = new TranslateTransition(); //Allow u to move the image on the X and Y axis
translate.setNode(image);
translate.setDuration(Duration.seconds(1)); // to take a second in moving, not so fast.
translate.setCycleCount(TranslateTransition.INDEFINITE); //to do it non-stop, or if u want specific number, then u can write it.
translate.setByX(250); //to move to the right 250 pixels
translate.setByY(-250); //to move to the up 250 pixels
translate.setAutoReverse(true); //to reverse when u get to the end of the transition
translate.play(); //to go
*/
//rotate:
/*
RotateTransition rotate = new RotateTransition(); //Allow u to move the image on the X and Y axis
rotate.setNode(image);
rotate.setDuration(Duration.seconds(1)); // to take a second in moving, not so fast.
rotate.setCycleCount(TranslateTransition.INDEFINITE); //to do it non-stop, or if u want specific number, then u can write it.
rotate.setInterpolator(Interpolator.LINEAR); //to not stop for a little while when it ends
rotate.setByAngle(360);
rotate.setAxis(Rotate.X_AXIS); //set which axis to rotate on, by default it is on the Z
rotate.play(); //to go
*/
//fade:
/*
FadeTransition fade = new FadeTransition(); //Allow u to move the image on the X and Y axis
fade.setNode(image);
fade.setDuration(Duration.seconds(1)); // to take a second in moving, not so fast.
fade.setCycleCount(TranslateTransition.INDEFINITE); //to do it non-stop, or if u want specific number, then u can write it.
fade.setInterpolator(Interpolator.LINEAR); //to not stop for a little while when it ends
fade.setFromValue(1); //can be any number from one to zero
fade.setToValue(0); //can be any number from one to zero
fade.play(); //to go
*/
//Scale:
ScaleTransition scale = new ScaleTransition(); //Allow u to move the image on the X and Y axis
scale.setNode(image);
scale.setDuration(Duration.seconds(1)); // to take a second in moving, not so fast.
scale.setCycleCount(TranslateTransition.INDEFINITE); //to do it non-stop, or if u want specific number, then u can write it.
scale.setInterpolator(Interpolator.LINEAR); //to not stop for a little while when it ends
scale.setByX(2);
scale.setAutoReverse(true);
scale.play(); //to go
}
}
MediaView
Exercise: create a simple video player with three buttons to play and
reset and pause the video.
-MediaView: -ID –Fit Width –Fit Hight.
- Button (3 buttons: play, pause, reset): -ID –onAction (each button
has different method).
- Note: u have to add to the VM Options in the Run then Edit Configuration
then add this line: --add-modules javafx.controls,javafx.media
-Code:
public class Controller implements Initializable {
@FXML private MediaView mediaView;
@FXML private Button play,pause,reset;
private File file;
private Media media;
private MediaPlayer mediaPlayer;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
file = new File("C:\\Users\\hp\\Desktop\\video.mp4");
media = new Media(file.toURI().toString()); //this has info about the file.
mediaPlayer = new MediaPlayer(media);//provide to play media
mediaView.setMediaPlayer(mediaPlayer); //to view the video
}
@FXML private WebView webView; //will display the content of a web engine.
@FXML private TextField textField;
@FXML private WebEngine engine;
private WebHistory webHistory;
private String homePage; //the first page open in the engine
private double webZoom;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
engine = webView.getEngine();
homePage = "www.google.com";
textField.setText(homePage);
webZoom=1;
loadPage();
}
public void executeJS(){ //to take u to a specific page, through some javascript code
engine.executeScript("window.location = \"https://www.youtube.com\";"); //this is a Javascript code, can be executed if written inside this executeScript method
}
}
Exercise: Create MP3 player.
-AnchorPane: -ID -Style (-fx-background-color Grey).
-Label (to hold the name of the current song): -ID.
-ProgressBar: -ID.
-Button (play): -ID -onAction.
-Button (pause): -ID -onAction.
-Button (reset): -ID -onAction.
-Button (previous): -ID -onAction.
-Button (next): -ID -onAction.
-ComboBox (drop menu, to change the speed of the song): -ID –onAction.
-Slider (for the volume): -ID –MAX (200) –Value (100).
-Connect the controller class.
-The view:
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import java.io.File;
import java.net.URL;
import java.util.*;
private File music; //to hold the directory of the music folder
private File[] files; //to hold each song
private ArrayList<File> songs; //this is like a playlist
import javafx.fxml.FXMLLoader; private Timer timer; //keep track of the progress bar to be updated
private TimerTask timerTask;
import javafx.scene.Parent; private Boolean running; //if the player is playing a song
files = music.listFiles(); // listFiles method will get all the files in the directory
public class Main extends Application { if(files!=null)
songs.addAll(Arrays.asList(files));
song_name.setText(songs.get(songNumber).getName()); //to set the label as the name of the song playing
speed_box.setOnAction(this::speed);
Parent root = FXMLLoader.load(getClass().getResource("ss.fxml")); //the volume slider:
Scene scene = new Scene(root); slider.valueProperty().addListener(new ChangeListener<Number>() {
@Override
stage.setScene(scene); public void changed(ObservableValue<? extends Number> observableValue, Number number, Number t1) {
mediaPlayer.setVolume(slider.getValue()*0.01);
}
stage.show(); });
} }
progress_bar.setStyle("-fx-accent: #00FF00;"); //change the color of the progressbar
mediaPlayer.stop();
if(running)
cancelTimer();
song_name.setText(songs.get(songNumber).getName());
play();
}
else { //if u reach the first song, to go to the last one
songNumber=songs.size()-1;
mediaPlayer.stop();
if(running)
cancelTimer();
song_name.setText(songs.get(songNumber).getName());
play();
}
}
public void next(){
if(songNumber<songs.size()-1){ //means it is not the last song
songNumber++;
mediaPlayer.stop();
if(running)
cancelTimer();
song_name.setText(songs.get(songNumber).getName());
play();
}
else { //if u reach the last song, to go back to the first one
songNumber=0;
mediaPlayer.stop();
if(running)
cancelTimer();
song_name.setText(songs.get(songNumber).getName());
play();
}
}
public void speed(ActionEvent event){
if(speed_box.getValue()==null){
mediaPlayer.setRate(1);
}else {
mediaPlayer.setRate(Integer.parseInt(speed_box.getValue().substring(0,speed_box.getValue().length()-1))*0.01); //note: substring to take out the % sign
}
}
public void beginTimer(){
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
running=true;
double current = mediaPlayer.getCurrentTime().toSeconds(); //current of the song
double end = media.getDuration().toSeconds(); //end of the song
progress_bar.setProgress(current/end);
if(current/end ==1){
cancelTimer();
}
}
};
timer.scheduleAtFixedRate(timerTask,0,1000); //1000 = 1 sec, it means repeat the timerTask every one sec and the delay is o
}
public void cancelTimer(){
running=false;
timer.cancel();
}
} //end class