TodoFX2

Revision as of 21:14, 8 June 2016 by Jnk (Talk | contribs)

By John Kostaras


Contents

Introduction

This article is an evolution of the TodoFX application. We shall see how to:

  • add a graph
  • port database access to JPA

Before we continue, please download the TodoFX application from here.

Add a graph

JavaFX has very good support for graphs. We shall extend our TodoFX application by creating a statistics graph to display due date distribution.

We'll use a Bar Chart containing a bar for each month to show how many tasks expire in that particular month.

  1. Right-click on the viewcontroller package and select New --> Other --> JavaFX --> Empty FXML as shown below. Click Next.
  2. Provide TaskStatistics as the FXML Name. Click Next.
  3. Check Use Java Controller and accept the default. Click Next.
  4. Click Finish.

"Figure 12 - Create new FXML file"

  1. Double click on TaskStatistics.fxml to open it in SceneBuilder.
  2. Select the root AnchorPane.
  3. Add a BarChart to the AnchorPane.
  4. Right-click on the BarChart and select Fit to Parent.
  5. Save the .fxml file

Open the TaskStatisticsController and add the following code:

package todofx.viewcontroller;

import java.net.URL;
import java.text.DateFormatSymbols;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.XYChart;
import todofx.model.Task;

/**
 * Task Statistics.
 *
 * @author ikost
 */
public class TaskStatisticsController implements Initializable {

    @FXML
    private BarChart<String, Integer> barChart;

    @FXML
    private CategoryAxis xAxis;

    private final ObservableList<String> monthNames = FXCollections.observableArrayList();

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // Get an array with the English month names.
        String[] months = DateFormatSymbols.getInstance(Locale.ENGLISH).getMonths();
        // Convert it to a list and add it to our ObservableList of months.
        monthNames.addAll(Arrays.asList(months));

        // Assign the month names as categories for the horizontal axis.
        xAxis.setCategories(monthNames);
    }

    /**
     * Sets the tasks to show the statistics for.
     *
     * @param tasks
     */
    public void setTaskData(List<Task> tasks) {
        // Count the number of tasks expiring in a specific month.
        int[] monthCounter = new int[12];
        tasks.stream()
                .map(t -> t.getDueDate().getMonthValue() - 1)
                .forEach(month -> monthCounter[month]++);

        XYChart.Series<String, Integer> series = new XYChart.Series<>();

        // Create a XYChart.Data object for each month. Add it to the series.
        for (int i = 0; i < monthCounter.length; i++) {
            series.getData().add(new XYChart.Data<>(monthNames.get(i), monthCounter[i]));
        }

        barChart.getData().add(series);
    }

}

The BarChart<String, Integer> uses the String for the months and the Integer for the number of tasks. In the initialize() method, xAxis is initialised with the list of months. setTaskData() will be accessed by Main to set the task data. It loops through all tasks and counts their due dates per month. Then it adds XYChart.Data for every month to the data series. Each XYChart.Data object will represent one bar in the chart.

In SceneBuilder, link the BarChart to the barChart (fx:id) and select the CategoryAxis and connect it to the xAxis property.

"Figure 18 - CategoryAxis"

To connect the TaskStatistics to the rest of the application, add the following method in Main:

    /**
     * Opens a dialog to show task statistics.
     */
    public void showTaskStatistics() {
        try {
            // Load the fxml file and create a new stage for the popup.
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(getClass().getResource("viewcontroller/TaskStatistics.fxml"));
            AnchorPane page = (AnchorPane) loader.load();
            Stage dialogStage = new Stage();
            dialogStage.setTitle("Task Statistics");
            dialogStage.initModality(Modality.WINDOW_MODAL);
            dialogStage.initOwner(primaryStage);
            Scene scene = new Scene(page);
            dialogStage.setScene(scene);

            // Set the tasks into the controller.
            TaskStatisticsController controller = loader.getController();
            try {
                controller.setTaskData(TaskManagerDB.getInstance().listAllTasks(true));
            } catch (DatabaseException ex) {
                Logger.getLogger(Main.class.getName())
                      .log(Level.SEVERE, null, ex);
            }

            dialogStage.show();

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

Finally, open TaskMain in SceneBuilder. Add a new menu Statistics and a new menu item inside it Show Statistics....

Edit TaskMainController by adding the following method:

    /**
     * Opens the task statistics.
     */
    @FXML
    private void handleShowTaskStatistics() {
        mainApp.showTaskStatistics();
    }

Don't forget to link the Show Statistics... menu item to the handleShowTaskStatistics() handler method (Inspector --> Code --> On Action).

If everything went OK, then you should be able to see a dialog box similar to the one below:

"Figure 19 - Task Statistics"

Support for JPA

JDBC is not used anymore in modern applications, when there is a choice to use an Object-Relational Mapping (ORM) library like the standard Java Persistence API (JPA).

References

  1. Lozano F. (2006), "A complete App using NetBeans 5", NetBeans Magazine, Issue 1, May, http://netbeans.org/download/magazine/01/nb01_completeapp.pdf
  2. Anderson G., Anderson P. (2014), JavaFX Rich Client Programming on the Netbeans Platform, Addison-Wesley.
  3. Dea C. et al. (2014), JavaFX 8 Introduction by Example, 2nd Ed., APress.
  4. Duodu E. (2015), "How to Create a JavaFX GUI using Scene Builder in NetBeans", IDR Solutions.
  5. Jacob M. (2014), "JavaFX 8 Tutorial", code.makery.
  6. Sharan K. (2014), Learn JavaFX 8, APress.
  7. Tamam M. (2015), JavaFX Essentials, APress.
  8. Vos J. et al. (2014), Pro JavaFX 8, APress.
Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo