[英]JTextArea real time output
嗨,我创建了一个带有循环的等待队列模拟,并且使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;
}
}
Swing是一个单线程框架。 也就是说,所有与UI的交互都应在事件调度线程的上下文内执行。
EDT的职责之一是处理重涂请求。
任何阻止此线程的进程都将阻止其更新UI。
在actionPerformed
方法中,您正在EDT中运行一个耗时的过程,这就是为什么要花一些时间才能看到结果
Yu可以启动第二个线程并在那里处理数据,从而使EDT继续响应更新请求。 问题是,Swing还要求对UI的任何修改也必须在EDT内部执行。
幸运的是,这里有一个简单的解决方案。
最好的选择是使用SwingWorker
。 它具有doInBackground
方法,该方法使您可以在EDT之外进行处理;一个publish
方法,使您可以将结果发送回EDT;在EDT中执行的用于处理正在发布的内容的process
方法;以及一个done
方法,它可以当doInBackground
方法存在时,在EDT的上下文中调用
一种实现方法是使用程序设计的模型视图类型。 基本上,您有2个线程:一个线程处理GUI(视图/控制器),另一个线程处理数据(模型)。 在GUI中执行操作时,您将启动第二个线程,并告诉它处理数据。 然后,当数据模型线程开始更改值时,它通知GUI线程通过发送某种事件来更新GUI。
有关模型视图控制器设计的更多信息,请参见http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
在伪代码中,这是如何工作的:
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
数据模型线程(通常有一个工作队列,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次。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.