Monday, May 19, 2014

Decorating a Stage in JavaFX

We need a start to build our UI. The top most level container is the stage. It will contain your window utility buttons like close, minimize, restore. It forms the basis of the start of your layout. After a stage has been created, you put a scene over it. 

Creating a stage is simple. You do not create it, but the javafx engine will do it for you. This is the main stage which is created for you on the main javafx thread. You can have multiple stages in an application after the first one and these can be created by you.

A simple code to show how you use the default stage.

public void start(Stage stage) throws Exception {
      stage.setWidth(1024);
      stage.setHeight(768);
      stage.setTitle("First");
      stage.show();
 }


This simply displays a window with the given dimensions and title when run. Now, this is the simplest form of a stage. I state this because this is the default stage javafx creates. 

 

Looking at the window that is created above, we observe that this has all the functions of a window. It can be closed, minimized, dragged, restored etc
Although, we should be happy by this, what we are getting here is a full featured window with minimum lines of code for us. Still, there are situations that call for different requirements. 
Let's say we wanted to create our own design or we do not want the window to be dragged by the users. The requirements are endless. Thankfully, a lot was thought about these and hence we have been given certain ways of doing the same.

A very simple property of the stage is "style". This will control how your stage will appear once you apply the same. 

You can apply these using 
stage.initStyle(StageStyle.DECORATED);

1. StageStyle.DECORATED
    The default style with all the functions available.


2. StageStyle.UNDECORATED
    A stage with a solid white background and no decorations.  

3. StageStyle.TRANSPARENT
    A stage with a transparent background and no decorations.

4. StageStyle.UTILITY
    A stage with a solid white background and minimal platform decorations.

Out of the above Utility will only have a closing button. Undecorated and transparent as mentioned are very self explanatory. However, I do see much of a difference between the two and hence I always use undecorated if required. 
 
Sometimes, we need an app to be full screen. Javafx also provides this functionality. 
stage.setFullScreen(true);
stage.setFullScreenExitHint("Press Exc to exit full screen");


Stage can be lot fun. All, we need is to start working on it and exploring it's capabilities.

Sunday, July 7, 2013

Create a Notepad with Javafx2 - Accelerators and MnemonicParsing

Our Notepad is sufficient with functionalities we have added. But I can still feel there is something missing. Something that we should add to our notepad to make it complete. What about adding the Mnemonics? What if our user presses the combination of ALT button and a specified Key and the File menu opens up automatically. Yes, this is definitely required. 

How to achieve this? Is is complicated? Well, no. As a matter of fact this is very easy. Open you notepad.fxml and update the following.

<Menu text="_File" fx:id="menufile" mnemonicParsing="true">
<Menu text="_Edit" mnemonicParsing="true">
<Menu text="F_ormat" mnemonicParsing="true">
<Menu text="_View" mnemonicParsing="true">
<Menu text="_Help" mnemonicParsing="true">

Looks pretty simple right? All that you have to do is add mnemonicParsing="true" wherever required. Now, for the key that you would want to associate with the ALT key all that you have to do is put an  "_" before that letter in your Menu text as shown above. For example if you want your File Menu to be opened up when you press ALT + F then change the text for File Menu from "File" to "_File". If you want Format Menu to be opened on ALT+O then change "Format" to "F_ormat".
That's it. The Mnemonics have been set. Now, run your application and test.

While the Mnemonics have been set and are paying a very important user friendly activity for us, but we still need a little more than this. There are some additional features that a notepad should have for its full usage. What are these? Lets say you are typing on the notepad and you feel like saving your work. Normally you'll do a Ctrl+S and it works for you. But here we have not provided anything that helps with this. Lets try and add this feature to our notepad as well. Now this may sound tricky but trust me it's not. This can easily be achieved through Accelerators. 

Let's start with this. Open your fxml file. Now, wherever you want an accelerator defined update you code as shown below.

<MenuItem fx:id="newItem" text="New" onAction="#newFile"></MenuItem>

All you are doing here is adding an ID to your Menu Item.

Now open you controller class and update it so that it implements the "javafx.fxml.Initializable" interface. The method that you'll have to implement would be 

@Override
public void initialize(URL location, ResourceBundle resources) {


}

Simple. This is called before the fxml is loaded and hence used to initialize your screen. 

Now add a global parameter that defines the menu item you have given ID's to.
@FXML
private MenuItem newItem; 

