I am creating a JavaFXML application and I need to have these classes there: ListOfAllEvents, Events and Instructors. ListOfAllEvents has an ArrayList of Events, and each Event has an ArrayList of Instructors.
Now, clicking on buttons and using methods for creating instances I first create several Instructors and add them to the ArrayList CurrentInstructors, then I create an instance of Event, assign the list of instructors to it and then I would like to add my new Event to the ArrayList CurrentEvents.
My problem is, CurrentEvents does add only one Event, and when I call the method for creating new Event for second time, the second event replaces the first one, even though my CurrentInstructors work correctly.
Can you help me? I am a beginner at Java, so I'll be thankful for every piece of advice.
My code:
public class FXMLDocumentController implements Initializable {
(...)
private ArrayList<Instructor> CurrentInstructors = new ArrayList<Instructor>();
private ArrayList<Event> CurrentEvents = new ArrayList<Event>();
#FXML
private void AddInstructor_Click(ActionEvent event) {
TextInputDialog dialog = new TextInputDialog("");
Optional<String> result = dialog.showAndWait();
if (result.isPresent()){
Instructor newInstructor = new Instructor(result.get());
CurrentInstructors.add(newInstructor);
}
}
private void NewEvent () {
Event newEvent = new Event(EventName.getText());
//this is the problematic row:
CurrentEvents.add(newEvent);
newEvent.setInstructors(CurrentInstructors);
CurrentInstructors.clear();
}
(...)
}
Instructor class:
public class Instructor {
private String name;
public String getName() {
return name;
}
public Instructor(String name){
this.name = name;
}
}
Event Class:
public class Event {
private String name;
private ArrayList<Instructor> Instructors = new ArrayList<Instructor>();
public Event(String name){
this.name = name;
}
//getters, setters
}
You only have one list which you are setting, then immediately emptying.
newEvent.setInstructors(CurrentInstructors);
CurrentInstructors.clear(); // This clears the list just set to newEvent
Since Java is pass-by-value, you have multiple references to a single List object
If you want each new event to hold it's own list, you need to explicitly make new ArrayList<>() each newEvent object made, then add to that, and call setInstructors
For example,
private void newEvent(String name) {
Event newEvent = new Event(name);
// Copy the list
List<Instructor> instructors = new ArrayList<>(currentInstructors);
// Set that list
newEvent.setInstructors(instructors);
currentEvents.add(newEvent);
// Now clearing this list won't clear the newEvent list
currentInstructors.clear();
}
Related
I have this code to create a class User
public class User {
private String name;
private ArrayList<User> owners = new ArrayList<>();
public User(String name, ArrayList<User> owners) {
this.name = name;
this.owners = owners;
}
public String getName() {
return name;
}
public void addOwner(User owner) {
owners.add(owner);
}
If i create an instance of this class with
User jhil = new User(name, new ArrayList<>());
What do i do to add a string element to the arraylist
I've tried with the addOwner method with
jhil.addOwner(jhilsara);
but i get a the method addOwner(String) is undefined for the type User error
I've also tried with the ArrayList add method
jhil.add(jhilsara);
But that doesn't work either.
So my question is what do i need to do in order to add something to the arraylist of an instanced of my class User
You have your ArrayList set to contain objects of the User class, not Strings. Change the declaration of it to:
private ArrayList<String> owners = new ArrayList<>();
Then, you also have to change addOwner to:
public void addOwner(String owner) {
owners.add(owner);
}
For some reasons, I need a new object to wrap the data I get from other API.
The problem I faced was that no idea to handle recursive field from the original object.
Here is the sample code:
//original object
public class Resource{
private String name;
private String content;
private Integer type;
private List<Resource> children = new LinkedList();
public void addChildrenResource(Resource children) {
this.children.add(children);
}
//getters&setters...
}
//the object try to convert
public class Menu{
private String name;
private String url;
private Integer type;
private List<Menu> subMenu = new LinkedList();
public void addChildrenResource(Menu subMenu) {
this.children.add(subMenu);
}
//getters&setters...
}
The implementation I did that I have no idea to do with recursive field...
Here is my code..
List<Resource> resources = rpcService.getResources();
//Here I can't handle the subMenu or children part..
List<Menu> menus = resources.stream().map(r -> new Menu(r.getName(),
r.getContent(), r.getType())).collect(Collectors.toList());
The recursion may be many layers, so how can I convert it with recursive field?
Note: The Resource class is from another module so I can't change that, for naming problem I must convert it.
We don't have to solve it by Stream(), just find a way to figure it out.
You need make a method and call this method recursively:
public static List<Menu> convert(List<Resource> resources) {
return resources == null ? null :
resources.stream()
.map(r -> new Menu(r.getName(), r.getContent(), r.getType(), convert(r.getChildren)))
.collect(Collectors.toList());
}
I'm trying to populate a JComboBox with object names. The objects are of Category type and are stored in an ArrayList (named categoryList) in the Category class.
Here is the content of the Category class:
public class Category {
private static String catName;
private static List<Category> categoryList;
public static void addToCatList(String str)
{
Category cat = new Category();
Category.setCatName(str);
categoryList.add(cat);
}
public static List<Category> getCatList()
{
return categoryList;
}
public static String getCatName()
{
return catName;
}
public static void setCatName(String catName)
{
Category.catName = catName;
}
#Override
public String toString()
{
return catName;
}
}
Here is the code that populates the JCombobox (method name: populateComboBox()):
List<Category> catList = new ArrayList<Category>();
catList = Category.getCatList();
Category list[] = new Category[catList.size()];
list = catList.toArray(list);
for(int i = 0; i <list.length; i++)
{
selectCatComboBox.addItem(list[i].getCatName());
}
addItemDialog.setVisible(true);
When I populate the ArrayList with 2 objects, named Obj1 and Obj2, I get the following problems:
When populateComboBox() is invoked, the combo box only displays the second object i.e. it only displays Obj2. The expected display was Obj1, Obj2.
Since it only displays Obj2. When populateComboBox() is invoked twice, the combo box displays two Obj2. When invoked three times it displays three Obj2. i.e. the number of times the method gets invoked, the number of times Obj2 gets displayed in the combo box.
Should the categoryList ArrayList be inside the Category class? or should it be inside the control class? I'm a bit confused with this one.
Your problem is that your design is broken. Category's catName name field is static and so only one object exists for the entire class. If you change it, you change it class wide. This is why Obj1 and Obj2 (bad names for variables by the way) share the same name and display the same name.
This class should be broken into two classes, one say called Category that has no static fields, no List fields, has private instance fields, constructor(s), public methods, and another, perhaps called Categories, that holds a non-static ArrayList<Category>, with the addCategory(...) and such methods. Fix this first before concerning yourself with GUI, else you'll be building your house on a very shaky foundation. Whenever you create a static field, always ask yourself why you're doing this, and strongly consider seeing if you can make it instance instead.
First off, I wouldn't have a POJO (Plain Old Java Object) that contains a List of itself. Also, the key word "static" means you can have only one of the variable across all instances of an object.
public class Category {
private String name = null; // I always like to initialize my variables
public Category() {
// empty constructor method, but I like to have a no argument constructor
}
public Category(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return catName;
}
}
List<Category> catList = new ArrayList<>();
catList.add(new Category("Category 1"));
catList.add(new Category("Category 2"));
for (Category category : catList) {
selectCatComboBox.addItem(category.getName());
}
addItemDialog.setVisible(true);
In this project the user must enter 1 or 2 hospitals but not 3 or more. So the program starts and I display a menu. If the user presses 1 he must enter a hospital(name and department). After this the program displays the menu again and the user can choose to insert another hospital.
But after that, if I choose to insert another one (which is not permitted) the program accepts it. It seems that every time InsertHospitals() is called from the main class, the value of numberofhospitals (which is a counter counting how many hospitals I entered) equals 0.
public class Hospital {
private String Name, Departments;
private char flag;
private int numberofhospitals;
private Hospital[] ListOfHospitals;
//private Patient[] ListOfPatiens;
//private Doctor[] ListOfDoctors;
//private Examination[] ListOfExaminations;
//private Folder[] ListOfFolders;
public Hospital(String Name, String Departments)
{
this.Name=Name;
this.Departments=Departments;
}
public Hospital()
{
ListOfHospitals = new Hospital[2];
//ListOfPatiens = new Patient[100];
//ListOfDoctors = new Doctor[100];
//ListOfExaminations = new Examination[100];
//ListOfFolders = new Folder[100];
}
public String getName()
{
return Name;
}
public void setname(String Name)
{
this.Name=Name;
}
public String getDepartments()
{
return Departments;
}
public void setdepartments(String Departments)
{
this.Departments=Departments;
}
public void InsertHospitals()
{
if(numberofhospitals==2)
{
System.out.println("You can give only two hospitals!");
}
else
{
String temp = sir.readString("Hospital's Name:");
Name=temp;
String temp1 = sir.readString("Hospital's departments:");
Departments=temp1;
Hospital hospital = new Hospital(Name, Departments);
ListOfHospitals[numberofhospitals]=hospital;
numberofhospitals=numberofhospitals+1;
}
}
}
Your misunderstanding something, the list of hospitals (as mentioned) should not be inside your hospital class. You have to consider your hospital class as a blueprint you are using in your application.
Which means that you need to have a list of hospitals, as a list inside your other application class (which runs the application) and the InsertHospitals method should not be in your hospital class either obviously.
As you add a new hospital in your program, you create a new hospital object and add it to the list of hospitals (fx an arraylist) your keeping as a field value.
Also posssibly make a new constructor with parameters in the hospital class so you can insert the values outside of the class.
Something like this fx.
public class MainApp {
private ArrayList<Hospital> hospitalList;
public static void main(String[] args) {
// Initialize or load it from a file or whatever here.
hospitalList = new ArrayList<Hospital>();
// your code here...
}
public void insertHospital(<insert parameters here to create a hospital>) {
Hospital newHospital = new Hospital(<insert params with new constructor>);
hospitalList.add(newHospital);
}
}
Whatever your problem, your program completely wrong. In insertHospital() your changing Name and Departments fields, and creating new Hospital with those values. When you print Hospital information all hospitals will have the same value.
I have a choiceBox which represents a list objects. When the name representing one of those objects is changed by another bit of code the name in the drop down list for the choice box does not change. For example if I have a choice box which is made up of list Test objects. The Code for Test is shown below:
class Test {
String name;
public Test(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return name;
}
}
Then have a choice Box as follows:
ChoiceBox<Test> chi = new ChoiceBox<>();
ObservableList<Test> items = FXCollections.observableArrayList();
chi.setItems(items);
items.addAll(new Test("ITEM1"),new Test("ITEM2"),new Test("ITEM3"));
The ChoiceBox will show the list ITEM1, ITEM2 and ITEM3
If I then change the name of one of the items via the following code:
items.get(1).setName("CHANGED");
The ChoiceBox will still show the list ITEM1, ITEM2 and ITEM3. How can I make it so the choiceBox will update and show the list ITEM1, CHANGED and ITEM3?
Just for completeness - in fx2 you are probably stuck with the replace approach as outlined in the other answer. Since fx8, there's a mechanism to tell the list to listen to changes of its contained items (precondition being, of course, that your item has properties and notifies listeners on change):
/** changed item to
* - use property and notify on change
* - not override toString (for visuals, use converter instead)
*/
class Test {
StringProperty name;
public Test(String name) {
setName(name);
}
public StringProperty nameProperty() {
if (name == null) name = new SimpleStringProperty(this, "name");
return name;
}
public void setName(String name) {
nameProperty().set(name);
}
public String getName() {
return nameProperty().get();
}
}
// use in collection with extractor
ObservableList<Test> items = FXCollections.observableList(
e -> new Observable[] {e.nameProperty()} );
items.addAll(...);
choiceBox = new ChoiceBox<>(items);
// tell the choice how to represent the item
StringConverter<Test> converter = new StringConverter<Test>() {
#Override
public String toString(Test album) {
return album != null ? album.getName() : null;
}
#Override
public Test fromString(String string) {
return null;
}
};
choiceBox.setConverter(converter);
I had the same issue in JavaFX 8 (with ComboBox too). I was able to get the same functionality by removing the item then adding a new one at the same location.
Example:
This gets selected item, creates a new item, then calls the replace method:
Channel selected = channelChoiceBox.getSelectionModel().getSelectedItem();
Channel newChan = new Channel("Example", "Channel");
replaceChannel(newChan, selected);
This replaces the selected channel with the new one, effectively editing it:
private void replaceChannel(Channel newChan, Channel oldChan) {
int i = channelChoiceBox.getItems().indexOf(oldChan);
channelChoiceBox.getItems().remove(oldChan);
channelChoiceBox.getItems().add(i, newChan);
channelChoiceBox.setValue(newChan);
}
It's not ideal, but does the job.
Disclaimer: I'm new to Java and programming in general.
Yes. This seems to be issue with JavaFx. I too had faced that. Use ComboBox instead of ChoiceBox that will work.