TodoFX2

(Difference between revisions)
(Add a graph)
(Support for JPA)
Line 165: Line 165:
==Support for JPA==
==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).
+
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). NetBeans provides very good support for JPA.
 +
 
 +
1. Right-click on <code>todofx</code> package and select <code>New --> Other --> Persistence --> Entity Classes from Database...</code> and click '''Next'''
 +
 
 +
[[File:TodoFX-Fig20.png|"Figure 20 - Start the JPA wizard"]]
 +
 
 +
2. Select your Database Connection, select the <code>TODO</code> table from the list of ''Available Tables'' and click on '''Add''' to add it to the list of ''Selected Tables''. Click '''Next'''.
 +
 
 +
[[File:TodoFX-Fig21.png|"Figure 21 - Select the Database Tables"]]
 +
 
 +
3. Edit the class name from <code>Todo</code> to <code>Task</code>. Leave the other settings as in the figure and click on '''Next'''.
 +
 
 +
[[File:TodoFX-Fig22.png|"Figure 22 - Edit the Entity Classes"]]
 +
 
 +
4. Leave the default settings in the ''Mapping Options'' page and click '''Finish'''.
 +
 
 +
Your project should be similar to the one shown in the figure:
 +
 
 +
[[File:TodoFX-Fig23.png|"Figure 23 - TodoFX project with JPA support"]]
 +
 
 +
The wizard has created the <code>persistence.xml</code> file that contains the details about the connection with the database:
 +
 
 +
<code><pre>
 +
<?xml version="1.0" encoding="UTF-8"?>
 +
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
 +
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 +
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
 +
                    http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
 +
  <persistence-unit name="TodoFX-JPAPU" transaction-type="RESOURCE_LOCAL">
 +
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
 +
    <class>todofx.Task</class>
 +
    <properties>
 +
      <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:file:C:\Users\ikost\db\todo.script"/>
 +
      <property name="javax.persistence.jdbc.user" value="SA"/>
 +
      <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
 +
      <property name="javax.persistence.jdbc.password" value=""/>
 +
    </properties>
 +
  </persistence-unit>
 +
</persistence>
 +
</pre></code>
 +
 
 +
It has also created <code>todofx.Task</code> class which is our Entity class. If you had chosen <code>todofx.model</code> package instead of <code>todofx</code>, the wizard would have created a <code>Task_1.java</code> file in order not to override <code>Task.java</code>.
 +
 
 +
Copy the changes from <code>todofx.Task</code> to <code>todofx.model.Task</code>. You may also copy <code>todofx.Task</code> to <code>todofx.model.Task</code> but I 'd personally keep the raw data types (<code>int, boolean</code>) instead of the generated ((<code>Integer, Boolean</code>)).
 +
 
 +
Another issue is with <code>dueDate</code>. JPA 2.1 does not support Java 8, while these lines are being written, so a workaround is needed.
 +
 
 +
The result should be something like:
 +
 
 +
<code><pre>
 +
 
 +
</pre></code>
 +
 
 +
''Note! When you clean and build the project, you might encounter an exception <code>class file for sun.util.logging.PlatformLogger not found</code>. Fortunately, there is an easy [http://stackoverflow.com/questions/22562797/javafx8-sun-util-logging-platformlogger-not-found-exception-in-netbeans-8 solution]:
 +
 
 +
# Right Click on the project and select "Properties".
 +
# Select "Libraries" from opened "Project Properties window".
 +
# Select "Processor" tab.
 +
# Remove EclipseLink from there.
 +
# Click on '''OK''' and do a Clean Build.''
==References==
==References==

Revision as of 20:32, 14 June 2016

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(TaskListWrapper.wrap(
                   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). NetBeans provides very good support for JPA.

1. Right-click on todofx package and select New --> Other --> Persistence --> Entity Classes from Database... and click Next

"Figure 20 - Start the JPA wizard"

2. Select your Database Connection, select the TODO table from the list of Available Tables and click on Add to add it to the list of Selected Tables. Click Next.

"Figure 21 - Select the Database Tables"

3. Edit the class name from Todo to Task. Leave the other settings as in the figure and click on Next.

"Figure 22 - Edit the Entity Classes"

4. Leave the default settings in the Mapping Options page and click Finish.

Your project should be similar to the one shown in the figure:

"Figure 23 - TodoFX project with JPA support"

The wizard has created the persistence.xml file that contains the details about the connection with the database:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
                    http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="TodoFX-JPAPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>todofx.Task</class>
    <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:file:C:\Users\ikost\db\todo.script"/>
      <property name="javax.persistence.jdbc.user" value="SA"/>
      <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
      <property name="javax.persistence.jdbc.password" value=""/>
    </properties>
  </persistence-unit>
</persistence>

It has also created todofx.Task class which is our Entity class. If you had chosen todofx.model package instead of todofx, the wizard would have created a Task_1.java file in order not to override Task.java.

Copy the changes from todofx.Task to todofx.model.Task. You may also copy todofx.Task to todofx.model.Task but I 'd personally keep the raw data types (int, boolean) instead of the generated ((Integer, Boolean)).

Another issue is with dueDate. JPA 2.1 does not support Java 8, while these lines are being written, so a workaround is needed.

The result should be something like:


Note! When you clean and build the project, you might encounter an exception class file for sun.util.logging.PlatformLogger not found. Fortunately, there is an easy solution:

  1. Right Click on the project and select "Properties".
  2. Select "Libraries" from opened "Project Properties window".
  3. Select "Processor" tab.
  4. Remove EclipseLink from there.
  5. Click on OK and do a Clean Build.

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