CtRan
CtRan

Reputation: 1

How to take terminal results and set a JTextArea to read the terminal?

I recently finished up a GUI where a user can input criteria, and get results adhering to said conditions. The program works result wise, but I'm having trouble getting my textField in my GUI to read my terminal window result. My code for the GUI is as followed:

package project205;
import javax.swing.*;

import java.awt.*;
import java.awt.event.*;

public class HouseListGUI extends JFrame
{
//GUI Components

HouseList availableHouses = new HouseList("src/houses.txt");

 JLabel  cLab   = new JLabel("Criteria");
 JLabel  minLab   = new JLabel("Min");
 JLabel  maxLab   = new JLabel("Max");
 JLabel  pLab   = new JLabel("Price");
 JLabel  aLab   = new JLabel("Area");
 JLabel  bLab   = new JLabel("Bedrooms");

 JTextField  pMin   = new JTextField(10);
 JTextField  pMax   = new JTextField(10);
 JTextField  aMin   = new JTextField(10);
 JTextField  aMax   = new JTextField(10);
 JTextField  bMin   = new JTextField(10);
 JTextField  bMax   = new JTextField(10);

 JTextArea  results    = new JTextArea(20, 40);

 JButton sButton   = new JButton("Search");
 JButton qButton   = new JButton("Quit");

public HouseListGUI()
{


        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(400,300);
        setVisible(true);  





Container c = getContentPane();
c.setLayout(new GridLayout(5,3,10,10));
c.add(cLab);
c.add(minLab);
c.add(maxLab);
c.add(pLab);
c.add(pMin);
c.add(pMax);
c.add(aLab);
c.add(aMin);
c.add(aMax);
c.add(bLab);
c.add(bMin);
c.add(bMax);
c.add(sButton);
c.add(results);
c.add(qButton);

sButton.addActionListener(
  new ActionListener()
  {
    public void actionPerformed(ActionEvent e)
    {
    String pmn = pMin.getText();
    String pmx = pMax.getText();
    String amn = aMin.getText();
    String amx = aMax.getText();
    String bmn = bMin.getText();
    String bmx = bMax.getText();

    int pmn1 = Integer.parseInt(pmn);
    int pmx1 = Integer.parseInt(pmx);
    int amn1 = Integer.parseInt(amn);
    int amx1 = Integer.parseInt(amx);
    int bmn1 = Integer.parseInt(bmn);
    int bmx1 = Integer.parseInt(bmx);


    Criteria theCriteria = new Criteria(pmn1, pmx1, amn1, amx1, bmn1, bmx1);

    availableHouses.printHouses(theCriteria);

    results.setText("");

    }
  });


qButton.addActionListener(
        new ActionListener()
        {
             public void actionPerformed(ActionEvent e)
             {
                 System.exit(0);
             }
        }
        );
}
public static void main(String[] args)
{

    //HouseList availableHouses = new HouseList("src/houses.txt");
    HouseListGUI g1 = new HouseListGUI();
    g1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    g1.setSize(1000,500);
    g1.show();
}

}

I would like the results of the code line availableHouses.printHouses(theCriteria); which returns a type void to be printed in the textArea results

I've tried using type cast to cast the void as a string and putting that into results, ie:

   results.setText((String)availableHouses.printHouses(theCriteria);

But Java's not having that.

TL;DR:

How might one take a terminal resulting from a method call of type void, and printing that as a type String into a textArea in the context of a GUI?

for further clarification:

my terminal window looks like this:

https://i.sstatic.net/ZTZFC.jpg

and my GUI looks like this:

https://i.sstatic.net/dCxbZ.jpg

and I want my terminal to be in the middle box in the last row.

Thanks for any advice/tips!

Upvotes: 0

Views: 1061

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347314

You can capture and redirect the content sent to System.out by supplying your own OutputStream. This is, by no stretch of the imagination, a foolproof solution, as anything printed to the standard out will be captured, but you could turn in on and off as you needed...

I've used this as a debug window in applications that did not have debug statements to a log file as well as filtering and stopping System.out from generating any output...

In this example I use ...

PrintStream ps = System.out;
System.setOut(new PrintStream(new StreamCapturer(capturePane, ps)));
doSomeProcessing();
System.setOut(ps);

To start and stop capturing the System.out, you could place a flag in StreamCapturer that turned the echoing feature on and off, which might be better way to approach the problem...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class RediretStdOutTest {

    public static void main(String[] args) {
        new RediretStdOutTest();
    }

    public RediretStdOutTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                final CapturePane capturePane = new CapturePane();
                JButton processButton = new JButton("Process");
                processButton.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        System.out.println("Look at me, I'm not in your UI");
                        PrintStream ps = System.out;
                        System.setOut(new PrintStream(new StreamCapturer(capturePane, ps)));
                        doSomeProcessing();
                        System.setOut(ps);
                        System.out.println("Neither am I");
                    }
                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(capturePane);
                frame.add(processButton, BorderLayout.SOUTH);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    protected void doSomeProcessing() {

        for (int index = 0; index < 10; index++) {
            System.out.println("--> " + index);
        }

    }

    public class CapturePane extends JPanel implements Consumer {

        private JTextArea output;

        public CapturePane() {
            setLayout(new BorderLayout());
            output = new JTextArea(10, 20);
            add(new JScrollPane(output));
        }

        @Override
        public void appendText(final String text) {
            if (EventQueue.isDispatchThread()) {
                output.append(text);
                output.setCaretPosition(output.getText().length());
            } else {

                EventQueue.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        appendText(text);
                    }
                });

            }
        }
    }

    public interface Consumer {

        public void appendText(String text);
    }

    public class StreamCapturer extends OutputStream {

        private StringBuilder buffer;
        private Consumer consumer;
        private PrintStream old;

        public StreamCapturer(Consumer consumer, PrintStream old) {
            buffer = new StringBuilder(128);
            this.old = old;
            this.consumer = consumer;
        }

        @Override
        public void write(int b) throws IOException {
            char c = (char) b;
            consumer.appendText(Character.toString(c));
            old.print(c);
        }
    }
}

Now, having said all that, I would fix you method so that it returned a result, as it would be cleaner...

Upvotes: 3

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

I've tried using type cast to cast the void as a string and putting that into results, ie:

results.setText((String)availableHouses.printHouses(theCriteria);

No that will never work, and you're going about it backwards. Much better to have the HouseList's printHouses(...) method return a String, and then this can easily be displayed in your JTextArea with little or no modification and certainly without an erroneous cast.

Otherwise, if you absolutely must get the standard output from another console program that you cannot change in any way, you'll have to call it in a separate process (and if a Java program, then in a separate JVM that is run as a process) using a ProcessBuilder, and then trap the InputStream from the process, and output that in your JTextArea. It's do-able, but requires use of background threading, of exception trapping, and is not something I'd recommend that a beginner delve into just yet.

Upvotes: 3

Related Questions