2014-03-25 7 views
1

예에서 GUI에 테이블을 추가 한 다음 진행률을 표시하기 위해 동적으로 행을 추가하려고합니다. 왜 모든 행이 한 번에 나타나는지 이해할 수 없습니다. 테이블이 바뀌고있는 것 아닌가요? 누군가 나에게 설명을 해줄 수 있습니까?JTable에 동적으로 행 추가 - 왜 한번에 나타 납니까?

import java.awt.Component; 

public class Main { 
    public static void main(String[] args) { 
    // Show GUI 
    java.awt.EventQueue.invokeLater(new Runnable() { 
     public void run() { 
     GUI gui = new GUI(); 
     gui.setVisible(true); 

     DefaultTableModel model = new DefaultTableModel(
      new String[] { "Column 1", "Column 2" }, 0); 
     JTable table = new JTable(model); 

     gui.add(table); 
     gui.validate(); 

     for (int i = 0; i < 10; i++) { 
      System.out.println("Row " + i); 
      model 
      .addRow(new String[] { "Row", String.valueOf(i) }); 
      // model.fireTableDataChanged(); 

      try { 
      Thread.sleep(250); 
      } catch (InterruptedException e) { 
      e.printStackTrace(); 
      } 

     } 
     } 
    }); 
    } 
} 

class GUI extends JFrame { 
    private static final long serialVersionUID = 1L; 

    public GUI() { 
    setTitle("GUI"); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setBounds(100, 100, 350, 100); 
    setLocationRelativeTo(null); 

    JPanel cp = new JPanel(); 
    cp.setBorder(new EmptyBorder(10, 10, 10, 10)); 
    setContentPane(cp); 
    } 
} 
+2

EDT - ** never never ever ** – kleopatra

+0

EDT는 Event Dispatch Thread의 약자입니다. 왜 이런 일이 일어나는 지 직관적으로 분명해야합니다. :) –

+0

힌트를 주셔서 대단히 감사합니다. 예제를 업데이트했습니다. 나는 그것을 심지어 더 나쁘게 만들었 느냐?! :-) –

답변

1

, 내 최초의 예는 고통 어리석은 실수에서. Peeskillet과 저는 다른 접근 방식을 따르고있었습니다. 필자의 예에서 알 수없는 시간이 걸릴 수 있고 실제로 실패 할 수있는 연결 시도 (다소간)를 나타내는 열 (이 경우에만 다음 열이 재생 될 것입니다.). 따라서 한 번에 행을 추가하는 것은 의미가 없었을 것입니다. (필자의 예가 peeskillet에 이상하게 보였을 것입니다.) SwingWorker를 사용하여 작업을 해결했습니다. 클레오 파트라 (kleopatra)가 지적한 바와 같이, 또 다른 실수가 있었는데, 이것은 이제 수정되었습니다. 여기 내 코드는 다음과 같습니다.

package SwingWorkerExampleCopy; 

import java.util.List; 
import java.util.Random; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.SwingWorker; 
import javax.swing.border.EmptyBorder; 
import javax.swing.table.DefaultTableModel; 
import java.awt.BorderLayout; 

public class SwingWorkerExampleCopy { 
    public static void main(String[] args) { 
    // Show GUI 
    java.awt.EventQueue.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
     GUI gui = new GUI(); 

     DefaultTableModel tableModel = new DefaultTableModel(); 

     // Use a SwingWorker 
     Worker worker = new Worker(tableModel); 
     worker.execute(); 

     JTable table = new JTable(tableModel); 
     table.setEnabled(false); 
     // table.setTableHeader(null); 

     JScrollPane scrollPane = new JScrollPane(table); 
     gui.getContentPane() 
      .add(scrollPane, BorderLayout.CENTER); 

     } 
    }); 
    } 
} 

class GUI extends JFrame { 
    private static final long serialVersionUID = 1L; 

    public GUI() { 
    setTitle("GUI"); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setBounds(100, 100, 350, 400); 
    setLocationRelativeTo(null); 
    setVisible(true); 

    JPanel contentPane = new JPanel(); 
    contentPane.setBorder(new EmptyBorder(10, 10, 10, 10)); 
    contentPane.setLayout(new BorderLayout(0, 0)); 

    setContentPane(contentPane); 
    } 
} 

class Worker extends SwingWorker<DefaultTableModel, Object[]> { 

    private final static int numRows = 10; 
    private final static int numCols = 10; 

    private DefaultTableModel model; 

    Worker(DefaultTableModel model) { 
    this.model = model; 
    model.setColumnCount(numCols); 
    } 

