- [Instructor] So, at the end of the last video,
we got this error that we couldn't connect to database,
and that was because we haven't got a suitable jdbc driver,
and if you recall, we actually set up the jdbc driver
in the previous application,
but we haven't done it for this one,
so let's go ahead and actually do that now.
So, I'm gonna come over here and click on the project.
Right click.
I can open Module Settings,
going to go to Libraries,
click on plus,
click on or select Java,
and the actual drive file is in the Downloads folder,
sqlite-jdbc.
That's the driver we have previously downloaded.
I'm gonna add that to this library,
and you can see that it's going to be added
to music UI, which is our current application,
our project.
Click on OK.
Click on OK again, and that's the driver
now added to the class path,
so we should now be able to run it again.
Now, just before I do run it, though,
note here that, because we've copied
the Datasource dot java file,
we've copied all the information
including the path, so the actual path, at the moment,
is pointing to our previous project,
the database in that directory,
and if you recall, we talked about, if you're on Windows,
selecting the path, so you may want to update this path
or just know that you're using the database
that's in that other project.
So I'm going to leave it on this default,
calling it the music folder,
which was, again, the previous application,
but just keep that in mind if you're wondering
where the database is.
It's actually grabbing that because we've copied
the Datasource dot java file.
It's using the same directory or the connexions string
pointing to that database.
Alright, so let's go back to main.
If we run it again, now,
we should find that things will work okay.
Okay, this time the error's now disappeared,
because we've added the jdbc driver for SQLite
to our class path, and you can see that
the interface has appeared.
Alright, so when the application starts,
what we want to do is display all the artists
in the artists table.
Now, it's also possible that the user
might explicitly ask to see,
or the artists after they've performed,
some other query,
so consequently, we need to query all the artists
when the application starts,
and also, potentially, in response to user input.
Now, remember that we always wanna perform long tasks
on a background thread,
not on the main javafx application thread,
and if you recall from the thread section of this course,
that when we want to run background threads
from a javafx application,
we need to use helper classes
in the javafx dot concurrent package.
So, I'm gonna perform the following steps,
not necessarily, though, in the order
that I'm gonna read them out.
Firstly, we wanna create a task
to perform the database action,
the query, the insert, or whatever we're doing.
Secondly, we want to initialise the task
with values required to perform the action,
if that's necessary.
Third, we want to implement the task dot core method
to perform the action.
Fourth, we want to bind the core results
to the table view's items property,
and then finally, we want to invoke the task.
Now, because we may need to use this task from two places,
at start up and when the user explicitly asks
to see all artists, we're not going to use
an anonymous task class
that we create in response to user input,
and you'll see an example of this later.
What we're gonna do is we'll add a get all artists
task class to the controller.
So, let's go ahead and add that,
so I'm just gonna close this down.
So, we're going back to our controller,
and what we're going to do is add the method in there.
Alright, so let's add this class,
the get all artists task class to the controller,
so I'm going to add the class below
the public class controller code,
and we're gonna call this one, type in class,
and GetAllArtistsTask,
and that's extending tasks, Task, I should say,
which is from the javafx dot concurrent.
Okay, then we're gonna override the core method,
but we do wanna change this around a little bit,
so we wanna actually make this an observable list
that it's going to be returning.
So, instead of object, it's gonna be
ObservableList,
and it's gonna be list up artist objects,
so Artists, and we might need to, right,
have the exception there, so I'm just gonna remove that,
so as instead of protected, also,
we'll just make that public for simplicity, so public.
It's returning an observable list of artist objects.
The core method is still the right one,
and in terms of what we're gonna return here,
instead of returning null,
we're going to return FXCollections
dot observableArrayList,
and I'll put that on the next line.
It's going to be Datasource
dot getInstance,
getting our singleton dot queryArtists,
and we're going to do a Datasource
order by sending, so order, underscore,
by, underscore, ask is what we wanna select there.
So, that's what this method's ultimately gonna call,
and again, the reason that we're creating
a separate class here and putting it in the controller
dot java file is we may need to use this task
in two places.
Firstly, at startup,
but also when the user explicitly asks to see all artists,
so that's why we're not using an anonymous task class.
Alright, so the class, as you can see,
had to extend task,
and if we wanna use data binding to populate the table,
the core method, which we've reconfigured,
has to return an observable list of artists,
and you saw me use the correct
javafx dot collections class when importing.
That's obviously very important,
and you can confirm that by checking
the import C on line three.
Alright, so we've overridden the core method
to call the query artist method
in our Datasource dot java file.
Now, that method, if you recall, returns a list.
Now, we don't wanna change it to return an observable list,
because that would violate the separation
between the model and UI code.
Instead, the tasks creating an observable list
from the list that query artists method returns,
so we're doing that by calling the FXCollections
dot observableArrayList passing in the list that is returned
from our Datasource,
which then, ultimately, will give us an observable list.
Now, in a previous video, I said that we can use
the model classes as is,
and that would be true if we didn't want to
take advantage of data binding,
but here, we do actually want to take advantage of that,
so consequently, we do need to make one small change
to the artist class to achieve that,
so instead of storing the artist name in a string,
we need to store it as a simple string property.
Now, this doesn't violate the model UI separation,
because simple string property isn't a UI specific class.
Now, we could have used it all along, actually.
We'll do the same for the artist ID, though,
even though we're not displaying it.
Now, because the fields will now be properties,
the getter and setter methods are all gonna change as well,
so let's go over to the artist class and make those changes.
So, at the moment, you can see that we've got them set up
as private, as an int and a string for the ID
and the name and the artist class,
but we're gonna change that to a simple
integer property,
and then a simple
string property,
so for the ID and the name,
you can see that we've returned that,
and consequently, we also need to change the
getters and setters, so for the ID,
we're going to pass in a simple property
and a simple integer property, and return the ID.
Likewise for the setting.
We're going to get a simple integer property,
and likewise for the string as well.
We're going to return the simple string property
and when we're setting it,
we're going to return the simple string property.
Alright, so that's our artist class updated,
and again, we're only doing this
because we want to use data binding.
Since this is a simple application,
if we wanted to keep our model classes
exactly as they were, then we could do that,
and we would explicitly then set the table items
when the task completes.
Now, there are two ways we could set the items.
Now, I covered the first way in the threading section
of the course.
We could call our core platform dot run later,
when the query artist method returns its results,
and in the runnable we passed to run later,
we could set the table items,
artistTable dot getItems dot setAllArtistResults.
Now, I also mentioned in the other threading section
that we can do more with tasks than we covered,
including running code, when the core method completes.
Now, to do that, we need to call task dot set on succeeded,
and it actually wants an event handler.
In our case, though, the most straightforward way
to pass the code we want to execute
is to use a lambda, so we're gonna do something like this.
We're going to do task dot setOnSucceeded
and create our lambda.
Gonna be artistTable dot getItems
dot setAll
artistResults.
That's ultimately what we're gonna be doing.
We're making this a little bit easier to call
when the core method completes.
Alright,
so basically, what I'm getting at here is
whenever data binding makes sense,
it's best to use it,
'cause then we don't have to do anything
when the task completes.
It's all handled automatically.
Now, we have to do one more step
for data binding to work, though.
We have to map the name field in the artist class
to the name column in the table.
If you recall from the threading videos,
that we accomplished this by adding a cell value factory
to the table column, so let's go ahead and do that
in our FXML file,
so we're gonna look at adding a cellValueFactory
for the artist name.
So, we've got our table column here
for our artistTable name,
so to achieve this, we can actually just close off
that ending tag there,
and under the table column,
we wanna add a cellValueFactory, so it's
cellValueFactory,
and then we wanna add a propertyValueFactory
so propertyValueFactory
property equals and it's going to record name,
and then we need to close off our table column.
So, basically, we've added a propertyValueFactory
for the name, and that maps to the name field
in the artist class.
So, now that we've done that,
we can add a method to the controller
that gets the artists.
Let's go back to the controller.
We're gonna add some code in the controller class itself,
so firstly, we need a reference to the artistTable,
so that's gonna be @FXML,
then we want a private TableView,
which is a list of artists.
We'll call it artistTable,
and the actual method is going to be public void
listArtist,
and then we need to create our task,
so it's going to be task.
We want that ObservableList of artist objects.
Task is equal to new GetAllArtistsTask.
That's calling the class that we've defined,
or at least instantiating it,
so we're creating a new task object,
and then we wanna do artistTable
dot itemsProperty
dot bind,
and task dot valueProperty.
So, you can see that we've created a new task object
on line 17, then on line 18,
we're binding the result of the task,
in this case, the artistsObservableList,
to the table view's items property,
so they're actually bound to each other.
Alright, so let's finish the video here.
In the next video, we'll start looking at
how this is going to be invoked,
because the controller isn't created
until the FXML is loaded,
so we have to figure out how we're gonna get that to work,
so let's work on that in the next video.