0

My program is supposed to take words and definitions from the user and display them like flash cards. I've got all the words sorted out into classes and such and now all I need to do is make it so that when a button is pressed by my application, the controller class will execute a method that will go through the arraylist of Card classes and display the word and eventually the definition.

My issue is that I have an object of the reader class which contains all the cards, and I want to be able to call a random card in the getWordClick method. I don't know how I can use that object in another class.

public class Main extends Application{


@Override
public void start(Stage primaryStage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("Scene.fxml"));
    primaryStage.setTitle("FlashCards");

    Scene scene = new Scene(root, 600, 400, Color.GREY);
    primaryStage.setScene(scene);
    primaryStage.show();
}


public static void main (String[] args){

    Reader r = new Reader();

    //Initialises the Arraylist and reads the file adding them to arraylist
    ArrayList<String> wordList = r.getWordList();
    r.OpenFile();
    r.readFile(wordList);
    r.closeFile();

    //Initialises the Definitions Arraylist and reads the file adding them
    ArrayList<String> definitionList = r.getDefinitionsList();
    r.OpenFile();
    r.readFile(definitionList);
    r.closeFile();

    /* IGNORE IS FOR TESTING PURPOSES
    //Wordlist is printed
    for (String i : wordList){
        System.out.println(i);
    }

    //Definitions list is printed
    for (String i : definitionList){
        System.out.println(i);
    } */

    //Card for each word and def is made
    ArrayList<Card> c = r.getCardList();
    Main m = new Main();
    r.cardSetter(m.addTerms(c, wordList.size(), wordList, definitionList));


    //Loops through and displays the word and defs
    for (Card i : c){
        System.out.printf("%s : %s\n",i.dispWord(),i.dispDef());
    }

    //Displays the window
    launch(args);
}

public ArrayList<Card> addTerms(ArrayList<Card> c, int q, ArrayList<String> word, ArrayList<String> def){
    for (int i = 0; i<q; i++){
        c.add(new Card(word,def,i));
    }
    return c;
}

}

Here is the reader class

public class Reader {

private Scanner x;
private Scanner sc;

//ArrayList to store the words
private ArrayList<String> wordList = new ArrayList<>();
//ArrayList to store the definitions
private ArrayList<String> definitionsList = new ArrayList<>();
//ArrayList to store the cards
private ArrayList<Card> cardList = new ArrayList<>();


//Simple scanner collects user input
public String getFileName(){
    sc = new Scanner(System.in);
    return sc.nextLine();
}

//Method to open the file and throw an exception if failed
public void OpenFile(){
    try{
        x = new Scanner(new File(getFileName()));
    }
    catch (Exception e){
        System.out.println("could not find file");
    }
}

//Assigns each line to a Array
public void readFile(ArrayList<String> e){
    while(x.hasNext()){
        e.add(x.nextLine());
    }
}

//Closes file
public void closeFile(){
    x.close();
}

//Returns the wordlist
public ArrayList<String> getWordList(){
    return wordList;
}

//Returns Definitionlist
public ArrayList<String> getDefinitionsList(){
    return definitionsList;
}

//Returns cardList
public ArrayList<Card> getCardList(){
    return cardList;
}

public void cardSetter(ArrayList<Card> c){
    c = cardList;
}
}

Here is the card class

public class Card {

private String word;
private String definition;

public Card(ArrayList<String> Word,ArrayList<String> Definition, int i){
    word = Word.get(i);
    definition = Definition.get(i);
}

public String dispWord(){
    return word;
}

public String dispDef(){
    return definition;
}

}

Finally here is the controller

public class Controller {

Random rand = new Random();
private int Random;
//Makes the rand instance variable int so that the def class can use it

public Button wordBox;
public Label defBox;

public void getWordClick(){

}

public void goExit(){

}

public void goRand(){

}

public void getDefClick(){


}

public void goNext(){

}

public void goPrev(){

}

}

Sorry I know its really long but the code is just there for reference, my main concern is how to i get the ArrayList<Card> from Reader r so that I can use it in the controller in the getWordClick() method. Literally any help is appreciated, I just need someone to throw me in the right direction as I am stuck.

Update: I now edited the controller class so it looks like this public class Controller {

Random rand = new Random();
private int Random;
//Makes the rand instance variable int so that the def class can use it

public Button wordBox;
public Label defBox;


private Reader mReader = null;

public Controller(Reader reader){
    this.mReader = reader;
}

public Reader getReader(){
    return this.mReader;
}

public void getWordClick(){
    getReader();
}

public void goExit(){

}

public void goRand(){

}

public void getDefClick(){


}

public void goNext(){

}

public void goPrev(){

}

}

