简体   繁体   English

JTextArea实时输出

[英]JTextArea real time output

Hi I have created a waiting queue simulation with loops and also I have made the GUI what the problem is when the user clicks the run button nothing shows up for couples of seconds like 10-15sec then the whole output shows in the JTextArea. 嗨,我创建了一个带有循环的等待队列模拟,并且使GUI出现了问题,当用户单击运行按钮时,几秒钟之内都没有显示,例如10-15秒,然后整个输出显示在JTextArea中。 How do I output everything that is being appending to the jtextarea like in the console. 我如何输出要添加到jtextarea的所有内容,例如在控制台中。 I looked up something called SwingWorker. 我查找了一个名为SwingWorker的东西。 But have not idea how to use it. 但是不知道如何使用它。 any help please. 请任何帮助。

package Windows;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;


public class Station implements  ActionListener 
{
    private JTextArea userinput, useroutput;
    private JScrollPane sbr_userinput, sbr_useroutput;
    private JButton runButton, clearButton, homeButton;

    //LinkedList Customer Queue created here.
    public static Queue<String> line = new  LinkedList<String> ();
    private static String time;   //time variable.
    private static DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");   //DateFormat variable.

    private int intervals;
    private int cashiers;
    private int processing_time;

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

    public Station()
    {
        JFrame frame = new JFrame("[=] Train Station Simulation [=]");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 400);

        frame.setContentPane(GUI());

        frame.setVisible(true);
    }

    public Container GUI() 
    {
        JPanel totalGUI = new JPanel();
        totalGUI.setLayout(new GridLayout(1, 2, 3, 3));

        JPanel lPanel = new JPanel();
        lPanel.setLayout(new GridLayout(2, 1, 3 , 3));
        totalGUI.add(lPanel);

        JPanel rPanel = new JPanel(new GridLayout(3, 1, 3 , 3));
        totalGUI.add(rPanel);

        userinput = new JTextArea("Welcome to Train Station Queue Simulation!!!" + "\n" + 
        "Enter the number of cashiers available HERE!!!!:" + "\n");
        userinput.setEditable(true);
        userinput.setLineWrap(true);
        userinput.setWrapStyleWord(true);
        lPanel.add(userinput);

        useroutput = new JTextArea();
        useroutput.setEditable(false);
        useroutput.setLineWrap(true);
        useroutput.setWrapStyleWord(true);
        lPanel.add(useroutput);

        sbr_userinput = new JScrollPane(userinput, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        sbr_userinput.setPreferredSize(new Dimension(300, 300));
        lPanel.add(sbr_userinput);

        sbr_useroutput = new JScrollPane(useroutput, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        sbr_useroutput.setPreferredSize(new Dimension(300, 300));
        lPanel.add(sbr_useroutput);

        runButton = new JButton("RUN");
        runButton.addActionListener(this);
        rPanel.add(runButton);

        clearButton = new JButton("CLEAR");
        clearButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                userinput.setText("");
                useroutput.setText("");
                System.out.println("cleared");
            }
        });
        rPanel.add(clearButton);

        homeButton = new JButton("HOME");
        rPanel.add(homeButton);

        totalGUI.setOpaque(true);
        return totalGUI;
    }

    public void actionPerformed(ActionEvent e)
    {
        cashiers = Integer.parseInt(userinput.getText());
        if (e.getSource() == this.runButton)
        {
            useroutput.append("CUSTOMERS ARE COMING !!!! !!!!" + "\n" + "\n");;

            //Array of all the customer that will enter the queue.
            String list[] = {"Naqi", "Monty", "Mohin", "Yasmin", "Maighjoo", "Ashish", "Paal", "Kevin", "Ruhail", "Tony"};
            //2nd ArrayList which customer are added to and removed later on so no duplicates arise.
            ArrayList<String> customer = new ArrayList<String>(Arrays.asList(list));

            int array_customer_list = list.length; //Recording the number of customers in the array.

            //While statement containing for loop add customers to the empty LinkedList object.
            while (line.isEmpty())
            {
                for (int x = 0; x < array_customer_list; x++ )
                {
                    try
                    {
                        Thread.sleep(ran_interval() * 1000);   //Sleep method to hold the arrival time by 1-2 seconds. 
                        int cus = (int) (Math.random() * customer.size());   //Random customer is picked here. 
                        String new_cus = customer.get(cus);   //New customer object is created ere.
                        line.add(new_cus);   //Customer objects are added to the empty LinkedList queue.
                        customer.remove(cus);

                        //For loop statement to outputting the queue.
                        for (String s : line)
                        {
                            useroutput.append("[" + s.toString() + " " + "]" + "\n");; //Outputting each customer and using the ".name" method so customers are readable.
                        }
                        //Outputting the whole queue and stating who has joined the queue.
                        useroutput.append("\n" + "The queue has " + line.size() + " customers so far" + "\n" + 
                        new_cus.toString() + " Has Joined the Queue " + " <=== WAITING" + "\n" + "\n");
                    }
                    catch(Exception a)   //ERROR handler for sleep method.
                    {
                        System.out.println("Intervals error: " + e);   //Outputting the ERROR message.
                        System.exit(0);   //If ERROR found exit system.
                    }

                }
            }

            userinput.append("\n");
            useroutput.append("CUSTOMERS ARE WAITING !!!! !!!!" + "\n" + "\n");
            useroutput.append("Processing START !!!!" + "\n" + "\n");

            while (!line.isEmpty())   //While statement with for loop to remove each customer from LinkedList queue.
            {
                try 
                {
                    String cus = line.remove(); //Method to remove customer from LinkedList queue.
                    String time = getTime();
                    Thread.sleep((processing_time() * 1000) / cashiers); //Sleep method to hold the processing by 1-3 seconds.
                    for (String s : line)
                    {
                        useroutput.append("[" + s.toString() + " " + "]" + "\n"); //Outputting each customer and using the ".name" method so customers are readable.
                    }
                    //Outputting the whole queue and stating who has joined the queue.
                    useroutput.append("\n" + "The queue has " + line.size() + " customers left" + "\n" + 
                    cus.toString()+ " waited for " + time + " <=== SERVED" + "\n" + "\n");
                }
                catch(Exception a)   //ERROR handler for sleep method.
                {
                    System.out.println("Cashiers_wait error: " + e);   //Outputting the ERROR message.
                    System.exit(0);   //If ERROR found exit system.
                }
            }
        }

        useroutput.append("Processing FINISHED !!!!" + "\n");
        System.out.println("working");
    }

    static String getTime()   //Time Constructor
    {
       Calendar cal = Calendar.getInstance();
       time = dateFormat.format(cal.getTime());   //Getting the current system time.
       return time;   //Return time.
    }

    public int ran_interval()
     {
         Random rand = new Random(); //Random object created here.
         int interval = this.intervals = rand.nextInt(2) + 1; //Random number between 1-2 is generated for customer arrival here.

         return interval;
     }

    public int processing_time()
     {
         Random ran = new Random();    //Random object created here.
         int time = this.processing_time = ran.nextInt(4) + 1;  //Random number between 1-3 is generated for customer arrival here.

         return time;
     }
}

