Developing a Simple Todo Application using JavaFX, Java and MongoDB- Part-3

In the previous post we created the UI for adding a new Todo where in we used a Tab, TabPane and added the required controls- TextField and a Button to the Tab.

also read:

Going forward, in this post we will create the UI for listing the Open Todos i.e the Todos which have not been marked as Closed. We intend to implement the following features in the UI:

  • Ability to load the Todos when the Tab is selected.
  • Obtain a list view for the Todos with a scroll bar if the list takes more vertical space than required.
  • For each Todo, provide a button to mark the todo as completed.

Before going further, lets have a look at the possible UI we wish to generate at the end:

Loading the Todo on Tab selection:

We add an EventHandler (class TodoLoader) which is added to the Tab#onSelectionChanged event, which loads the Todos from the repository and creates a GridPane with the task name, date when it was added and the button to mark the Todo as completed. This button, which marks the Todo as closed, uses the CloseTodoHandler.

TodoLoader and CloseTodoHandler implement EventHandler and the handle method is overridden to add the required functionality.

Constructing the Handler for loading the Open Todos:

In the TodoLoader#handle(Event event) method we:

Get all the open todos from the database:

 
openTodos = TodoDAO.getOpenTodos();

For each Todo we have fetched, create a Label for task text and date added and a button for marking the todo as completed. Also for the button we set its actionEvent handler which is an instance of CloseTodoHandler.

 
for(Todo aTodo : openTodos)
{
  GridPane todoPane = new GridPane();
  Label taskLabel = new Label(aTodo.getTask());
  Label dateAdded = new Label(aTodo.getAdded().toString());

  CloseTodoHandler closeHandler =
    new CloseTodoHandler(todoBox,
          todoPane,
          aTodo);
  Button closeButton  = ButtonBuilder.create()
      .graphic(new ImageView(
           new Image(getClass().getResourceAsStream('check.png'))))
      .onAction(closeHandler)
      .build();

  todoPane.add(taskLabel,1,1,5,1);
  todoPane.add(dateAdded,1,2,4,1);
  todoPane.add(closeButton, 5, 2, 1, 1);
  todoBox.getChildren().add(todoPane);
}

The code for the complete class which loads the Todos and constructs the required UI is:

 
class TodoLoader implements EventHandler<Event>{

  List<Todo> openTodos;   
  VBox todoBox;

  TodoLoader(VBox todoBox){
    this.todoBox = todoBox;
  }
  @Override
  public void handle(Event event) {
    //Clear the existing Todos, for adding new Todos
    todoBox.getChildren().clear();
    try {
      openTodos = TodoDAO.getOpenTodos();
      for(Todo aTodo : openTodos)
      {
        //A component that displays the information for each todo
        GridPane todoPane = new GridPane();
        Label taskLabel = new Label(aTodo.getTask());
        Label dateAdded = new Label(aTodo.getAdded().toString());

        //Event handler for handling close operations
        CloseTodoHandler closeHandler =
            new CloseTodoHandler(todoBox,
                todoPane,
                aTodo);
        Button closeButton  = ButtonBuilder.create()
            .graphic(new ImageView(
                     new Image(getClass().
                               getResourceAsStream('check.png'))))
            .onAction(closeHandler)
            .build();

        /*
         * Add the task label,
         * date added, and the 
         * close button to the 
         * gridpane component
         */
        todoPane.add(taskLabel,1,1,5,1);
        todoPane.add(dateAdded,1,2,4,1);
        todoPane.add(closeButton, 5, 2, 1, 1);
        todoBox.getChildren().add(todoPane);
      }
    } catch (UnknownHostException e) {
      e.printStackTrace();
    }
  }
}

Now, lets look at some aspects of the CloseTodoHandler.

Constructing the handler for closing the Todos:

Each button which handles closing of todo should be aware of:

  • which Todo to close i.e have a reference to the Todo instance
  • which GridPane to remove from the VBox, should have a reference to GridPane instance
  • which VBox to remove from i.e reference to the VBox instance.