But now the concern is that when the fxml file runs and looks for a controller how will it make an object itself or will it use an object I have created, because I made an object where i added the reader in as a constructor. However I do not know how the fxml file will use it for event handling.

  • I don't think I understand the question. You already have a method `getCardList` to retrieve the list of cards for a `Reader`. Can't you just have an instance variable to store the `Reader` and then call `reader.getCardList()` in `getWordClick`? – sprinter Dec 22 '15 at 23:23
  • Is your problem manipulating List ? see one tuto: http://examples.javacodegeeks.com/core-java/util/arraylist/arraylist-in-java-example-how-to-use-arraylist/ . Otherwise, you can pass an manage it like any object variable. – guillaume girod-vitouchkina Dec 22 '15 at 23:37

2 Answers2

0

Well I see a simple way although I don't know how memory efficient it is:

Declare in your controller class

private Reader mReader = null;

And add a constructor

public Controller(Reader reader)
{
     this.mReader = reader;
}
public Reader getReader()
{
     return this.mReader;
}

So the difference in your declaration of the Controller class is that you pass the reference of the reader object to the reference of that class. It is a concept known as encapsulation.

EDIT:

Classes that can provide constructors are powerful tools. Polymorphism and the like are well researched topics with a lot of practical application with regards to development. I was also going to recommend links to check out but I need to do more research myself :p

A quick google of polymorphism java will give you more than adequate surknowledge!

EDIT2 CODE REPRISE:

Reader

public class Reader {

private Scanner x;
private Scanner sc;

//ArrayList to store the words
private ArrayList<String> readContent = new ArrayList<>();
private String filename = "";

public Reader()
{
    //if every time I want a new reader, I want to read user input
    //this.filename = readUserInput();
    //If I want to read indefinitely which I will do for now
    readIndefinitely();
}

//This will continuously read until the user enters a valid file name
public void readIndefinitely()
{
    while (!OpenFile())
    {
        filename = readUserInput();
    }
}
public Reader(String fileIWantToRead)
{
    this.filename = fileIWantToRead;
}

public String readUserInput()
{
    if (sc != null)
    {
       sc.close();
       sc = null;
    }
    sc = new Scanner(System.in);
    return sc.nextLine();
}
//Simple scanner collects user input
public String getFileName(){
    return filename;
}

//Method to open the file and throw an exception if failed
public boolean OpenFile(){
    try{
        //assume we already know the filename
        x = new Scanner(new File(filename));
    }
    catch (Exception e){
        System.out.println("could not find file");
        return false;
    }
    return true;
}

//Assigns each line to a Array
public ArrayList<String> readFile(){
OpenFile();
try
{
    readContent.clear();
    while(x.hasNext()){
        readContent.add(x.nextLine());
    }
}
catch(Exception e)
{
    e.printStackTrace();
}
closeFile();
return readContent;
}

//Closes file
public void closeFile(){
    x.close();
}
public String getReadContent()
{
   return readContent;
}
public void clearReadContent()
{
   readContent.clear();
}
} //end class

Card Class

public class Card {
    private String word;
    private String definition;

    public Card(String word, String definition){
        this.word = word;
        this.definition = definition
    }

    public String getWord(){
        return word;
    }

    public String getDefinition(){
    return definition;
    }

}

Main Class

public class Main extends Application{

    private ArrayList<Card> mCards = new ArrayList<>();
    public Main(ArrayList<Card> cards)
    {
        this.mCards = cards;
        //do what is required to get the cards to the controller either here or start
    }

    @Override
public void start(Stage primaryStage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("Scene.fxml"));
    primaryStage.setTitle("FlashCards");

    Scene scene = new Scene(root, 600, 400, Color.GREY);
    primaryStage.setScene(scene);
    primaryStage.show();
}

    public static void main (String[] args){

        Reader wordReader = new Reader();
        Reader definitionReader = new Reader();
        wordReader.readFile();
        definitionReader.readFile();

        /* IGNORE IS FOR TESTING PURPOSES
        //Wordlist is printed
        for (String i : wordList){
            System.out.println(i);
        }

        //Definitions list is printed
        for (String i : definitionList){
            System.out.println(i);
        } */

        //if we know that both the words and definitions are the same size, we can make cards
        ArrayList<Card> c = makeCards(wordReader.getReadContent(), definitionReader.getReadContent());
    //Loops through and displays the word and defs
        for (Card i : c){
            System.out.printf("%s : %s\n",i.dispWord(),i.dispDef());
        }

        Main m = new Main(c);
    //Displays the window
        //Not sure how FXMLLoader and this functions as I don't work too much with java but if you pass a reference to main in you'd be good to go
        launch(args);
    }

public ArrayList<Card> makeCards(ArrayList<String> word, ArrayList<String> def){
    ArrayList<Card> cards = new ArrayList<>();
    for (int i = 0; i<word.size(); i++){
        c.add(new Card(word.get(i),def.get(i)));
    }
    return c;
}
}

Controller:

public class Controller {
    Random rand = new Random();
    private int Random;
    //Makes the rand instance variable int so that the def class can use it
    private int position = 0;
    public Button wordBox;
    public Label defBox;
    //instead of passing in an entire reader we just pass in cards (oops!)
    private ArrayList<Card> mCards = new ArrayList<>();

