0

As many of you may know, when you have a while loop (or any loop for that matter) when an input method is called, the program stops and waits for input.

e.g.

  while {
      String input = in.readLine();
      int x = 55;  //This will not execute until input has been given a value
      System.out.println (x + x);
      }

Now I am using buttons for input. Is there any way I can do the same thing (halt the program in a loop) with the use of JButton, JPanel, JFrame etc. ?

NOTE: I am also open to use the Runnable () interface if required.

UPDATE: I am using listeners for the button. This is the exact problem.

 public void actionPerformed (ActionEvent x){ string = x.getActionCommand}

 public void someOtherMethod ()
 {

 while (true){
 start ();
 if (string.equals ("exit") break;  // This line will never execute because start() 
    //is always repeating itself.
     }
 }

EDIT: I found a solution (FINALLY!)

this is all that needs to be done....

 string = "";
 while (true){
 if (string.equals ("");
 start ();
 if (string.equals ("exit") break; // I guess I didn't explain the problem too well...
     }

Thank you for everybody's help!

Jimmy Huch
  • 4,400
  • 7
  • 29
  • 34
  • 1
    You need to understand better how GUI's work. You can have a main program doing an infinite loop. However, this should be decoupled from the GUI. The GUI runs in its own thread (the event dispatch thread (EDT)) and your main program should run in some other thread. Of course the main thread and the GUI thread will sometimes have to communicate, but this should be kept to a minimum. There is a standard way to handle this threading with Swing and you should read the tutorial (I know it is quite long and complicated). – toto2 Jun 05 '11 at 14:47
  • @toto is right. Your solution isn't much of a solution. To grasp the problem at hand, you need to break your dependence on a procedural, linearly driven program and learn the paradigm of an *event* driven program. GUIs are almost exclusively event driven. – Mark Peters Jun 05 '11 at 14:51

4 Answers4

2

I think the problem you're having is how to change what the button does depending on what has been entered into the GUI. Remember that with a GUI, the user can interact with any enabled GUI component at any time and in any order. The key is to check the state of the GUI in your button's ActionListener and then altering the behavior of this method depending on this GUI's state. For example if your GUI had three JTextFields, field1, field2, and sumField and a JButton addButton:

   private JTextField field1 = new JTextField(5);
   private JTextField field2 = new JTextField(5);
   private JTextField sumField = new JTextField(5);
   private JButton addButton = new JButton("Add");

And you wanted the addButton to add the numbers in field1 and field2 together and place the results into the sumField, you're obviously not going to want to do any addition if either field is left blank, and so you test for it in the JButton's ActionListener:

  addButton.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
        String text1 = field1.getText().trim();
        String text2 = field2.getText().trim();

        if (text1.isEmpty() || text2.isEmpty()) {
           // data not entered... so return the method and do nothing
           return;
        }

        // if we've reached this point, the user has entered in text and so we handle it

Here's the whole thing:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class WaitForInput extends JPanel {
   private JTextField field1 = new JTextField(5);
   private JTextField field2 = new JTextField(5);
   private JTextField sumField = new JTextField(5);
   private JButton addButton = new JButton("Add");

   public WaitForInput() {
      addButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            String text1 = field1.getText().trim();
            String text2 = field2.getText().trim();

            if (text1.isEmpty() || text2.isEmpty()) {
               // data not entered... so return the method and do nothing
               return;
            }

            try {
               int number1 = Integer.parseInt(field1.getText());
               int number2 = Integer.parseInt(field2.getText());
               int sum = number1 + number2;

               sumField.setText("" + sum);
            } catch (NumberFormatException e1) {
               // TODO: use JOptionPane to send error message

               // clear the fields
               field1.setText("");
               field2.setText("");
            }
         }
      });

      add(field1);
      add(new JLabel("+"));
      add(field2);
      add(new JLabel("="));
      add(sumField);
      add(addButton);
   }

   private static void createAndShowUI() {
      JFrame frame = new JFrame("WaitForInput");
      frame.getContentPane().add(new WaitForInput());
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            createAndShowUI();
         }
      });
   }
}

