1

嗨,我已经创建了一个带有循环的等待队列模拟,并且我已经让 GUI 出现了问题,当用户单击运行按钮时,几秒钟内什么都没有显示,比如 10-15 秒,然后整个输出显示在 JTextArea 中。如何像在控制台中一样输出附加到 jtextarea 的所有内容。我查找了一个名为 SwingWorker 的东西。但不知道如何使用它。请提供任何帮助。

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;
     }
}
4

2 回答 2

4

Swing 是一个单线程框架。也就是说,与 UI 的所有交互都旨在从事件调度线程的上下文中执行。

EDT 的职责之一是处理重绘请求。

任何阻塞此线程的进程都会阻止它更新 UI。

在你的actionPerformed方法中,您在 EDT 中运行了一个耗时的过程,这就是为什么在看到结果之前需要时间

Yu 可以启动第二个线程并在那里处理数据,从而允许 EDT 继续响应更新请求。问题是,Swing 还要求对 UI 的任何修改也必须在 EDT 内执行。

幸运的是,有一个简单的解决方案。

最好的选择是使用SwingWorker. 它有一个doInBackground方法,允许您在 EDT 之外进行处理,一个publish允许您将结果发送回 EDT 的process方法,一个处理正在发布的内容的方法,该方法在 EDT 中执行,以及一个在 EDTdone中调用的方法EDT 的上下文,当doInBackground方法存在

查看Swing 中的并发以获取更多详细信息

于 2013-06-07T21:15:57.173 回答
0

您可以做到这一点的一种方法是使用模型视图类型的程序设计。基本上,您有 2 个线程:一个处理 GUI(视图/控制器),另一个处理数据(模型)。在 GUI 中执行操作时,您启动第二个线程并告诉它处理数据。然后,随着数据模型线程开始更改值,它告诉 GUI 线程通过发送某种事件来更新 GUI。

有关模型-视图-控制器设计的更多信息,请参阅http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

在伪代码中,这是如何工作的:

图形用户界面线程

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

数据模型线程(通常有一个工作队列,GUI 线程可以使用它来告诉它要做什么)

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

如您所见,如果您从一开始就结合这个想法,这将更容易实现。

“修复”此问题的另一种方法是在您希望 UI 立即更新时植入此调用:

frame.paint(frame.getGraphics());

然而,这是一个 hack,因为 JFrame.paint 和 JFrame.getGraphics 都是内部的 Swing 方法,所以除非你别无选择,否则不应该使用它。如果您过于频繁地调用它,它确实会产生令人讨厌的闪烁效果/屏幕撕裂,因为您在计算机将像素数据发送到显示器进行显示的同时更新像素数据。(大多数计算机每秒大约执行 30-60 次。)

于 2013-06-07T16:54:17.027 回答