So far so good. Now you have got the reference of your MenuItem. For me it is the New MenuItem in FileMenu.

Now,  add the following code in your initialize method.

KeyCombination kc = new KeyCodeCombination(KeyCode.N,
KeyCombination.CONTROL_DOWN);

newItem.setAccelerator(kc);


The above code declares a KeyCombination class. Here you define the key combinations. In the example above you have added Ctrl + N as Key Combination. next you add the combination as an accelerator to the menuitem   instance. 

That's it. Now Ctrl +N will also call the onAction method defined on New Menu Item. 

Your shortcut is ready. These definitely are a lot helpful in using your applications and hence should be used wherever you can.  

Notepad is finished. There were a lot of things that could have been done here but I did not because it was not worth discussing here. For example, adding  a message box when you press New in File Menu asking the user if he actually wants to save his work or not. I did not add the functionality of any other Menu like Edit. Trust me these are essentials for out application but need not be discussed here. The motive here was to examine the ease with which the applications like notepad be developed using JavaFX. 

If you want to visit my prev blogs on notepad, please click on the links below.
Create a Notepad with Javafx2 - Building the Logic
Create a Notepad with Javafx2 - Styling
Create a Notepad with Javafx2 - The Layout

Saturday, July 6, 2013

Create a Notepad with Javafx2 - Building the Logic

Notepad is a simple application. I am trying to demonstrate how easy creating the logic could be, by using Javafx2. The previous two blogs helped us in creating the layout and styling the notepad
In this blog we will try to create the logic for our notepad to work. This would deal with adding functionalities that would be triggered for specific needs.

Lets start by adding the methods for File Menu.

This is simple. Open your notepad.fxml and update the File Menu code as under.

<items>
<MenuItem fx:id="newItem" text="New" onAction="#newFile"></MenuItem>
<MenuItem text="Open..." onAction="#openFile"></MenuItem>
<MenuItem text="Save" onAction="#saveFile"></MenuItem>
<MenuItem text="Save As..." onAction="#saveasFile"></MenuItem>
<SeparatorMenuItem></SeparatorMenuItem>
<MenuItem text="Page Setup..."></MenuItem>
<MenuItem text="Print"></MenuItem>
<SeparatorMenuItem></SeparatorMenuItem>
<MenuItem text="Exit" onAction="#exitApp"></MenuItem>
</items>

onAction defines the methods that would be called when you click on the respective Items.
These methods will be defined in the controller of the fxml. Defining a controller is simple. Add this to the place you defined BorderPane.

<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="NotepadController">

Easy, the fully qualified name of the class is defined here. Next, create a controller class with the name and package matching the fully qualified class name you have given above. Now that you have the controller created, add the methods defined above to your class.

import java.net.URL;
import java.util.ResourceBundle;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;

public class NotepadController{

@FXML
protected void newFile(ActionEvent event) {
System.out.println("new File");
}
@FXML
protected void openFile(ActionEvent event) {
System.out.println("Open file");
}
@FXML
protected void saveFile(ActionEvent event) {
System.out.println("Save File");
}
@FXML
protected void saveasFile(ActionEvent event) {
System.out.println("Save File As");
}
@FXML
protected void exitApp(ActionEvent event) {
System.out.println("Exiting");
}

}

The code above is very simple. It is just a class with methods defined. Observe the signatures of the method. This is the only thing to be noted down. Now your controller is ready. Lets start adding the functionality.

I start by adding the close event. 
Add a close Application code in the exit Event. Just update your code as shown below.

@FXML
protected void exitApp(ActionEvent event) {
Platform.exit();
}

Run your App and test exit event.  It should close the application as expected.

Now, lets add the new Functionality. When a user clicks on new the TextArea should be refreshed. This should be simple as well. All you need is a reference of the textArea in your controller. This is done in two steps.
1. Add an ID to textarea in your fxml file

<center>
<TextArea fx:id="textpane">
</TextArea>
</center>
2. declare ID in controller
@FXML
private TextArea textpane;

Now, that you have the reference of textarea add the desired functionality.

@FXML
protected void newFile(ActionEvent event) {
textpane.clear();
}

This was simple. Now lets start building the notepad.
First we start with the new File functionality.

@FXML
protected void newFile(ActionEvent event) {
textpane.clear();
Stage stage = (Stage) textpane.getScene().getWindow();
stage.setTitle("Untitled - Notepad");
file = null;
}

We have also defined two global parameters.