When we are creating the instance of the CloseTodoHandler, we pass in these information as shown

 
CloseTodoHandler closeHandler = 
    new CloseTodoHandler(todoBox,
                         todoPane,
                         aTodo);

In the handling of this event: we just have to invoke the corresponding DAO method to close the Todo and also remove it from the VBox as shown below:

 
@Override
public void handle(ActionEvent actionEvent) {
  try {
    TodoDAO.setTodoAsCompleted(todo);
    todoBox.getChildren().remove(todoPane);
  } catch (UnknownHostException e) {
    e.printStackTrace();
  }
}

The complete code for the CloseTodoHandler is:

 
class CloseTodoHandler implements EventHandler<ActionEvent>{

  VBox todoBox;
  GridPane todoPane;
  Todo todo;

  CloseTodoHandler(VBox todoBox,
                   GridPane todoPane,
                   Todo todo){
    this.todo = todo;
    this.todoBox = todoBox;
    this.todoPane = todoPane;
  }
  
  @Override
  public void handle(ActionEvent actionEvent) {
    try {
      TodoDAO.setTodoAsCompleted(todo);
      todoBox.getChildren().remove(todoPane);
    } catch (UnknownHostException e) {
      e.printStackTrace();
    }
  }
}

Now we have to build the Tab which uses all the above classes, event handlers to generate the UI as shown in the screen shot above. An instance of VBox is created to add all the Todos on the UI and this instance is passed to the TodoLoader class so that it can use it to populate the UI as shown above in the TodoLoader class definition.

 
final VBox todoBox = new VBox();
todoBox.setTranslateX(10);
todoBox.setSpacing(10);

As the items can occupy more than the given height of the application, we use ScrollPane to add the Veritcal scroll bars:

 
final ScrollPane todoListScroll = ScrollPaneBuilder.create()
    .hbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED)
    .prefHeight(APP_HEIGHT - 90)
    .maxWidth(APP_WIDTH)
    .build();
todoListScroll.setContent(todoBox);

And finally build the Tab as:

 
Tab allTodosTab = TabBuilder.create()
    .text('All todos')
    .content(todoListScroll)
    .closable(false)
    .onSelectionChanged(new TodoLoader(todoBox))
    .build();

We refactor this code into a method and this method is invoked from the TodoAppRunner defined in the previous post.

 
private Tab buildShowAllTodoUi(){
  final ScrollPane todoListScroll = ScrollPaneBuilder.create()
    .hbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED)
    .prefHeight(APP_HEIGHT - 90)
    .maxWidth(APP_WIDTH)
    .build();

  final VBox todoBox = new VBox();
  todoBox.setTranslateX(10);
  todoBox.setSpacing(10);
  todoListScroll.setContent(todoBox);

  Tab allTodosTab = TabBuilder.create()
   .text('All todos')
   .content(todoListScroll)
   .closable(false)
   .onSelectionChanged(new TodoLoader(todoBox))
   .build();

  return allTodosTab;
}

The complete source code can be downloaded from here. I know its been a long series of posts and if you are stuck at any point just let us know via the comments here and we would try to clear out the confusion.

Comments

comments

About Mohamed Sanaulla

In his day job he works on developing enterprise applications using ADF. He is also the moderator of JavaRanch forums and an avid blogger.

Comments

  1. Nice post Sana, I had attempted something similar in Flex-AIR long time back – I was wondering if there was any option in JavaFX to change the native window shape (it’s called Custom Chrome in AIR).

    • Mohammed Sanaulla says:

      Hi Shreyas, the JavaFX components can be styled using CSS and I think one can change the appearance using CSS. I haven’t tried it, let me give it a try and may be write a post.
      Thanks for dropping by!

Trackbacks

  1. [...] my next post, I will show how to create a UI for listing all the unfinished Todos, and set the Todos as [...]

  2. JavaPins says:

    Developing a Simple Todo Application using JavaFX, Java and MongoDB- Part-3…

    Thank you for submitting this cool story – Trackback from JavaPins…

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better