    public Controller(ArrayList<Card> cards){
        this.mCards = cards;
    }

    public ArrayList<Card> getCards()
    {
        return this.mCards;
    }

    public void goExit(){
        //Exit program
    }

    public void goRand(){
        //nextInt in range is ((max - min) + 1) + min and we want a position that corresponds from 0 to the size of cards

        position = rand.nextInt(cards.size());
        wordBox.setText(cards.get(position).getWord());
        defBox.setText(cards.get(position).getDefinition());
    }

    public void getDefClick(){
        //Call to either cards.get(position).getDefinition() or defBox.getText().toString()

    }

    public void goNext(){
        //because retrieving from cards starts at index 0 the equivalent position will require a +1 and we are looking for the next
        if (cards.size() < position+2)
        {
            position++;
            wordBox.setText(cards.get(position).getWord();
            defBox.setText(cards.get(position).getDefinition();
        }
    }

    public void goPrev(){
        //same concept as above but assume that position is already an acceptable value
        if (position != 0 && !cards.isEmpty())
        {
            position--;
            wordBox.setText(cards.get(position).getWord());
            defBox.setText(cards.get(position).getDefinition());
        }
    }
}
KoalaKoalified
  • 687
  • 4
  • 15
  • Thanks i'll try this out and see how it goes :D – Harsh Sheth Dec 23 '15 at 00:55
  • You're welcome. Post any questions you may have regarding this topic and I'll do my best to answer again. – KoalaKoalified Dec 23 '15 at 00:59
  • So i added what you told me to the controller class and it makes perfect sense because now when the contoller object is made it will take a reader. But the other issue is that when the fxml file looks for a controller will it build an object, and if so where do I declare the object that it will use. Because that is my main concern right now. I know how I can add the reader to the controller class but how do I get the fxml class to use the object i made with the reader within. – Harsh Sheth Dec 23 '15 at 02:30
  • I added more info for you – Harsh Sheth Dec 23 '15 at 02:35
  • thanks for your help but its ok I figured it out another way and i got it to work :D – Harsh Sheth Dec 24 '15 at 21:06
-1

It seems to me like you just need a bit more practice with Object-Oriented Design concepts.

Lets look at this problem logically. You have a Controller class which is used as a way to control the view for a list of Cards. The obvious issue here is that your Controller actually lacks a list of Cards to control, hence, you should add that to the class.

public class Controller {
    // The list of Cards that are being controlled.
    private ArrayList<Card> cards;

    ...
}

Now this simply adds to the abstract idea of a Controller. Obviously, we need a way to specify which list of Cards the Controller should use. Thus, we should create a constructor.

public class Controller {
    // The list of Cards that are being controlled.
    private ArrayList<Card> cards;

    ...

    // A list of cards must be specified when creating a Controller instance.
    public Controller(ArrayList<Card> cards) {
        this.cards = cards;
    }

    ...
}

Alternatively, you can use a mutator method (a.k.a a setter method) to set the list of cards using a concept known as encapsulation, as KoalaKoalified mentioned.

public class Controller {
    // The list of Cards that are being controlled.
    private ArrayList<Card> cards;

    ...

    // Specify a list of cards.
    public void setCards(ArrayList<Card> cards) {
        this.cards = cards;
    }

    ...
}

So now, inside Main, or wherever you are creating an instance of the Controller, you do this:

Controller controller = new Controller(r.getCardList());

or, if you prefer to use the mutator method instead, this:

Controller controller = new Controller();
controller.setCards(r.getCardList());

Now, your Controller class can reference the list of Cards in each of its methods, and it can potentially reused if you have some other source that supplies the list of Cardss.

I would strongly recommend doing some more research on Object-Oriented Design (OOD). Java depends very heavily on this type of design. You seem to have bits and pieces of it scattered around in your program, but you seem to be slightly confused on some of the details and possibly the big picture.

Caleb Rush
  • 512
  • 4
  • 7
  • When the FXML file runs will it use the controller object I created in main to execute methods when I press a button? Because I'm using Java FX to make an application. If I have an event handler inside the controller class will it use the object I created in main to handle the click events? – Harsh Sheth Dec 23 '15 at 00:54
  • Ill try out what u suggested and see how it goes :D Thanks a lot. – Harsh Sheth Dec 23 '15 at 00:55
  • Given the way the OP is loading the FXML, you shouldn't call the `Controller` constructor yourself, as the instance you get cannot possibly be the same instance that is connected to the UI defined by the FXML file. Either show how to set the controller in the `FXMLLoader`, or show how to retrieve the instance it creates. – James_D Dec 23 '15 at 01:27
  • @James_D what can I do to fix this? – Harsh Sheth Dec 23 '15 at 02:06
  • See if http://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml helps – James_D Dec 23 '15 at 02:55