2013-06-07 2 views
1

안녕하세요 루프를 사용하여 대기열 시뮬레이션을 만들었고 사용자가 실행 버튼을 클릭했을 때 GUI에 문제가있는 경우 GUI를 만들었습니다. 몇 초 만에 10-15 초 정도의 출력이 나오면 전체 출력이 나오지 않습니다. JTextArea에 보여줍니다. 콘솔에서와 같이 jtextarea에 추가되는 모든 것을 어떻게 출력합니까? 나는 SwingWorker라는 것을 찾아 보았다. 그러나 그것을 사용하는 방법을 모릅니다. 제발 도와주세요.JTextArea 실시간 출력

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; 
    } 
} 
+0

에 대한 Concurrency in Swing에서 봐 존재하는 경우 EDT의 컨텍스트 내에서 호출, 즉, 모든 GUI를 제어하는 ​​EDT (이벤트 발송 쓰레드)입니다 그래서 UR 프로그램은 얼어 버릴 것입니다, http://www.javacreed.com/swing-worker-example/ 여기에 간단한 예나 사용법이 있습니다 만, 기본적으로 U가 원하는 작업을 수행하는 또 다른 스레드입니다. 때 f inish는 관찰자 패턴처럼 통지한다. – nachokk

+0

'나는 SwingWorker라고 불리는 것을 찾아 보았습니다. Swing 튜토리얼에 예제가 있습니다. 포럼에 예제가 있습니다. – camickr

+0

분명히 여기서 도움이 충분하지 않습니다. 이제 질문은 crossposted입니다 : http://www.java-forums.org/awt-swing/76259-real-time-console-output-jtextarea.html – camickr

답변

1

한 가지 방법은 모델보기 유형의 프로그램 디자인을 사용하는 것입니다. 기본적으로 GUI (view/controller)를 처리하는 스레드와 데이터 (모델)를 조작하는 두 번째 스레드라는 두 개의 스레드가 있습니다. 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()); 

, 이것은 해킹 JFrame.paint로, 그리고 JFrame.getGraphics은 모두 내부 Swing 메서드를 사용하므로 다른 선택이 없으면이 메서드를 사용하면 안됩니다. 이것을 너무 자주 호출하면 컴퓨터가 픽셀 데이터를 모니터로 보내 디스플레이와 동시에 픽셀 데이터를 업데이트 할 때 불쾌한 깜박임 효과/화면 끊김 현상이 발생합니다. (대부분의 컴퓨터는 초당 30-60 회 정도를 수행합니다.)

+0

저에게 보여줄 수있는 이런 종류의 모델의 예가 있습니까? 제발? – user2464333

+0

이 모델의 개념을 이해하지만 Im은이 모델로 현재 코드가 작동하고 있다고 생각합니다. 또한 본질적으로 멀티 스레딩을위한 관련 구문을 모르겠습니다. – user2464333

+0

글쎄, 당신은 이벤트 처리기에서 모든 작업을 수행합니다. 이 작업을 수행하는 데 필요한 모든 것은 if 문 안의 모든 내용을 public void run()으로 새 메서드로 추출하고, Runnable을 구현하도록 Station 클래스를 설정 한 다음 GUI를 Runnable로 사용하여 새 스레드를 간단히 작성하는 것입니다. 매개 변수. –

3

스윙은 단일 스레드 프레임 워크입니다. 즉, UI와의 모든 상호 작용은 Event Dispatching Thread의 컨텍스트 내에서 수행됩니다.

EDT의 책임 중 하나는 다시 칠하기 요청을 처리하는 것입니다.

이 스레드를 차단하는 프로세스로 인해 UI가 업데이트되지 않습니다. 당신의 actionPerformed 방법에서

, 당신은 결과

를 볼 전에 시간이 걸리는 이유 이

유는 EDT에 허용, 두 번째 스레드를 시작하고이 데이터를 처리 할 수있는 EDT 내에서 시간 소모적 인 프로세스를 실행 업데이트 요청에 계속 응답하십시오. 문제는 Swing은 EDT 내에서 UI에 대한 수정을 수행해야한다는 것입니다.

운 좋게도 간단한 해결책이 있습니다.

가장 좋은 방법은 SwingWorker입니다.그것은 doInBackground 방법을 사용하여 EDT에서 처리를 수행 할 수 있습니다. publish 메서드를 사용하면 EDT로 결과를 다시 전송할 수 있고, process 메서드는 EDT에서 실행되며, done 메서드는 doInBackground 방법은

은 자세한 내용

U 주 스레드을 자고
+0

@camickr 사실, 나는 질문을 읽었을 뿐이며, 대답을 게시하지 않았다. (IMHO) 질문에 대답하지 않았다. 죄송합니다. 다른 의견을 읽을 시간이 없지만 사실은 비슷한 문제가있는 다른 사람들이 그 점을 놓치지 않기를 바랍니다. – MadProgrammer

+0

다른 답변이 정확한지, 문제를 해결하지 못했습니다. 나는 그들이 SwingWorker에 대해 이해하지 못했던 것을 진술하거나 튜토리얼을 읽지 않으려 고 애 쓰고있는 OP에 화가났다. 대신 그들은 숟가락으로 답변을 받기를 희망하는 다른 포럼에서 질문을 게시합니다. 나는 좌절감으로 의견을 썼다. 나는 당신이 그것을 읽을 기회가 있기 전에 그것을 제거했다고 생각했지만, 다시 한번 당신은 너무 빨랐습니다. 귀하의 회신은 실제로이 질문에 대한 다른 사람들에게 도움이 될 것입니다 (+1). – camickr

+0

@camickr 여기 게시판에 게시 된 사람들에게 오히려 PO가 표시되므로 귀하의 좌절감을 이해합니다. – MadProgrammer