0

The client has requested a Graphical Interface for their currently command-line driven program. (The program animates a flowchart in a separate window.) The commands activate loops which repaint the flowchart window.

The problem I am having is that when using my GUI, the flowchart does not animate. repaint() is not repainting the same way.

I have tried the solutions at How can I write to stdIn (JAVA) and JUnit testing with simulated user input but they all rely on System.setIn(in) which doesn't work for me.

Here is a minimal code that shows the problem. Enter commands via the standard input and you will see them animate. Do the same thing via the GUI and there is no animation. Both input methods run the same command, drawFakeData - so why do they produce different results??

import javax.swing.*;
import java.awt.*;
import java.util.*;

public class FlowChart {

    public GUImin gui;
    private static int i;

    public static void main(String[] args) {
        FlowChart sdm = new FlowChart();
        sdm.runInterpreter();
    }

    public FlowChart() {
        EventQueue.invokeLater(() -> {
            gui = new GUImin();
        });
    }

    public void runInterpreter() {

        Scanner takeCommand = new Scanner(System.in);
        String userCommandLine;
        do {

            //capture all Standard Input from console
            userCommandLine = takeCommand.nextLine();
            processInput(userCommandLine);


        } while (!userCommandLine.equals("quit"));
        takeCommand.close();
    }

    public void processInput(String input) {

        for (i = 0; i < 10; i++) {  //emulate an animation loop

            EventQueue.invokeLater(() -> {
                gui.drawFakeData(input + i);
            });
            // pause for a given number of seconds
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    class GUIpanelmin extends JPanel {
        public String input = "^";
        public int x;
        public int y;

        public GUIpanelmin() {
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);  //no idea what this does - draws background I think?
            System.out.println("GUI: " + "Paint Component Reached.");
            Graphics2D g2d = (Graphics2D) g;  //or this
            g2d.drawString(input, x, y);  //just an example
        }

    }

    public class GUImin extends JFrame {
        public GUIpanelmin GUIpanel;

        public GUImin() {
            super("GUI");
            super.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            super.setVisible(true);
            setSize(350, 250);  //TBD
            setLocationRelativeTo(null);  //centers the panel
            this.getContentPane().setLayout(new FlowLayout());


            //input text box
            JTextField inputField = new JTextField(10);
            inputField.setPreferredSize(new Dimension(200, 30));
            add(inputField);

            //the button
            JButton submitButton = new JButton("Submit Command");
            submitButton.setPreferredSize(new Dimension(40, 30));
            submitButton.addActionListener(e -> {
                for (int i = 0; i < 10; i++) {  //emulate animation loop
                    drawFakeData(inputField.getText());
                    // pause for a given number of seconds
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
                inputField.setText("");
            });
            add(submitButton);

            //the panel with all the pretties
            GUIpanel = new GUIpanelmin();  //there's only one
            GUIpanel.setPreferredSize(new Dimension(300, 300));
            add(GUIpanel);
        }

        public void drawFakeData(String command) {
            //just an example - real thing will be much more complicated
            GUIpanel.x = (int) (Math.random() * 100 + 5);
            GUIpanel.y = (int) (Math.random() * 100 + 5);
            GUIpanel.input = command;
            GUIpanel.repaint();
        }
    }
}

Any help explaining this puzzling behavior is appreciated.

Edit: here is what the GUI looks like (right image): enter image description here Text from standard input (left image) animates. Text from text box does not animate, even though both text is processed by the same code.

john k
  • 6,268
  • 4
  • 55
  • 59
  • "Do the same thing via the GUI and there is no animation" can you clarify what you meant by that, did you have to modify the above code to do just that? What I am saying, is by modifying it use the GUI would involve changing the behaviour of the code. Can you absolutely confirm this by debugging it without the use of the standard input? – t0mm13b Jul 11 '18 at 06:58
  • `private static int i;` ... seriously? You make a loop counter a static variable of the class? And you still name it "i", as if that name would mean anything outside of the scope of a small counting for loop? In other words: use names that say what they mean, and mean what they say. i, x, y, mean close to nothing. – GhostCat Jul 11 '18 at 06:58
  • Have a look at Swing timers : https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html – Arnaud Jul 11 '18 at 07:00
  • Ghostcat ‘i’ is pretty standard to use as a loop index. Static was required to pass it into the GUI function, according to IntelliJ – john k Jul 11 '18 at 19:53
  • T0mm13b the whole question is about the difference between std input and in-program execution. Saying to test stdin without using stdin makes no sense in this context. Not sure what you mean. – john k Jul 11 '18 at 19:58

0 Answers0