【问题标题】:JTextArea real time outputJTextArea 实时输出
【发布时间】:2013-06-07 16:39:29
【问题描述】:

嗨,我已经创建了一个带有循环的等待队列模拟,并且我已经让 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;
     }
}

【问题讨论】:

  • 你正在休眠主线程,即控制所有 gui 的 EDT(事件调度线程),所以你的程序会冻结,javacreed.com/swing-worker-example 这里你有一个简单的例子或如何使用它,但基本上是另一个执行你想要的任务的线程,当它完成时,通知,就像观察者模式一样。
  • ` 我查了一个叫做 SwingWorker 的东西。但是不知道怎么用` - Swing 教程有例子,论坛里有例子。
  • 显然这里的帮助还不够。现在问题是交叉发布:java-forums.org/awt-swing/…

标签: java swing jtextarea


【解决方案1】:

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

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

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

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

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

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

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

查看Concurrency in Swing了解更多详情

【讨论】:

  • @camickr 实际上,我阅读了这个问题,他们只发布了答案,而(恕我直言)没有回答这个问题。很抱歉我没有花时间阅读其他 cmets,但我真的不希望其他有类似问题的人错过重点
  • 你是对的,另一个答案是题外话,没有解决这个问题。我对 OP 很生气,他们懒得说出他们对 SwingWorker 的不理解或阅读教程。相反,他们在另一个论坛上交叉发布一个问题,希望得到答案。我沮丧地写了评论。我以为我在你有机会阅读之前删除了它,但你又一次太快了。您的回复确实会让遇到这个问题的其他人受益 (+1)。
  • @camickr 我也很喜欢有人在这里重复发帖,所以我理解你的沮丧。
【解决方案2】:

您可以做到这一点的一种方法是使用模型视图类型的程序设计。基本上,您有 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 次。)

【讨论】:

  • 有没有这种模型的例子可以给我看看?
  • 我理解这个模型的概念,但我只是想我当前的代码是否适用于这个模型。而且我也不知道这本质上是多线程的相关语法。
  • 好吧,您在事件处理程序中完成所有工作。只需要将 if 语句主体中的所有内容提取到带有签名 public void run() 的新方法中,将您的 Station 类设置为实现 Runnable,然后只需使用您的 GUI 作为 Runnable 创建一个新线程参数。
  • 可以在同一个类文件中做多线程而不是两个不同的类文件吗?
  • 不,您不应该使用 getGraphics() 方法进行绘画。下次 Swing 确定组件需要重新绘制时,绘制将丢失。此外,模型的更新应该在 EDT 上完成,而不是在单独的线程上。简单的解决方案是 SwingWorker,它在结果可用时发布结果。然后更新模型并自动重新绘制组件。
猜你喜欢
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-12
  • 2021-09-09
  • 2016-04-22
  • 2011-05-02
  • 2017-02-12
相关资源
最近更新 更多