Search code examples
javaswingjtextarea

Appending data to JTextArea for a running simulation


I've looked around some other answers and found a few solutions, I'm using JTextArea.append(), however what's confusing me is that my implementation works in one method, but not another.

In my frame class when I call "open()" and open a file it displays the output in the jTextArea1 using getjTextArea1() and

getjTextArea1().append("\n"+"Writing data to file..." + "\n"+Controller.stats());

However, when I attempt to do the same (I think it's the same, but it doesn't work, so clearly it isn't) with the method "display()" it runs the method, but doesn't append the jTextArea.

I'm quite the greenhorn to java and I've spent some time looking at other answers but just can't seem to see why my code doesn't work.

I have the following code, which should compile and run as a minimum example.

Main controller class:

package forSO;
 import java.awt.EventQueue;
 import javax.swing.JFrame;
 public class Controller {
public static Checkout till1;
public static void main(String[] args) throws Exception
{
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            new Frame().setVisible(true);
            new Frame().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    });
    till1 = new Checkout();
    till1.simulation();
}
public static String stats()
{
    String maxLength=till1.CalculateMaxLength();
    String stats = "Max length = "+maxLength;
    return stats;
    }
}

Checkout class, where the simulation occurs:

    package forSO;

import java.io.*;
import java.text.DecimalFormat;
import java.util.*;

public class Checkout{
    private static int nTimeSteps = Frame.getnTimeSteps();
    private static Queue<String> tillQueue;
    private static int rndNumber;
    private static int currentLen;
    private static ArrayList <Integer> lengthList;
    private int maxLength;
    private static Random r;


    public Checkout(){
        tillQueue = new LinkedList<String>();
        currentLen = 0;
        lengthList = new ArrayList <Integer>();
        r = new Random();
    }

