0

I'm having some issues on using a conditionally assigned value in more than one class. I want to apply the use of a value in one class if and only if a condition is met, then use it in some-other class to add up to a total score. this is my code!

@SuppressWarnings("serial")
public class Beginner extends JPanel {

    static JButton quest;
    Random rand = new Random();

    int n = 10;

    static List <Point> points = new ArrayList<Point> ();

    int scores;
    int fails;

    public Beginner() {

              int radius = 200;
              Point center = new Point (250, 250);

              double angle = Math.toRadians(360 / n);

              points.add(center);

              for (int i = 0; i < n; i++) {
                  double theta = i * angle;

                  int dx = (int) (radius * Math.sin(theta));

                  int dy = (int) (radius * Math.cos(theta));

                  Point p = new Point (center.x + dx , center.y + dy);

                  points.add(p);

              }

              draw (points);
              }

               public void draw (List<Point> points) {

                   JPanel panels = new JPanel();

                   SpringLayout spring = new SpringLayout();

                   int count = 1;
                   for (Point point: points) {

                       quest = new JButton("Question " + count);
                       quest.setForeground(Color.BLACK);
                        Font fonte = new Font("Script MT Bold", Font.PLAIN, 20);
                        quest.setFont(fonte);

                       add (quest);
                       count++;

                       spring.putConstraint(SpringLayout.WEST, quest, point.x, SpringLayout.WEST, panels );

                       spring.putConstraint(SpringLayout.NORTH, quest, point.y, SpringLayout.NORTH, panels );

                       setLayout(spring);

                       panels.setOpaque(false);
                       panels.setVisible(true);
                       panels.setLocation(5,5);

                       add(panels);

                        quest.addActionListener(new java.awt.event.ActionListener(){
                            @Override
                            public void actionPerformed (ActionEvent p) {   

                                if (point.equals(points.get(0))) {

                                    new Quest1();

                                    JButton source = (JButton) p.getSource();
                                  source.setEnabled(false);
                                  source.setBackground(Color.GREEN);

                                }   
                               else if (point.equals(points.get(1))) {

                                    new Quest2();

                                     JButton source = (JButton) p.getSource();
                                        source.setEnabled(false);
                                        source.setBackground(Color.GREEN);
                                                        }
                               else if (point.equals(points.get(2))) {

                                       new Quest3();

                                   JButton source = (JButton) p.getSource();
                                  source.setEnabled(false);
                                  source.setBackground(Color.GREEN);

                                                       }
                             else if (point.equals(points.get(3))) {

                                    new Quest4();

                                    JButton source = (JButton) p.getSource();
                                   source.setEnabled(false);
                                   source.setBackground(Color.GREEN);
            }

            else if (point.equals(points.get(4))) {

                new Quest5();

                JButton source = (JButton) p.getSource();
              source.setEnabled(false);
              source.setBackground(Color.GREEN);
                                    }

Now, this is what my first called-up class (named Quest1) looks like

    public class Quest1 {
        //sound files to be shuffled and played!
        String [] word = { "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/audio.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/bomb.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/baby.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/gym.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/hearing.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/goal.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/manifest.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/mountain.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/market.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/debate.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/election.wav",
                "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/number.wav",
        };
        //matching strings for each file
        String [] words = { "Audio", "Bomb", "Baby", "Gym", "Hearing", "Goal", "Manifest","Mountain", "Market", "Debate", "Election", "Number" };

        Random rand = new Random();
        int random = rand.nextInt(word.length);
        String temp = word[random];

        int scores;
        int fails;


        public Quest1 () {

           //announcing the JComponents to be used
            JFrame frame =  new JFrame ();
            JButton click = new JButton("Play");
            JTextField type = new JTextField(15);
            JLabel pic = new JLabel(new ImageIcon("C:\\Users\\HP\\Desktop\\Sample pics\\1.png"));
            JButton score = new JButton ("Check My Answer");
            JPanel cont = new JPanel ();

            //set up frame properties
            frame.getContentPane().setBackground(Color.WHITE);
            frame.setLayout(new FlowLayout());
            frame.setUndecorated(true);                             
            frame.setResizable(false);
            frame.setSize(500,500);
            frame.setLocationRelativeTo(null);
            frame.add(cont, BorderLayout.CENTER);
            frame.getRootPane().setWindowDecorationStyle(JRootPane.NONE);
           frame.setVisible(true);

           //setting layout of JPanel
            cont.setLayout(new GridBagLayout());
            cont.setOpaque(false);
            cont.setPreferredSize(new Dimension(500,500));
            cont.setLocation(100, 50);
            GridBagConstraints g = new GridBagConstraints();
            g.anchor = GridBagConstraints.WEST;
            g.gridx = 4;
            g.gridy = 2;
            g.gridwidth = 2;
            g.insets = new Insets (70, 2, 2, 2);
            cont.add(pic , g);


            g.anchor = GridBagConstraints.WEST;
            g.gridx = 4;
            g.gridy = 5;
            g.gridwidth = 2;
            g.insets = new Insets (50, 2, 2, 2);
            cont.add(click, g);


            click.addActionListener(new ActionListener(){
                public void actionPerformed (ActionEvent e) {
                        //sound file shuffled and played
                    }
            });
                   g.anchor = GridBagConstraints.EAST;
                   g.gridx = 10;
                   g.gridy = 4;
                   g.gridwidth = 5;
                   g.insets = new Insets(30, 2, 2, 10);
                   Font fonty = new Font("Lucida", Font.PLAIN, 15);
                   type.setFont(fonty);
                   cont.add(type, g);

                   g.anchor = GridBagConstraints.SOUTH;
                   g.gridx = 9;
                   g.gridy = 8;
                   g.gridwidth = 2;
                   g.insets = new Insets(2, 2, 2, 50);
                   cont.add(score, g);

                   score.addActionListener(new ActionListener(){
                       public void actionPerformed (ActionEvent tx) {

                          if (type.getText().equals(words[random])) {

                             //sound file played
                                    scores+= 3;
                                     String a = "Correct!..... The answer is " + words[random];
                              JOptionPane.showMessageDialog(null, a);

                              frame.dispose();
                              return;
                          }

                          else {
                                //sound file played again
                                    fails+=0; 
            // This is where my problem is: The other 10 classes are like 
      //this, I want to get this value and that of scores (depending on the 
      //condition that is met), and add them up in the class beginner! )
                           String a = "Sorry, The Answer is " + words[random];
                           JOptionPane.showMessageDialog(null, a);

            frame.dispose();
                              }   
                          }  
                       });
                  //sound file played
        }

    }
thePatriarch
  • 97
  • 1
  • 12

1 Answers1

1

Your score and fail are local variables within the listener event. If you create an instance variable in your help class you can update them within the listener but they will persist as long as your program is running and then can be passed into more classes as constructor parameter for whatever purpose you may need.

public class help extends JFrame {
        JPanel hold = new JPanel ();
        JTextField enter = new JTextField(10);
        JButton check = new JButton ("Check answer");
        JButton quest = new JButton ("See question");
        JLabel lunch = new JLabel ("Who is the current President of the United States?");

        //Add fields you want to track here
        int scores;
        int fails;

     public help () {

Then inside your listeners

     scores += 3; //track them anyway you want

Update:

So it looks like you want to pass the score/fails from your Quest class back to your original class. You can do this by adding some accessor methods for scores and fails to your Quest class.

public int getScores(){ 
       return scores;
}

public int getFails(){
       return fails;
}

This will allow you get retrieve the values when you need them. You'd simply call them on the Quest object you made. However there's another problem...

new Quest1(); 

The quest needs to be stored in a variable like scores and fails or else it will get thrown away by the garbage collector. Add a variable that will hold the current Quest on top then swap them out when you switch quests.

Quest1 q1;
...
...
q1 = new Quest1();
...
...
scores = q1.getScores();
fails = q1.getFails();

Update: Button Flags

You can add flags to check if things have occurred by adding booleans variables. In this case you can have Quest1-5 flags in your Beginner class. When the user clicks on the class you can change it to true, then check if all of them have been done.

boolean Q1 = false;
boolean Q2 = false;
...

if (point.equals(points.get(0))) { // User clicks quest 1
    Q1 = true;
    ...

...
if (checkQuests()){
    //do stuff if all buttons are clicked
}

...

public boolean checkQuests(){ //cleaner if you use arrays
   if(Q1 == false || Q2 == false || ... Q5== false){
      return false;
   }
   else{
      return true;
   }
}

Update: Call back function

When working GUIs and listeners, not all actions happen in the sequence you want it to. GUIs and events happen on their own thread and often you want to trigger an event at the end of another. You can do this by utilize a call back function.

What is a callback function?

Here's how you can implement one in your program.

Inside your Quests include an interface and variable for an interface:

public class Quest{

    CallBack cb;

    interface CallBack{
        public void callBack();
    }

    //add some way to set the call back, such as setter (or use constructor)
    public void setCB(CallBack cb){ this.cb = cb;}

  //Inside the action listener of your quest doing something
  ...
    cb.callBack(); //call the callback method when you are done and want to do your check (it calls the beginner class back)

Inside your Beginner class:

//When creating a quest 
  Q1 = new Quest1();
  Q1.setCB(new CallBack{
      public void callBack(){
          CheckQuests(); //this tells the program what to do when it hears back from Q1
      }
  }

What ends up happening is when the code of Q1 finishes, it calls the callBack() method (it could be any time but in your case call it when you're done with your logic).

The beginner class passes in code that tells Q1 what it should do when that method is called.

Community
  • 1
  • 1
Brion
  • 746
  • 3
  • 10
  • Your code logic sounds fine....but I have some difficulty applying it!....your third code snippet reads otherclass.process(scores, fails) which when applied...reads error! I had already created scores and fails in each class, but its not working! – thePatriarch Sep 29 '16 at 17:10
  • 1
    Yes, it's because I don't know the name and methods you have in the classes you want to pass your information to. You need to replace "otherclass" with whatever class you're trying to send the information to, and "process" can be replaced with whatever method is going to be using the score and fail values you want to pass around. – Brion Sep 29 '16 at 17:13
  • 1
    Yes. Update it with as much information as you need and I will update my answer to better assist you. – Brion Sep 29 '16 at 17:24
  • Edited Question @Brion – thePatriarch Sep 29 '16 at 17:43
  • Thank your very much @Brion...however, there is another problem!...how do I detect when all the buttons have been clicked, that is, when all if statements have been implemented? – thePatriarch Oct 01 '16 at 15:25
  • 1
    @Presh_K7 Normally for games, they will have something call "flags", this is a variable that can be used to check if a condition is met. In this case you can create boolean flags that specify if a button has been clicked. This can belong to the button itself or as a separate variable, then make a method that will will loop through all the buttons and checks to see if all the flags are on. – Brion Oct 03 '16 at 13:23
  • Can you add some code please....as an update...it will be really helpful! – thePatriarch Oct 03 '16 at 13:27
  • Thanks! I'll try it and get back to you shortly!! – thePatriarch Oct 03 '16 at 13:45
  • Its working....but the if (checkQuests()) {} runs immeadiately I click the last button.... I want to make it in such a way that the last button must have finished its action before the if (checkQuests()){} method runs....! – thePatriarch Oct 04 '16 at 15:37
  • 1
    You'll have to place them at logical points in the program. One such workaround is to call your checkQuest() trigger after each quest has completed. (Maybe inside your listeners) – Brion Oct 04 '16 at 18:05
  • Yes, that is what I did, but in this case, the checkQuest() trigger runs immeadiately after all the buttons have been clicked, not after the buttons designated action has been completed...in other words, it runs at the same time as the action placed on the last button – thePatriarch Oct 04 '16 at 19:57
  • Ok, you'll have to implement something called a "call back function". It allows the button to perform their actions then tell you when they're done with their code. I'll update my answer to include it. – Brion Oct 04 '16 at 20:23
  • Now, your code logic is kinda fine, but each time I try to add the line public setCB(Callback cb){this.cb = cb;}, it returns syntax error, with the IDE stipulating it should be public void and not just public. When I make it so... it doesn't return anything because it is void already! – thePatriarch Oct 06 '16 at 09:22
  • 1
    Sorry, it should be void. I was a typo on my part and I'll fix the error. – Brion Oct 06 '16 at 12:54
  • Maybe you should check the spellings of 'callback' at some points, they seem contradictory @Brion – thePatriarch Oct 10 '16 at 01:47
  • 1
    @Presh_K7 Thanks for pointing those out. I've fixed them to me more consistent. – Brion Oct 10 '16 at 13:30