Search code examples
javaswingjava.util.scannersystem.in

Writing to System.in from swing ui and reading the input with Scanner


So, I was wondering if Scanner could read from System.in that is set from JFrame. This is what I mean.

This is my WriteToSystemIn (JFrame class), which is the GUI part of the program.

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;

public class WriteToSystemIn extends JFrame {
    private static class ChangeNumber implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            ByteArrayInputStream s = null;
            try {
                s = new ByteArrayInputStream("1\n".getBytes("UTF-8"));
            } catch (UnsupportedEncodingException ex) {
                throw new RuntimeException(ex);
            }
            System.setIn(s);

        }
    }
    WriteToSystemIn() {
        JButton button = new JButton("try click it m8");
        button.addActionListener(new ChangeNumber());
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(button);
        this.setVisible(true);
        this.pack();
    }
}

And this is the Main function of the program.

import java.util.Scanner;

public class Main {
    private static class MainRunnable implements Runnable {

        @Override
        public void run() {
            new WriteToSystemIn();
        }
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new MainRunnable());

        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        System.out.println(s);

        System.out.println("ended");
    }
}

So, when the button is pressed from WriteToSystemIn, it should write "1\n" to System.in for Scanner to read.

But, it isn't doing that. It won't read anything. It has no problem printing to System.out so I thought it would've been a non-issue, but clearly I'm wrong. So, I'm wondering here, is there something that I'm doing wrong here? Or, am I trying to do something that is impossible?


Solution

  • Continuing on from @Torben's answer, you need to make class Main wait until the JButton (in class WriteToSystemIn) is clicked. Once the JButton is clicked, you can notify Main that it can stop waiting and continue executing.

    Class Main

    import java.util.Scanner;
    
    public class Main {
        private static class MainRunnable implements Runnable {
            private Main main;
    
            public MainRunnable(Main main) {
                this.main = main;
            }
    
            @Override
            public void run() {
                new WriteToSystemIn(main);
            }
        }
    
        public static void main(String[] args) {
            Main main = new Main();
            javax.swing.SwingUtilities.invokeLater(new MainRunnable(main));
            synchronized (main) {
                try {
                    main.wait();
                    Scanner scanner = new Scanner(System.in);
                    String s = scanner.nextLine();
                    System.out.println(s);
                }
                catch (InterruptedException x) {
                    x.printStackTrace();
                }
            }
            System.out.println("ended");
        }
    }
    

    Class WriteToSystemIn

    import javax.swing.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.ByteArrayInputStream;
    import java.io.UnsupportedEncodingException;
    
    public class WriteToSystemIn extends JFrame {
    
        private static class ChangeNumber implements ActionListener {
            private Main main;
    
            public ChangeNumber(Main main) {
                this.main = main;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                ByteArrayInputStream s = null;
                try {
                    s = new ByteArrayInputStream("1\n".getBytes("UTF-8"));
                    System.setIn(s);
                    synchronized (main) {
                        main.notifyAll();
                    }
                } catch (UnsupportedEncodingException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
    
        WriteToSystemIn(Main main) {
            JButton button = new JButton("try click it m8");
            button.addActionListener(new ChangeNumber(main));
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.add(button);
            this.setVisible(true);
            this.pack();
        }
    }