EDIT 1
Otherwise if you absolutely have to use a loop, then yes, do it in a Runnable and do that in a background Thread. Remember to call Thread.sleep(...) inside of the loop even for a short bit so it doesn't hog the CPU. For example

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class HaltingProblem extends JPanel {
   private static final int PANEL_HEIGHT = 400;
   private static final int PANEL_WIDTH = 600;
   private static final long SLEEP_DELAY = 100;
   private Color[] colors = {Color.red, Color.orange, Color.yellow,
      Color.green, Color.blue, Color.cyan};
   private boolean halt = false;
   private JButton haltButton = new JButton("Halt");
   private int colorIndex = 0;

   public HaltingProblem() {
      setBackground(colors[colorIndex]);
      haltButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            halt = !halt; // toggle it!
         }
      });
      add(haltButton);

      new Thread(new Runnable() {
         public void run() {
            while (true) {
               keepDoingThis();
            }
         }
      }).start();
   }

   private void keepDoingThis() {
      try {
         Thread.sleep(SLEEP_DELAY);
      } catch (InterruptedException e) {}

      if (halt) {
         return;
      }
      colorIndex++;
      colorIndex %= colors.length;
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            setBackground(colors[colorIndex]);
         }
      });
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
   }

   private static void createAndShowUI() {
      JFrame frame = new JFrame("HaltingProblem");
      frame.getContentPane().add(new HaltingProblem());
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            createAndShowUI();
         }
      });
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
1

The programming paradigm is a bit different when you're using a GUI.

By registering listeners on the buttons you get notified when something happens - if nothing happens the Swing event loop (EDT) is already doing "nothing".

Perhaps I misunderstood the question though.

extraneon
  • 23,575
  • 2
  • 47
  • 51
  • Yes a bit. I am using listeners, and the problem is, the loop just keeps on going around and around, and it always overrides when a listener action happens. I will update OP post a bit. – Jimmy Huch Jun 05 '11 at 13:59
  • @Jimmy: the solution is to not use the loop. Instead when the button is pressed check the text in your JTextField to see if it contains the needed String. You need to change your way of thinking. – Hovercraft Full Of Eels Jun 05 '11 at 14:05
  • @Hovercraft Full Of Eels, I wish I could change my way of thinking, unfortunately my program must have a main loop to control flow. I know this is weird, but teachers are teachers. – Jimmy Huch Jun 05 '11 at 14:07
  • @Jimmy: please see my answer posted in this thread. Also, if your teachers instructions are strange, unusual or difficult to understand, post the exact instructions in an edit to your original post so we can read and try to interpret them, and then use the information to correct our recommendations. – Hovercraft Full Of Eels Jun 05 '11 at 14:20
1

If you have a GUI, you do not generally have a central main loop that executes indefinitely. The canonical way to respond to events is with event listeners:

mybutton.addListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) { System.out.println("Clicked"); }
    });
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • That is the problem - I want a central main loop to execute while I have GUI :S I hope someone here knows how to get around this. – Jimmy Huch Jun 05 '11 at 14:03
  • @Jimmy: The GUI already *is* the main loop. It sounds like you need some kind of worker thread; see e.g. http://download.oracle.com/javase/tutorial/uiswing/concurrency/. – Oliver Charlesworth Jun 05 '11 at 14:10
1

Make your JFrame implement ActionListener and call button.addActionListener(this). Then the code inside the actionPerformed(ActionEvent event) method will execute when the button is clicked :)

Or you could make the ActionListener anonymous with

button.addActionListener(new ActionListener() {
    void actionPerformed(ActionEvent event) {
        // Insert code to execute when button is clicked
    }
}
khellang
  • 17,550
  • 6
  • 64
  • 84
  • 1
    No, do not make the JFrame implement ActionListener as this makes for a very poor design (mixing control and gui elements in a single class) and does not scale well. Yes to the anonymous listener or separate listener class and 1+ for that. – Hovercraft Full Of Eels Jun 05 '11 at 14:03
  • This still doesn't exactly solve my problem. I want a central loop to control the flow of my program w/string action commands when buttons are clicked. – Jimmy Huch Jun 05 '11 at 14:05
  • 1
    I don't think you get how flow works in a GUI applications.. In a regular console application the code executes in a specific order, but in a GUI application the code executes by raising events from the GUI. Check out some tutorials on GUI and concurrency... – khellang Jun 05 '11 at 14:15