private FileChooser fileChooser = new FileChooser();
private File file;

The code is extremely simple. we cleared off the textarea. Then we changed the name of the window title. Third the file parameter was changed to null.

The code for Opening a file.

@FXML
protected void openFile(ActionEvent event) {
file = fileChooser.showOpenDialog(null);
if (file != null) {
Stage stage = (Stage) textpane.getScene().getWindow();
stage.setTitle(file.getName() + " - Notepad");
BufferedReader br = null;
try {
String sCurrentLine;
br = new BufferedReader(new FileReader(file));
while ((sCurrentLine = br.readLine()) != null) {
textpane.appendText(sCurrentLine + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

It is simple, open a file using a jfilechooser. Traverse it and append the same in the textpane. 

The code for saving a file 

@FXML
protected void saveFile(ActionEvent event) {
String content = textpane.getText();
if (file != null) {
try {
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
} else {
// open a file dialog box
file = fileChooser.showSaveDialog(null);
if (file != null) {
Stage stage = (Stage) textpane.getScene().getWindow();
stage.setTitle(file.getName() + " - Notepad");
try {
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

@FXML
protected void saveasFile(ActionEvent event) {
file = fileChooser.showSaveDialog(null);

String content = textpane.getText();
if (file != null) {
Stage stage = (Stage) textpane.getScene().getWindow();
stage.setTitle(file.getName() + " - Notepad");
try {
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}


The code for saving files is redundant and can be further optimized. But that is not the motive here. You can correct the code as you like. There can be many ways of doing the same thing and I don't deny that, but, keeping it simple is easier to understand.
The above code is not complicated as it may look, thanks to the formatting etc. readily available for usage here, all that is relevant here is setting the stage title and extracting the file information from the user. There are two important things for us how we get the stage from any element and the dialog boxes that we have on save and open. 

This completes our File menu related functionality for the notepad except for the print related tasks. I tried looking for JavaFX printing support but could not find one. This is still to be released in future editions. Though, we have alternatives for this but that goes beyond scope.

We know now how simple creating logic can be using JavaFX.
Apart from this lets move to other stuffs in the next and the final blog. Let us explore how Accelerators and Mnemonics be used.


Create a Notepad with Javafx2 - Styling

We created the layout of the notepad in the previous blog. We got a default look and feel of the application we are trying to create. Surely, we will need much more than that to impress ourselves with the capability of Javafx2. How did we style in Swing Applications? Or AWT's ? One of the advantages of using Javafx2 was the styling using the css. Even though I am not much of a css loving developer, still I thought of giving this a try and to my amazement the results were a bit more satisfying. 

Of course, it is up to the developer, but what I feel is that the idea of separating the presentation entirely makes a lot more sense than including the same in your code. Imagine a fully grown complex Application and all of a sudden "I kinda wanna change the way it looks"...

Now, lets try and make our application aware of the css. This is simple handled in the code. 
Open your Launcher.java or any other class where you have called your stage and scene instances. 
Add the line of code.

scene.getStylesheets().add(getClass().getResource("/css/notepad.css").toExternalForm());

I have an eclipse structure. My notepad.css should be residing in the src/css folder. To start with the basics you can read this css tutorial on Javafx2. This mentions about the the default css called "caspian.css" that is available in the   "jfxrt.jar". Even if you do not want to alter the css, it is a very good resource for your knowledge on the subject.

Now let us create a notepad.css in the mentioned folder structure. 
First, I specifically do not like the black colour of the menubar. Let's start by changing the colour of the same.
This is done in two steps.

Open your fxml file and an ID to the menubar.
<MenuBar fx:id="menubar">

Now add the following in your css
#menubar{
-fx-background-color: #b0c4de;
}

This is what you get as an output. 



















The colour is changed but it is still flat. Let us add a gradient look to it.
Change the above code to

-fx-background-color: linear-gradient(#FFF, #D4DBED, #E1E6F6);

It works well, but there is still lot of things to be fixed. Again, I am no css expert and hence not getting into too much detail here. Please refer css reference for details.

Moving ahead, I am not liking the white color of the menu labels. Let me change the same to black. 
Add the following code to the css file.
.menu .label{
    -fx-text-fill: black;
}
Here I am telling the fx engine to paint black all the labels of the menu.

Now, I observe a blue coloured border around the textarea that we created. Lets remove the same. This is Javafx default.
Update the below line to your fxml file. We are adding an id to the textarea.
<TextArea fx:id="textpane">
</TextArea>

Now let's add the style in css. Add the following styling to the css.
#textpane{
-fx-background-insets: 0, 0, 1, 2;
}

Instead of adding an ID you can use .text-area as well. Totally upto you.But we'll be needing the ID we added in our application later on. So might as well use it.

Now, I want to change the drop down menu that appears when you click on File or Edit or any other Menu. I want the background color a bit different and solid. The code below is to be added for this in your css file.

.context-menu {
-fx-background-color: #F1F1F1;
-fx-border-color: black;
-fx-border-width: 0.5;
}

It gives a more familiar looking context menu. Now we have almost the look and feel we want for our notepad. There are still a lot that can be done here. Lets stop with the styling part here itself.

The core of the application is the functionality. Let us start by adding those in the next part.  

Saturday, June 29, 2013

Create a Notepad with Javafx2 - The Layout

There are many things that a FX Application can do. Its features can be experienced when we start creating Applications and diving into the limitless creative abilities and features offered. Our motive here is also simple here. 

Lets start by creating a simple Application - Notepad. Yes, one of simplest yet a very useful application. 

There are many ways of creating a Notepad. I'll be using the following.



The detailed breakup of layout is shown below.




Let us know start writing the fxml code for all that we decided above. The code will be very simple and will contain only the layout of the application and nothing beyond that. The rest is parked for a later discussion. For now lets create the layout. 

Create a notepad.fxml file and start filling up as we have mentioned in the prototype above.

Now, creating a window will be handled in the Java code. Let's start by creating a BorderPane. BorderPane lays out children in top, left, right, bottom, and center positions.

Enter the following lines in your fxml file.

<BorderPane xmlns:fx="http://javafx.com/fxml">
        <top>
        </top>
<center>
<TextArea>
</TextArea>
</center>
</BorderPane>

The code is simple. We are adding a BorderPane. We need a top and center placement and hence the elements 'top' and 'center'. 
Now we have to fill up top placeholder. Looking back at the  requirement we are supposed to add a MenuBar. Easy. Javafx helps us with this as well. 

       <top>
<MenuBar>
<menus>
<Menu text="File">
<items>
<MenuItem text="New"></MenuItem>
<MenuItem text="Open..."></MenuItem>
<MenuItem text="Save"></MenuItem>
<MenuItem text="Save As..."></MenuItem>
</items>
</Menu>
<Menu text="Edit">
<items>
<MenuItem text="Undo"></MenuItem>
<SeparatorMenuItem></SeparatorMenuItem>
</items>
</Menu>
</menus>
</MenuBar>

</top>

Adding a MenuBar is simple. The entire container that holds your Menu is called a MenuBar. A MenuBar will contain Menu's which in turn will have different submenus called items. Fill up whatever Menu and items you need and complete the code.

Here is the fxml code that I have written.

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.SeparatorMenuItem?>
<BorderPane xmlns:fx="http://javafx.com/fxml">
<top>
<MenuBar>
<menus>
<Menu text="File">
<items>
<MenuItem text="New"></MenuItem>
<MenuItem text="Open..."></MenuItem>
<MenuItem text="Save"></MenuItem>
<MenuItem text="Save As..."></MenuItem>
<SeparatorMenuItem></SeparatorMenuItem>
<MenuItem text="Page Setup..."></MenuItem>
<MenuItem text="Print"></MenuItem>
<SeparatorMenuItem></SeparatorMenuItem>
<MenuItem text="Exit"></MenuItem>
</items>
</Menu>
<Menu text="Edit">
<items>
<MenuItem text="Undo"></MenuItem>
<SeparatorMenuItem></SeparatorMenuItem>
<MenuItem text="Cut"></MenuItem>
<MenuItem text="Copy"></MenuItem>
<MenuItem text="Paste"></MenuItem>
<MenuItem text="Delete"></MenuItem>
<SeparatorMenuItem></SeparatorMenuItem>
<MenuItem text="Find..."></MenuItem>
<MenuItem text="Find Next"></MenuItem>
<MenuItem text="Replace..."></MenuItem>
<MenuItem text="Go To..."></MenuItem>
<SeparatorMenuItem></SeparatorMenuItem>
<MenuItem text="Select All"></MenuItem>
<MenuItem text="Time/Date"></MenuItem>
</items>
</Menu>
<Menu text="Format">
<items>
<MenuItem text="Word Wrap"></MenuItem>
<MenuItem text="Font..."></MenuItem>
</items>
</Menu>
<Menu text="View">
<items>
<MenuItem text="Status Bar"></MenuItem>
</items>
</Menu>
<Menu text="Help">
<items>
<MenuItem text="View Help"></MenuItem>
<SeparatorMenuItem></SeparatorMenuItem>
<MenuItem text="About Notepad"></MenuItem>
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<TextArea>
</TextArea>
</center>
</BorderPane>


Fxml code is easy to understand. 
Remember to note the import statements like 
<?import javafx.scene.control.Menu?>

The fxml above is to be loaded by Java code as already mentioned in previous blogs. 
Here is the Java code for us. 

import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class Launcher extends Application {

 @Override
 public void start(Stage primaryStage) {

  try {
   // loading the fxml
   Pane pane = FXMLLoader.load(getClass().getResource(
     "/fxml/notepad.fxml"));
   
   // creating and initializing the scene.
   Scene scene = new Scene(pane);
   primaryStage.setScene(scene);

   // setting the height and width of stage.
   primaryStage.setWidth(1024);
   primaryStage.setHeight(768);

   // setting the App title
   primaryStage.setTitle("Untitled - Notepad");

   // display the stage
   primaryStage.show();

  } catch (IOException e) {
   e.printStackTrace();
  }
 }

 public static void main(String[] args) {
  launch(args);
 }
}


After we have finished, run the application. This is what we get as an output. Not much but we have managed at least the layout. looking at the code it cannot become simpler than this. 



So here we are with the layout of the App. Next we will try to add some css to  the application. 

Friday, June 14, 2013

Creating your first Javafx Program

The conventional way of starting is "Hello world!!!". Lets not do it and start off with something that just helps us going forward. 

I'll be using Eclipse for all my projects. Needless to mention, that the basics should be the same for any editor of your choice. Also, I'll be creating my projects using fxml (an xml representation of your UI). But this does not mean that you are limited to using the same. Javafx offers the very familiar swingy way of creating UI's as well. Why I prefer fxml is different story altogether. 

Create a JavaFX project in your eclipse. If you have downloaded e(fx)clipse you'll be able to view it in the new project wizard. You can refer to this post if you want to do the same. However, if not downloaded and you do not intend to as well then just create a java application and add jfxrt.jar in your project. You should find it in your jdk installation. if you don't want to include it in each and every time you create a project then you can default it in your eclipse.
  
Project Structure


My Project Structure looks something like this. 












Select Main Class





Go to src folder and right click to view the select wizard. Select Javafx Main Class as shown. Fill up a name and click finish. You should see a class created in the src folder. 
















After you have finished with the wizard, you will see a class file with the same skeleton structure as shown on the left. If you don't have e(fx)clipse installed the simply create a class and add the code as shown on the left. 







Creating the Main class

---------------------------------------------------------------------------------

import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class First extends Application {

@Override
public void start(Stage primaryStage) throws IOException {

//loading the fxml
Pane pane = FXMLLoader.load(getClass().getResource(""));

//creating and initializing the scene.
Scene scene = new Scene(pane);
primaryStage.setScene(scene);

//setting the height and width of stage.
primaryStage.setWidth(1024);
primaryStage.setHeight(768);

//setting the App title
primaryStage.setTitle("My first program");

//display the stage
primaryStage.show();
}

public static void main(String[] args) {
launch(args);
}

}

-----------------------------------------------------------------------

You should see an error when you try to run this. This is because you have not supplied the name of fxml when you are trying to load the fxml. Change the line to 

Pane pane = FXMLLoader.load(getClass().getResource("first.fxml"));

Now you should be creating the fxml file. 
Right click on the src folder and select the Javafx wizard in the same way you did above. Select New fxml document. Add a name to the fxml document you wish to create and supply the same name to the FXML loader in the main class. 


Creating the fxml file

---------------------------------------------------------------------------------

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.BorderPane?>

<BorderPane xmlns:fx="http://javafx.com/fxml">
<!-- TODO Add Nodes -->
</BorderPane>

---------------------------------------------------------------------------------

Now your set to go. Run you main class and you should be able to see the stage. Your stage should be something like this

First Stage


That's it. This looks very simple as compared to a lot many programs that I have written for the same purpose.  My choice was fxml, but if you want you code your ui in the classes as well. Simple yet powerful and that is what Javafx2 is all about.