    @Override 
    protected DefaultTableModel doInBackground() throws Exception { 
    // Add row 
    for (int row = 0; row < numRows; row++) { 
     // Build columns 
     for (int col = 0; col < numCols; col++) { 
     if (col == 0) { 
      publish(new Object[] { new String("Row " + row), row, 
      col }); 
     } else { 
      // Simulate a slow source 
      Thread 
      .sleep(new Random().nextInt((250 - 50) + 1) + 50); 

      Boolean isSuccessful = false; 

      // Simulate a return value 
      if (new Random().nextBoolean()) { 
      isSuccessful = true; 
      } 

      publish(new Object[] { 
      new String((isSuccessful == true ? "x" : "o")), row, 
      col }); 

      if (isSuccessful == true) { 
      break; 
      } 
     } 
     } 
    } 

    return model; 
    } 

    @Override 
    protected void process(List<Object[]> chunks) { 
    for (Object[] chunk : chunks) { 
     // chunk[0]: cell value 
     // chunk[1]: number 
     // chunk[2]: column 
     if ((int) chunk[2] == 0) { 
     Object[] row = new Object[numCols]; 
     row[0] = (Object) chunk[0]; 
     model.addRow(row); 
     } else { 
     model.setValueAt((Object) chunk[0], (int) chunk[1], 
      (int) chunk[2]); 
     } 
    } 
    } 
} 
+0

+1 질문 및 답변 :-) – kleopatra

0

코드가 실행되는 동안 다른 이벤트 (예 : 칠하기 이벤트)를 실행할 수 없으므로 완료 될 때까지 이벤트 스레드를 차단합니다.

직접 다시 칠할 수는 있지만 코드가 실행되는 동안 UI는 입력에 응답하지 않습니다. 별도의 작업자 스레드에서 루프를 실행하는 것이 더 나을 것입니다. 필요할 때 invokeLater 또는 invokeAndWait을 사용하여 UI 업데이트를 수행하는 것이 좋습니다.

+0

당신이 끝날 때까지 이벤트 스레드'Thread.sleep (250);에 의해 차단됩니다. – mKorbel

3

되풀이 클레오 파트라 : this answer

enter image description here


편집

I에서 볼 수 있듯이 은 EDT 수면하지 마십시오

당신은 대신 javax.swing.Timer을 사용할 수 있습니다 (그것은 나에게 이상한 모양해서) 코드 엉망 너무 많이 원하지만 나는 그것이 다소 타이머를 추가로 변경하지 않았다

로는 클레오 파트라와 peeskillet 지적
import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.Timer; 
import javax.swing.border.EmptyBorder; 
import javax.swing.table.DefaultTableModel; 

public class Main { 

    static JTable table; 
    static GUI gui; 
    static Processor p = null; 

    public static void main(String[] args) { 
     // Show GUI 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       gui = new GUI(); 

       p = new Processor() { 

        @Override 
        public void execute() { 
         final JTable table = new JTable(p.getTableModel()); 
         final JScrollPane scrollPane = new JScrollPane(table); 
         gui.getContentPane().add(scrollPane, BorderLayout.CENTER); 
         gui.setLocationRelativeTo(null); 
         gui.setVisible(true); 

         Timer timer = new Timer(100, new ActionListener(){ 
          public void actionPerformed(ActionEvent e) { 
           p.processRow(); 
           table.scrollRectToVisible(table.getCellRect(table.getRowCount() - 1, 0, true)); 
          } 
         }); 
         timer.start(); 
        } 
       }; 
       p.execute(); 
      } 
     }); 
    } 
} 

class GUI extends JFrame { 

    private static final long serialVersionUID = 1L; 

    public GUI() { 
     setTitle("GUI"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setBounds(100, 100, 350, 400); 

     JPanel contentPane = new JPanel(); 
     contentPane.setBorder(new EmptyBorder(10, 10, 10, 10)); 
     contentPane.setLayout(new BorderLayout(0, 0)); 

     setContentPane(contentPane); 
    } 
} 

interface Callback { 

    void execute(); 
} 

abstract class Processor implements Callback { 

    private final String[] cols = {"COL", "COL", "COL", "COL", "COL"}; 
    private DefaultTableModel tableModel; 
    int numRows; 
    int numCols; 
    int a, b, c, d, e; 

    Processor() { 
     a = 1; b = 2; c = 3; d = 4; e = 4; 
     numRows = 1000; 
     tableModel = new DefaultTableModel(cols, numCols); 
    } 

    public DefaultTableModel getTableModel() { 
     return tableModel; 
    } 

    public void processRow() { 
     tableModel.addRow(new Object[]{a, b, c, d, e}); 
     a++; b++; c++; d++; e++; 
    } 
} 
+0

예제를 업데이트했습니다. 여전히 뭔가 잘못하고있는 것처럼 보입니다 (심지어 Thread.sleep() 문제를 제거한 후에도). 나는 그것을 얻지 않는다! –

+0

EDT에서 장기간 실행중인 프로세스가 실행 중이므로이를 차단하고 원하는 효과를주지 못합니다. 내가 제안한 것처럼 타이머를 구현하지 않은 이유는 무엇입니까? –

+0

테스트를 위해 그 작업을했지만, 내가하려는 일을하지 않습니다. 작업이 얼마나 오래 걸릴지 전혀 알지 못하기 때문에 이것은 화장품 이상입니다. –