Swing is a single threaded framework. Swing是一个单线程框架。 That is, all interactions with the UI are intended to performed from within the context of the Event Dispatching Thread. 也就是说,所有与UI的交互都应在事件调度线程的上下文内执行。

One of the responsibilities of the EDT is to process repaint requests. EDT的职责之一是处理重涂请求。

Any process that blocks this thread will prevent it from updating the UI. 任何阻止此线程的进程都将阻止其更新UI。

In your actionPerformed method, you are running a time consuming process within the EDT which is why it takes time before you see the results actionPerformed方法中,您正在EDT中运行一个耗时的过程,这就是为什么要花一些时间才能看到结果

Yu could start a second thread and process the data there, allowing the EDT to continue responding to update requests. Yu可以启动第二个线程并在那里处理数据,从而使EDT继续响应更新请求。 The problem is, Swing also requires that any modifications to the UI be executed from within the EDT as well. 问题是,Swing还要求对UI的任何修改也必须在EDT内部执行。

Luckily for you, there is a simple solution. 幸运的是,这里有一个简单的解决方案。

The best option is to use a SwingWorker . 最好的选择是使用SwingWorker It has a doInBackground method, which allows you to do processing off the EDT, a publish method to allow you to send results back to the EDT, a process method to process what's being published, which is executed in the EDT and a done method which is called within the context of the EDT when the doInBackground method exists 它具有doInBackground方法,该方法使您可以在EDT之外进行处理;一个publish方法,使您可以将结果发送回EDT;在EDT中执行的用于处理正在发布的内容的process方法;以及一个done方法,它可以当doInBackground方法存在时,在EDT的上下文中调用

Take a look at Concurrency in Swing for more details 查看Swing中的并发以了解更多详细信息

One way you can do this is using the model-view type of program design. 一种实现方法是使用程序设计的模型视图类型。 Basically, you have 2 threads: one that handles the GUI (view/controller), and a second thread that manipulates the data (model). 基本上,您有2个线程:一个线程处理GUI(视图/控制器),另一个线程处理数据(模型)。 When an action is performed in the GUI, you start the second thread and tell it to go muck with the data. 在GUI中执行操作时,您将启动第二个线程,并告诉它处理数据。 Then, as the data model thread starts changing values, it tells the GUI thread to go update the GUI by sending an event of some sort. 然后,当数据模型线程开始更改值时,它通知GUI线程通过发送某种事件来更新GUI。

For more about the Model-View-Controller design, see http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller 有关模型视图控制器设计的更多信息,请参见http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

In pseudo code, here's how this would work: 在伪代码中,这是如何工作的:

GUI Thread GUI线程

Initialize UI
While program is running
    Wait for event (like action performed, or ready to update event)
    If button was pressed
        Add task to data model's work queue
    Else // Was not a button event, so therefore the data model must 
         // have sent an update
        Set values in GUI components using the updated data
        Repaint GUI

Data Model Thread (usually has a work queue that the GUI thread can use to tell it what to do) 数据模型线程(通常有一个工作队列,GUI线程可以使用该工作队列来告诉它要做什么)

While model has work to do
    Work on next task // and manipulate data
    Send update event to GUI

As you can see, this is easier to implement if you incorporate this idea from the start. 如您所见,如果从一开始就将这一思想纳入其中,那么将更易于实现。

Another way to "fix" this issue is to plant this call whenever you want the UI to update instantly: 解决此问题的另一种方法是,每当您希望UI立即更新时,都植入此调用:

frame.paint(frame.getGraphics());

HOWEVER, this is a hack, as JFrame.paint and JFrame.getGraphics are both internal Swing methods, and so this should not be used unless you have no other choice. 但是,这是一个hack,因为JFrame.paint和JFrame.getGraphics都是内部的Swing方法,因此,除非没有其他选择,否则不应使用此方法。 If you call this too frequently, it does create a nasty flickering effect/screen tearing, as you are updating the pixel data at the exact same time as the computer is sending that pixel data to the monitor for display. 如果您过于频繁地调用它,则确实会产生令人讨厌的闪烁效果/屏幕撕裂,因为您正与计算机将像素数据发送到显示器进行显示的同时更新像素数据。 (Most computers do this about 30-60 times per second.) (大多数计算机每秒执行此操作约30至60次。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM