0

I'm writing a small program that runs one of three samples of code depending on which button is pressed. With the third button, a sample of code should run until the JFrame is closed, or until a button is pressed (I don't really mind how it's stopped, just as long as the user has a method of stopping the loop). The code is run, and a delay of 8 seconds is added to ensure the code finished running before it loops.

How do I implement this? The program doesn't seem to terminate when looping, even when I try to close it by clicking the close button in the JFrame.

The main part of the program looks as follows:

public class WaspmoteSim extends JFrame implements ActionListener {
public WaspmoteSim() {
    setDefaultCloseOperation(EXIT_ON_CLOSE);

    //getContentPane().setLayout(new GridLayout(1, 3, 10, 10));
    getContentPane().setLayout(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();
    c.insets = new Insets(30,30,30,30);
    c.ipadx = 10;
    c.ipady = 30;
    setSize(700, 150);
    setLocation(100, 100);

    JButton button1 = new JButton("Demonstration Mode");
    button1.addActionListener(this);
    add(button1, c);

    JButton button2 = new JButton("Distribution Fitting Mode");
    button2.addActionListener(this);
    add(button2, c);

    JButton button3 = new JButton("Operational Mode");
    button3.addActionListener(this);
    add(button3, c);

    setVisible(true);
}
public static void main(String[] args) {
    new WaspmoteSim();
}

@Override
public void actionPerformed(ActionEvent e) {
    String command = e.getActionCommand();

    if (command.equals("Demonstration Mode")) {
        try {
            DemoMethod();
        } catch (IOException ex) {
            Logger.getLogger(WaspmoteSim.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    if (command.equals("Distribution Fitting Mode")) {
        try {
            FittingMethod();
        } catch (IOException ex) {
            Logger.getLogger(WaspmoteSim.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    if (command.equals("Operational Mode")) {
        try {
            OperationsMethod();
        } catch (IOException ex) {
            Logger.getLogger(WaspmoteSim.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InterruptedException ex) {
            Logger.getLogger(WaspmoteSim.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

The code that I want to run on a loop looks like this:

public void OperationsMethod() throws IOException, InterruptedException {
        while(true) {
            String workingDir = System.getProperty("user.dir");
            System.out.println(workingDir);
            Process proc;
            proc = Runtime.getRuntime().exec("cmd.exe /C C:\\Progra~1\\R\\R-3.2.1.\\bin\\Rscript.exe " + workingDir + "\\Fitter.r");
            TimeUnit.SECONDS.sleep(8);
        }
    }
Martin
  • 277
  • 2
  • 5
  • 17

2 Answers2

1

The procedure you can follow is this:

1) Create a Process using ProcessBuilder and store it for later use (You can use a holder singleton class "ProcessHolder" for this).

2) Register an event function to your button that takes You register an event function to your button that has access to the ProcessHolder, and terminates the process using destroy() method.

Check for more here.

//Process Holder singleton
public class ProcessHolder {
    private Map<String, Process>  _processes;

    private static ProcessHolder _processHolder;

    private ProcessHolder() {
        _processes = new HashMap<>();
    }

    public static ProcessHolder getInstance() {
        if(_processHolder == null) {
            _processHolder = new ProcessHolder();
        }
        return _processHolder;
    }

    public void getProcesses() {
        return _processes;
    }

}

//......
public class WaspmoteSim extends JFrame implements ActionListener {

    public static final String YOUR_PROCESS_NAME = "Rscript.exe";

    public WaspmoteSim() {
        //....
        JButton button = new JButton("Destroy Process");

        Process process    = Runtime.getRuntime().exec(
            System.getenv("cmd.exe /C C:\\Progra~1\\R\\R-3.2.1.\\bin\\" + YOUR_PROCESS_NAME + " + workingDir + "\\Fitter.r");
        ProcessHolder.getInstance().getProcesses().put(processName, p);
        button.addActionListener(this);
        //....
    }

    //Callback:
    @Override
    public void actionPerformed(ActionEvent e) {
        ProcessHolder.getInstance().getProcesses().get(YOUR_PROCESS_NAME).destroy();
    }

}

Also a notice:

You are doing:

 while(true) {
     Process proc;
     proc = Runtime.getRuntime().exec("cmd.exe /C C:\\Progra~1\\R\\R-3.2.1.\\bin\\Rscript.exe " + workingDir + "\\Fitter.r");
     TimeUnit.SECONDS.sleep(8);
 }

This will attempt to start a new process every 8 seconds (!). In order to start a process, do it once, store it, then kill it when needed using destroy, unless your target is to create new processes like this, indeed.

Community
  • 1
  • 1
Nick Louloudakis
  • 5,856
  • 4
  • 41
  • 54
  • I'm still having some trouble implementing your example; Java states that the abstract method Process needs an empty list to be instantiated, not a String (which is the process name I'm trying to create). Am I doing something else wrong? – Martin Oct 11 '15 at 09:45
  • Answer updated, you do it, you use `Runtime.getRuntime().exec(....)` to create it. – Nick Louloudakis Oct 11 '15 at 09:53
  • Thanks; I'll be home again in an hour or two and will try it then. Thanks so much for your time! – Martin Oct 11 '15 at 10:02
  • Hi @nick-l, I tried implementing, but it gave me a "Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException" at the "Runtime.getRuntime().exec(System.getenv)" statement. I had to surround it by a try-catch, as it would constantly say it's receiving an IOException. Any ideas? – Martin Oct 11 '15 at 12:23
  • I made a fix, try it again and search for any not initialized reference in your code. – Nick Louloudakis Oct 11 '15 at 12:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/91959/discussion-between-martin-and-nick-l). – Martin Oct 11 '15 at 13:01
0

first define a new boolean variable isClosed in your JFrame add a close-listener to your JFrame and set a boolean variable to true

addWindowListener(new WindowAdapter()
{
    public void windowClosing(WindowEvent e)
    {
        isClosed = true;
    }
});

now change your while(true) to while(!isClosed)

JohnnyAW
  • 2,866
  • 1
  • 16
  • 27