    public void simulation(){
        System.out.println("Time"+"\t"+"Rnd"+"\t"+"Queue Status");
        int t = 1;  //controller for timesteps
        Frame fFrame = new Frame();

        while (Frame.isRunning == true && t < nTimeSteps+1){            
            rndNumber = r.nextInt(6)+1; //Generate random number between 0-6
            if (rndNumber==2 || rndNumber==4 || rndNumber==6){
                tillQueue.add(String.valueOf(t));
                currentLen++;
            }
            else if ((rndNumber==1 || rndNumber==3) && !tillQueue.isEmpty()){
                tillQueue.remove();
            currentLen--;
            }
            else if(rndNumber==5){
            }

            //Printing the queue.
            if (tillQueue.isEmpty()){
                System.out.print(t+"\t"+rndNumber+"\t"+"Empty"+"\t");
            }
            else if (!tillQueue.isEmpty()){
                System.out.print(t+"\t"+rndNumber+"\t"+tillQueue.toString()+"\t");
            }

            //add currentLen to ArrayList for statistics
            lengthList.add(new Integer(currentLen));
            //print out the statistics after first updating the arraylist
            System.out.println(Controller.stats());

            /**
            *########################################################################
            *This is where I make the call to the display() method and where I EXPECT
            *to see the stats data printed to my JTextField
            *########################################################################
            */
            fFrame.display();

            //slow down the simulation rate
            try
            {
                Thread.sleep(200);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            //increment timesteps
            t++;
        }
    }

    //Normally there would be a lot of calculation for variance/standard dev,
    //but I've limited it to just the max length to give an example.

    public String CalculateMaxLength()
    {
        maxLength=0;
        for (int i=0; i<lengthList.size(); i++)
        {
            int c = (Integer)lengthList.get(i).intValue();
            if (maxLength < c)
            {
                maxLength = c;
            }
        }
        String maxLengthString = new DecimalFormat("00").format(maxLength);
        return maxLengthString;
    }

    public static boolean saveStringToFile(String fileName, String saveString)
    {
        boolean saved = false;
        BufferedWriter bw = null;
        try
        {
            bw = new BufferedWriter(new FileWriter(fileName, true));
            try
            {
                bw.write(saveString); //write data to disk
                saved = true;
            }
            finally
            {
                bw.close();
            }
        }
        catch (IOException ex)
        {
            ex.printStackTrace(); //Print Exceptions
        }
        return saved; //true if the data was saved
    }
}   

Frame class, where I create the JTextArea and attempt to populate it with data from the checkout class

package forSO;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.GroupLayout;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.LayoutStyle;
import javax.swing.WindowConstants;

public class Frame extends JFrame {
private static final long serialVersionUID = 1L;
public Frame() {
    super("Pro Checkout Simulator 2014");
    initMenu();
    initComponents();
}

private void initMenu(){
    //Menu bar
    menubar = new JMenuBar();
    this.setJMenuBar(menubar);
    saveItem = new JMenuItem("Save");
    saveItem.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent ae)
        {
            //save file code
            saveFile();
        }
    });

    exitItem = new JMenuItem("Exit");
    exitItem.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent ae){
            System.exit(0);
        }
    });

    //file menu
    fileMenu = new JMenu("File");
    menubar.add(fileMenu);
    fileMenu.add(saveItem);
    fileMenu.add(exitItem);
}   
private void initComponents(){
    p1 = new JPanel();
    p4 = new JPanel();
    p5 = new JPanel();
    jScrollPane1 = new JScrollPane();
    setjTextArea1(new JTextArea());

    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    GroupLayout p4Layout = new GroupLayout(p4);
    p4.setLayout(p4Layout);
    p4Layout.setHorizontalGroup(
        p4Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(p4Layout.createSequentialGroup()
            .addContainerGap()
            .addContainerGap())
    );
    p4Layout.setVerticalGroup(
        p4Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(p4Layout.createSequentialGroup()
            .addContainerGap()
            .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
    );

    p5.setLayout(new BorderLayout());

    jScrollPane1.setAutoscrolls(true);

    getjTextArea1().setColumns(20);
    getjTextArea1().setLineWrap(true);
    getjTextArea1().setRows(5);
    getjTextArea1().setMinimumSize(new java.awt.Dimension(100, 100));
    getjTextArea1().setEditable(false);
    jScrollPane1.setViewportView(getjTextArea1());

    p5.add(jScrollPane1, BorderLayout.CENTER);

    GroupLayout layout = new GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addComponent(p1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(p4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(p5, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGap(6, 6, 6)))
            .addContainerGap())
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addComponent(p1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addContainerGap()
            .addComponent(p5, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
            .addComponent(p4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addContainerGap())
    );

    pack();
}

public static int getnTimeSteps() {
    return nTimeSteps;
}


static boolean isRunning = true;
public void saveFile()
{
    int result = fc.showSaveDialog(this);
    if (result == JFileChooser.APPROVE_OPTION)
    {
        File myfile = fc.getSelectedFile();
        //save file stuff
        super.setTitle("Saved "+myfile.getAbsolutePath());
        getjTextArea1().append("\n"+"Writing data to file..." + "\n"+Controller.stats());
              Checkout.saveStringToFile(myfile.getAbsolutePath(),"\n"+Controller.stats());
    }
    else
    {
        super.setTitle("Cancel file save");
    }
}

public void display()
{
    getjTextArea1().append("This text should appear within the GUI window");
    System.out.println("If you can see this, display() is being called");
    getjTextArea1().append(Controller.stats());
}

public JTextArea getjTextArea1() {
    return jTextArea1;
}

public void setjTextArea1(JTextArea jTextArea1) {
    this.jTextArea1 = jTextArea1;
}

    // Declare variables
public static int nTimeSteps = 10;
    public static int addSliderValue;
    public static int subSliderValue;
private JMenu fileMenu;
private JMenuBar menubar;
private JMenuItem saveItem,exitItem;
private JFileChooser fc = new JFileChooser();
    private JPanel p1;
    private JPanel p4;
    private JPanel p5;
    private JScrollPane jScrollPane1;
    private JTextArea jTextArea1;                  
}

Solution

  • I count five separate instances Frame in your code, of which I think only one is visible, which generally isn't the one you are interacting with...

    // 1...
    public class Controller {
        public static Frame myFrame = new Frame();
    
    // 2, 3...
    public static void main(String[] args) throws Exception
    {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Frame().setVisible(true);
                new Frame().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
        });
    
    // 4...
    public class Checkout{
    
        Frame testFrame = new Frame();
    
    // 5...
    public void simulation(){
        //...
        Frame fFrame = new Frame();
    

    Reduce this to one and use it alone. This may mean you will need to pass a reference of the frame to other parts of you application.

    A better solution would be to build some kind of model, which could trigger notifications, telling interested parties that some part of the model has changed and any one depending on it's data should be updated....