I have some problem with understanding bindings in JavaFX.
For example I use simple class Person for showing data in TableView.
public class Person {
private StringProperty name=new SimpleStringProperty();
public Person() {
}
public Person(StringProperty name) {
this.name = name;
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
}
I have PersonDataModel class too
public class PersonDataModel {
private ObservableList<Person> personObservableList= FXCollections.observableArrayList();
private SimpleObjectProperty<Person> singlePerson=new SimpleObjectProperty<>(new Person());
public void listInitialize(){
personObservableList.clear();
personObservableList.add(new Person(new SimpleStringProperty("John")));
personObservableList.add(new Person(new SimpleStringProperty("Mike")));
personObservableList.add(new Person(new SimpleStringProperty("Ana")));
}
public ObservableList<Person> getPersonObservableList() {
return personObservableList;
}
public void setPersonObservableList(ObservableList<Person> personObservableList) {
this.personObservableList = personObservableList;
}
public Person getSinglePerson() {
return singlePerson.get();
}
public SimpleObjectProperty<Person> singlePersonProperty() {
return singlePerson;
}
public void setSinglePerson(Person singlePerson) {
this.singlePerson.set(singlePerson);
}
}
And now I want bind label.textProperty() with selected item in tableView.I use controller class.
public class PersonWindowController {
private PersonDataModel personDataModel=new PersonDataModel();
#FXML
private TableView<Person> nameTableView;
#FXML
private TableColumn<Person, String> nameTableColumn;
#FXML
private Label nameLabel;
#FXML
public void initialize(){
personDataModel.listInitialize();
nameTableColumn.setCellValueFactory(cellData->cellData.getValue().nameProperty());
nameTableView.setItems(personDataModel.getPersonObservableList());
nameLabel.textProperty().bind(personDataModel.getSinglePerson().nameProperty());
nameTableView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
if(newValue!=null) {
//1. Option doesn't work
//personDataModel.setSinglePerson(newValue);
//System.out.println(personDataModel.getSinglePerson().getName());
//2. Option works
personDataModel.getSinglePerson().setName(newValue.getName());
System.out.println(personDataModel.getSinglePerson().getName());
}
});
}
}
My questions are:
Why first option doesn't work ?. I changed singlePerson object but nameLabel didn't change.
I don't want to set all properties one by one when Person class will be more complicated. How to avoid this ?.
When singlePerson in PersonDataModel is just an object of Person class not SimpleObjectProperty the programm behaves exactly the same. Is any advantage to use SimpleObjectProperty in my example ?
Sorry for all mistakes I've made. Thanks in advance for your help.
Greg
Edit1: I edited my question after user Kleopatra answer.
Related
I have no problem filling my tableview with diffrent data from 1 class. But it does not work for me with multiple classes. Any idea how to solve that?
I have checked out similar questions on stackoverflow. But none of them could help me. If you suggest anything with the "Callback" class, please provide me the full import, because there are a couple of Callback classes out there.
public class MainViewController implements Initializable {
#FXML
private TableColumn<TaskControl, Boolean> colErledigt;
#FXML
private TableColumn<TaskControl, Character> colPrioritaet;
#FXML
private TableColumn<TaskControl, String> colBeschreibung;
#FXML
private TableColumn<ProjectControl, String> colProjekt;
#FXML
private TableView<TaskControl> tblView;
public final void initialize(final URL location,
final ResourceBundle resources) {
initializeTableElements();
}
public final void initializeTableElements() {
colBeschreibung
.setCellValueFactory(new PropertyValueFactory<>("description"));
colPrioritaet
.setCellValueFactory(new PropertyValueFactory<>("priority"));
colProjekt.setCellValueFactory(new PropertyValueFactory<>("name"));
colErledigt.setMaxWidth(50);
colErledigt.setCellValueFactory(
new PropertyValueFactory<TaskControl, Boolean>("isDone"));
colErledigt
.setCellFactory(CheckBoxTableCell.forTableColumn(colErledigt));
colErledigt.setEditable(true);
try {
tblView.setItems(getObsTasks());
} catch (IDNotValidException | StringNotValidException e1) {
System.out.print("FEHLER beim getObsTasks");
}
tblView.setEditable(true);
}
public ObservableList<TaskControl> getObsTasks()
throws IDNotValidException, StringNotValidException {
ObservableList<TaskControl> obsTasks = FXCollections
.observableArrayList();
Map<Context, Set<Task>> test = TasksContextUtility.INSTANCE
.getAllContextsAndTasks();
test.values().forEach(v -> {
v.forEach(b -> obsTasks.add((TaskControl) b));
});
return obsTasks;
}
Further question: How can I show a certain Attribute of an Instance in a HashSet in a TableCell. So I have in my TaskControl class a HashSet. In that HashSet there are Instances of the class "ProjectControl". Every instance of ProjectControl has attributes like "name" or "id" etc.
And I want to represent all the names of the project instances in 1 single table cell if possible. Maybe as a string seperated with commas (project1,project2,project3...).
Task class (shortened a lot) my TaskControl Class inherits from this class
public abstract class Task
implements Serializable, IDValidatable
{
private int id;
private char priority = ' ';
private final Set<Project> projects = new HashSet();
public Task(int oid)
throws IDNotValidException
{
if (isIDValid(oid)) {
this.id = oid;
} else {
throw new IDNotValidException("The ID you have specified is not valid!")
{
private static final long serialVersionUID = 99044660889990790L;
};
}
}
public final void setId(int oid)
throws IDNotValidException
{
if (isIDValid(oid)) {
this.id = oid;
} else {
throw new IDNotValidException("The ID you have specified is not valid!")
{
private static final long serialVersionUID = 99044660889990790L;
};
}
}
public final int getId()
{
return this.id;
}
public final Collection<Context> getContexts()
{
return this.contexts;
}
public final void addContext(Context context)
throws ContextNotValidException
{
this.contexts.add(context);
}
public final void removeContext(Context context)
throws ContextNotValidException
{
this.contexts.remove(context);
}
public final Collection<Project> getProjects()
{
return this.projects;
}
public final void addProject(Project project)
throws ProjectNotValidException
{
this.projects.add(project);
}
public final void removeProject(Project project)
throws ProjectNotValidException
{
this.projects.remove(project);
}
public final Map<String, String> getAddons()
{
return this.addons;
}
}
In my opition you only have one nice solution for this.
You need a extra Class that holds your TaskControl, ContextControl and ProjectControl.
Your Code can look something like that.
class Wrapper{
private TaskControl taskControl;
private ContextControl contextControl;
private ProjectControl projectControl;
...
public Boolean isDone(){
return taskControl != null ? taskControl.isDone() : null;
}
}
#FXML
private TableView<Wrapper> tblView;
#FXML
private TableColumn<Wrapper, Boolean> colErledigt;
colErledigt.setCellValueFactory(
new PropertyValueFactory<Wrapper, Boolean>("isDone"));
Solved it by adding an additional String to my TaskControl, that contains the names of all the projects it contains. It gets the names through a function that I call just before I create the ObservableList for the Table Column.
private String projectsAsString;
...
public final void convertProjectsToString() {
String projects = "";
for (Project p : this.getProjects()) {
ProjectControl pp = (ProjectControl) p;
projects += pp.getName() + ", ";
}
if (projects != null && projects != "" && projects.length() > 4) {
projects = projects.substring(0, projects.length() - 2);
}
this.projectsAsString = projects;
}
Thank you guys anyways for helping me.
I'm creating simple JavaFX application. I want my model layer to be completely independent from JavaFX - no StringProperty, IntegerProperty and etc. as fields. I want it to be POJO. Main reason to do so is that I want it to be Serializable.
I've created DataRepository - simple CRUD-like interface and some implementations of it, so I can at anytime change where I store my data - XML file, SQLite database or anything else. I also have to somehow connect my data storage with JavaFX (to display its content in TableView), so I decided to create my implementation of ObservableList which wraps my repository. My question is - is there any other way? ObservableList contains about 30 methods to implement and it looks like I'm doing something wrong.
My (simplified) model:
public class Movie implements Serializable {
private String title;
private String director;
public Movie() {
}
public Movie(String title, String director) {
this.title = title;
this.director = director;
}
// Getters and setters, equals etc...
}
MovieRepository:
public interface MovieRepository {
public void add(Movie movie);
public void remove(String title);
public void remove(int index);
public Movie get(String title);
public Movie get(int index);
public List<Movie> getAll();
}
Controller for my main view:
public class MainController {
#FXML
private TableView<Movie> movieTable;
#FXML
private TableColumn<Movie, String> movieTitleColumn;
#FXML
private Label titleLabel;
private MovieRepository movies = new DBMovieRepository(); //MovieRepository implementation which uses SQLite DB to store data
private MainApp app;
#FXML
private void initialize() {
movieTable.setItems(new ObservableMovies(movies));
// ObservableMovies is my implementation of ObservableList
// It basically wraps methods from MovieRepository
// and notifies listeners
showMovieDetails(null);
movieTitleColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getTitle()));
movieTable.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> showMovieDetails(newValue));
}
private void showMovieDetails(Movie movie) {
if(movie != null) {
titleLabel.setText(movie.getTitle());
} else {
titleLabel.setText("");
}
}
#FXML
private void handleNew() {
Movie movie = new Movie();
app.showNewMovieDialog(movie);
movieTable.getItems().add(movie);
}
public void setApp(MainApp app) {
this.app = app;
}
}
You have a couple of options here (maybe more), which are covered in other questions on this site. However, for convenience, I'll summarize them here too.
1. Use JavaFX Properties and make the class Serializable
You can do this with a custom serialized form. Make the JavaFX properties transient and implement readObject and writeObject to store the values they wrap:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Objects;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Movie implements Serializable {
private transient StringProperty title = new SimpleStringProperty();
private transient StringProperty director = new SimpleStringProperty();
public Movie() {
}
public Movie(String title, String director) {
setTitle(title);
setDirector(director);
}
#Override
public int hashCode() {
return Objects.hash(getDirector(), getTitle());
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Movie other = (Movie) obj;
return Objects.equals(getTitle(), other.getTitle())
&& Objects.equals(getDirector(), other.getDirector());
}
public final StringProperty titleProperty() {
return this.title;
}
public final String getTitle() {
return this.titleProperty().get();
}
public final void setTitle(final String title) {
this.titleProperty().set(title);
}
public final StringProperty directorProperty() {
return this.director;
}
public final String getDirector() {
return this.directorProperty().get();
}
public final void setDirector(final String director) {
this.directorProperty().set(director);
}
private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
s.defaultReadObject();
title = new SimpleStringProperty((String) s.readObject());
director = new SimpleStringProperty((String) s.readObject());
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeObject(getTitle());
s.writeObject(getDirector());
}
}
2. Use a POJO with "bound properties".
See JavaBean wrapping with JavaFX Properties for details. In brief:
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class Movie {
private String title ;
private String director ;
private final PropertyChangeSupport propertySupport ;
public Movie(String title, String director) {
this.title = title ;
this.director = director ;
this.propertySupport = new PropertyChangeSupport(this);
}
public Movie() {
this("", "");
}
public String getTitle() {
return title ;
}
public String setTitle(String title) {
String oldTitle = this.title ;
this.title = title ;
propertySupport.firePropertyChange("title", oldTitle, title);
}
// similarly for director...
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertySupport.addPropertyChangeListener(listener);
}
// hashCode and equals...
}
For wanting to wrap your repository as an observable list, instead wrap it with a repository implementation that uses an observable list:
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class ObservableMovieRepository implements MovieRepository {
private final MovieRepository repository ;
private final ObservableList<Movie> movieList;
public ObservableMovieRepository(MovieRepository repository) {
this.repository = repository ;
this.movieList = FXCollections.observableArrayList(repository.getAll());
}
#Override
public void add(Movie movie) {
repository.add(movie);
movieList.add(movie);
}
#Override
public void remove(String title) {
Movie movie = get(title);
repository.remove(title);
movieList.remove(title);
}
#Override
public void remove(int index) {
repository.remove(index);
movieList.remove(index);
}
#Override
public Movie get(String title) {
return repository.get(title);
}
#Override
public Movie get(int index) {
return movieList.get(index);
}
#Override
public ObservableList<Movie> getAll() {
return movieList ;
}
}
This uses the standard ObservableList implementation that copies an existing list on creation, and the implementation keeps that list in sync with the list in the wrapped repository. Now your UI code can do
ObservableMovieRepository movies = new ObservableMovieRepository(new DBMovieRepository());
// ...
movieTable.setItems(movies.getAll());
With the Movie class above, you would just do
movieTitleColumn.setCellValueFactory(cellData -> cellData.getValue().titleProperty());
If you use the POJO version you can do
movieTitleColumn.setCellValueFactory(cellData -> {
try {
return new JavaBeanStringPropertyBuilder()
.bean(cellData.getValue())
.name("title")
.build();
} catch (Exception e) { throw new RuntimeException(e); }
}
There seem to be multiple question in here, so I'm not really sure, if I understood you correctly, but I will try to split it up a bit.
I want my model layer to be completely independent from JavaFX - no
StringProperty, IntegerProperty and etc. as fields. I want it to be
POJO.
You could mark your properties as transient. Then you just need to wrap them around your values and it will be both JavaFX compliant and Serializable. You just have to propagate changes back to your backing attributes.
I also have to somehow connect my data storage with JavaFX (to display
its content in TableView), so I decided to create my implementation of
ObservableList which wraps my repository. My question is - is there
any other way?
Very limited information on this and I really don't know, why you would need to create your own implementation of ObservableList, but to keep it POJO, you could maintain plain java.util.Collections in your bean and provide transient ObservableLists, which you can create on creation by wrapping your java.util.Lists in your POJO. You can find those methods in the FXCollections utility class.
ObservableList contains about 30 methods to implement and it looks
like I'm doing something wrong.
If you really need to implement it, you can inherit from ObservableListBase.
I created a TableView a while back and registered Properties to each of the TableColumns. Editing of the internal data reflected itself back in the TableView just fine.
With a ListView, however, it is a different story. The changes are not being shown right away unless I close the frame and open it again.
My ListView consists of ActionSteps. Note that I used the Javafx beans properties.
package application.objects;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.function.IntPredicate;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class ActionStep {
private StringProperty actionStepID;
private ObjectProperty<LocalDate> dateSet, dateFinished;
private StringProperty stepName;
private IntegerProperty completion;
private ArrayList<StepComment> comments;
public ActionStep(String name) {
actionStepID = new SimpleStringProperty();
stepName = new SimpleStringProperty();
dateSet = new SimpleObjectProperty<LocalDate>();
dateFinished = new SimpleObjectProperty<LocalDate>();
completion = new SimpleIntegerProperty();
stepName.setValue(name);
}
public void setName(String name) {
stepName.setValue(name);
}
public String getName() {
return stepName.getValue();
}
public StringProperty stepNameProperty() {
return actionStepID;
}
public void setID(String id) {
actionStepID.setValue(id);
}
public String getID() {
return actionStepID.get();
}
public StringProperty actionStepIDProperty() {
return actionStepID;
}
public void setCompletion(int percent) {
if (percent < 0 || percent > 100)
return;
completion.set(percent);
}
public int getCompletion() {
return completion.get();
}
public IntegerProperty completionProperty() {
return completion;
}
public void setDateSet(LocalDate date) {
dateSet.set(date);
}
public LocalDate getDateSet() {
return dateSet.get();
}
public ObjectProperty<LocalDate> dateSetProperty() {
return dateSet;
}
public void setDateFinished(LocalDate date) {
dateFinished.set(date);
}
public LocalDate getDateFinished() {
return dateFinished.get();
}
public ObjectProperty<LocalDate> dateFinishedProperty() {
return dateFinished;
}
public String toString() {
return stepNameProperty().get();
}
}
My ListView uses an ObservableList as well.
#FXML
private ListView<ActionStep> actionStepsListView;
private ObservableList<ActionStep> listOfSteps;
listOfSteps = FXCollections.observableArrayList();
actionStepsListView.setItems(listOfSteps);
if (plan != null) {
ArrayList<ActionStep> arrayOfSteps = plan.getStepsArrayList();
for (int i = 0; i < arrayOfSteps.size(); i++)
listOfSteps.add(arrayOfSteps.get(i));
} else
plan = new ActionPlan();
How come changes made to the ObservableList do not reflect themselves in the ListView? I noticed that the ListView called upon every object's toString() to display their values in the ListView, rather than binding it to their Properties.
What am I doing wrong? Am I supposed to override a cell factory or something?
Note that you're trying to do something more complex with the cells in your ListView than you were with the cells in the TableView. In the TableView, the objects displayed in the cells were changing, so it was easy for the cells to observe this. In the ListView, you want the cells to notice when properties that belong to the objects displayed in the cells change; this is one further step removed, so you have to do a bit of extra coding (though not much, as you'll see).
You could create a custom cell factory to bind to the stepNameProperty(), but it's tricky (you have to make sure to unbind/remove listeners from old items in the updateItem() method).
The easier way, though, which isn't well documented is to use an ObservableList with an extractor defined.
First, fix your method names: you have some weird mismatches in the code you posted. The getX/setX/xProperty method names should all match correctly. I.e. instead of
public void setName(String name) {
stepName.setValue(name);
}
public String getName() {
return stepName.getValue();
}
public StringProperty stepNameProperty() {
return actionStepID;
}
you should have
public final void setName(String name) {
stepName.setValue(name);
}
public final String getName() {
return stepName.getValue();
}
public StringProperty nameProperty() {
return stepName;
}
and similarly for the other property accessor methods. (Obviously, the names of the fields can be anything you like, as they're private.) Making the get/set methods final is good practice.
Then, create the list with an extractor. The extractor is a function that maps each element in the list to an array of Observables which the list will observe. If those values change, it will fire list updates to the list's observers. Since your ActionStep's toString() method references the nameProperty(), I assume you want the ListView to update if the nameProperty() changes. So you want to do
listOfSteps = FXCollections.observableArrayList(
actionStep -> new Observable[] { actionStep.nameProperty() } // the "extractor"
);
actionStepsListView.setItems(listOfSteps);
Note that in earlier versions of JavaFX 2.2 the ListView did not properly observe the list for update events; this was fixed (if I remember correctly) shortly prior to the release of Java 8. (Since you tagged the question JavaFX8, I assume you're using Java 8 and so you should be fine here.)
If you are not using Java 8, you can use the following (equivalent but more verbose) code:
listOfSteps = FXCollections.observableArrayList(
new Callback<ActionStep, Observable[]>() {
#Override
public Observable[] call(ActionStep actionStep) {
return new Observable[] { actionStep.nameProperty() } ;
}
});
actionStepListView.setItems(listOfSteps);
Here is sample how make listview with custom objects:
public class JavaFX_ListView extends Application {
class MyObject {
String day;
int number;
MyObject(String d, int n) {
day = d;
number = n;
}
String getDay() {
return day;
}
int getNumber() {
return number;
}
#Override
public String toString() {
return number + " " + day;
}
}
ObservableList<MyObject> myList;
// Create dummy list of MyObject
private void prepareMyList() {
myList = FXCollections.observableArrayList();
myList.add(new MyObject("Sunday", 50));
myList.add(new MyObject("Monday", 60));
myList.add(new MyObject("Tuesday", 20));
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("sample");
prepareMyList();
ListView<MyObject> listView = new ListView<>();
listView.setItems(myList);
Pane root = new Pane();
root.getChildren().add(listView);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
// testing
Timer timer = new Timer();
timer.schedule(new UpdateListTask(), 1000, 1000);
}
public static void main(String[] args) {
launch(args);
}
// testing
public class UpdateListTask extends TimerTask {
#Override
public void run() {
Platform.runLater(new Runnable() {
#Override
public void run() {
myList.add(new MyObject("sample", Calendar.getInstance()
.getTime().getSeconds()));
}
});
}
}
}
I need some help, even my case is simple.
But i can't understand why the check box in the tableview is not geting the value.
I have get the example from the javafx ensemble
I have a class
public class ReservationObj {
private BooleanProperty tcheck;
private StringProperty tname;
private StringProperty tstatus;
private int tser;
public ReservationObj(boolean tcheck, String lname , String lBStatus, int serialinVector) {
this.tcheck = new SimpleBooleanProperty(tcheck);
this.tname = new SimpleStringProperty(lname);
this.tstatus = new SimpleStringProperty(lBStatus);
this.tser = serialinVector;
this.tcheck.addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
System.out.println("The check Box is: " + t1);
}
});
}
public BooleanProperty getTcheck() {return tcheck;}
public String getTname() {return tname.getValue() ;}
public void setTname(String tname) {this.tname.set(tname);}
public String getTstatus() {return tstatus.getValue() ;}
public void setTstatus(String tstatus) {this.tstatus.set(tstatus);}
public int getTser() {return tser;}
public void setTser(int tser) { this.tser = tser;}
}
And also i have the.
public Parent createContent() {
final ObservableList<ReservationObj> ReservationList = FXCollections.observableArrayList(
new ReservationObj(true, "aaaaaaaa", "bbbbbbbbb", 1));
TableColumn RCheckCol = new TableColumn<ReservationObj, Boolean>();
RCheckCol.setCellValueFactory(new PropertyValueFactory("tcheck"));
RCheckCol.setText("aaa");
RCheckCol.setCellFactory(new Callback<TableColumn<ReservationObj, Boolean>, TableCell<ReservationObj, Boolean>>() {
public TableCell<ReservationObj, Boolean> call(TableColumn<ReservationObj, Boolean> p) {
return new CheckBoxTableCell<ReservationObj, Boolean>();
}
});
TableColumn RNameCol = new TableColumn();
RNameCol.setCellValueFactory(new PropertyValueFactory("tname"));
RNameCol.setText("bbbb");
TableColumn RAgeCol = new TableColumn();
RAgeCol.setCellValueFactory(new PropertyValueFactory("tstatus"));
RAgeCol.setText("cccc");
TableView AAView = new TableView();
AAView.setItems(ReservationList);
AAView.setEditable(true);
AAView.getColumns().addAll(RCheckCol,RNameCol,RAgeCol);
return AAView;
}
And when simple .
#Override
public void start(Stage primaryStage) {
primaryStage.setScene(new Scene(createContent()));
primaryStage.show();
}
The columns of the tableview are getting the values except from the first “Checkbox”.
Also the listener in the checkbox is not working.
I really don’t understand what I have done wrong. Because I get the example from the ensemble.
Thanks for every idea and any solution.
Elias
Your ReservationObj class doesn’t respect JavaFX Properties convention in naming methods.
If you want to bind the RCheckCol with the tcheck BooleanProperty in :
RCheckCol.setCellValueFactory(new PropertyValueFactory("tcheck"));
You have to provide a tcheckProperty method in your model class:
public BooleanProperty tcheckProperty() {
return tcheck;
}
As an example of a valid JavaFX Bean:
public class Person {
private StringProperty name = new SimpleStringProperty("");
public Person(String name) {
this.name.setValue(name);
}
public String getName() {
return name.getValue();
}
public void setName(String name) {
this.name.setValue(name);
}
public StringProperty nameProperty() {
return name;
}
}
I have two classes: one called Student and the other one called Course. I would like to make a simulation for a simple registration system.
My Student class part has the following form:
class Student
{
private String id,
private Course[] listOfCourses;
private int numCourse;
//accesing methods
public registration(Course course){
listOfCourses[numCourse]=course;
numCourse++;
}
public Course[] getCourse(){
return listOfCourses;
}
}
and the Course class has the following form:
class Course
{
String id, String courseName;
//constructor
//accesing methods
}
I would like that by pressing a buttom in a form made in Java Swing, to display the contents of the courses registered by one specific student into a jTable. I have tried the following, but with no results at all:
Student e=new Student();
Course d[]=new Course[4];
d=e.getCourses(); //to receive the array of Courses from the Student class
for (int i=0;i<d.length;i++){
jTable2.setValueAt(estLista[i].getName(), i, 0);
}
how I can do that? I mean there is a way in which I could get the contents of the array, that is stored in the Course class, into the ActionEvent of the button?
From the code you have provided I believe there atleast one reason why you are not getting the courses.. because it is not set in registration process:) (Also the syntax is not correct unless you have a registration class?) This might not be a complete solution but it corrects one of the problem
public void registration(Course course){
// listOfCourses[numCourse];
listOfCourses[numCourse]=course;
numCourse++;
}
Ok, it is not too clear for me yet, but I will put some code and tell me if it helps you.
Note: Not tested
For Student (sorry I prefer to use lists instead of arrays):
public class Student {
private String id;
private List<Course> takenCourses;
public void registration(Course course){
if (this.takenCourses != null) {
takenCourses.add(course);
} else {
System.err.println("an array has not been specified.");
}
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Course> getTakenCourses() {
return takenCourses;
}
public void setTakenCourses(List<Course> takenCourses) {
this.takenCourses = takenCourses;
}
For course:
public class Course {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
For your UI, I just created a "simulation" of UI, I assume you have implemented something more complete... I assume you have intialized the components as global variables for your frame or panel or at least you have methods to get them.
public class UIHelper extends JFrame {
Student student = new Student();
JButton btnAction;
JTable myTable;
public UIHelper() {
//Methods for creating UI
//.
//.
//.
student.setId("stackoverflowed");
student.setTakenCourses(new ArrayList<Course>());
btnAction = new JButton("Action!");
//Methods of the JButton (...)
btnAction.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Now just process since student is a global variable (you can set it static as well) but it shouldn't be a good practice at all
for (Course course : student.getTakenCourses()) {
System.out.println(course.getName());
//Add the element to your table.
}
}
});
}
public static void main(String[] args) {
//Assume this is your UI
new UIHelper();
}
Hope I give you an idea, best regards.