0

죄송합니다, 긴 비트,하지만 내 응용 프로그램에서 예상대로SwingWorker의 과정() GUI 업데이트 어려움이

SwingWorker의 내가 '하나 결절 문제를 제외하고 완전히 작동 ... 조금 관여 API가 완벽하게 가능하고 정상이라고 명시하기 때문에, 청크가 프로세스 (들)에 도착할 때, 해결하기 위해 고심하고있다.

문제는 예를 들어 "일이 일어났습니다. 잠시 기다려주십시오"라는 메시지로 시작하는 JDialog가있는 경우입니다. 따라서 doInBackground()에 청크가 게시되어 process()에 도착하고 JDialog가 설정됩니다.

doInBackground의 긴 작업이 완료되면 2 개의 추가 명령을 "게시"합니다. 하나는 "JDialog의 메시지를"GUI 업데이트를 기다리는 중 "으로 변경하고 다른 하나는"결과로 JTable 채우기 "라고 말합니다. 나는 너를 보내고있어. "

이 점에 대해 요점은, JTable에 많은 양의 새로운 데이터를 보내서 TableModel의 벡터를 대체한다면 실제로 Swing이 무시할 수없는 시간을 가져 와서 ... 원하는 이유 때문입니다. 사용자에게 "길어진 작업이 끝났지 만 지금은 스윙이 GUI를 업데이트 할 때까지 기다리고 있습니다"라고 말합니다.

이상한 점은이 두 명령어가 2 개의 합쳐진 청크로 도착하면 JDialog가 부분적으로 만 업데이트 될 수 있다는 것입니다. setTitle ("blab")은 JDialog의 제목이 변경됨을 의미하지만 다른 모든 것은 변경됩니다. JDialog에 대한 변경은 JTable의 메인 GUI 업데이트가 끝날 때까지 보류됩니다.

청크 게시 사이에 doInBackground에서 약간의 지연이 발생하도록 JDialog가 업데이트하므로 문제가 발생합니다. 분명히, 합쳐진 덩어리로 나는 루프를 하나씩 차례로 사용하고 있습니다. 그래서 각 루프의 끝 부분에 타이머를 두는 것을 생각했습니다. 이것은 아무런 효과가 없었다.

나는 또한 JDialog에서 "유효성 검사"와 "페인트"및 "다시 칠하기"의 수많은 순열을 시도했습니다.

질문은 다음과 같습니다. GUI가 통합 된 청크를 처리하는 반복 사이에서 process() 내에서 자체를 업데이트하려면 어떻게해야합니까?

NB 나는 또한 다른 것을 시도했다 : 그것이 여러 개인 경우 청크를 재 게시했다. 이것의 문제는 사물의 비동기 성질을 감안할 때, doInBackground로 되돌아 가면 청크가 잘못된 순서로 게시된다는 결과를 낳을 수밖에 없는데, 앞으로도 계속해서 일들이 출판 될 것입니다. 게다가, 이런 종류의 해결책은 정당하지 못합니다.

import javax.swing.*; 
import javax.swing.table.*; 
import java.awt.*; 
import java.util.*; 


class Coalescence extends SwingWorker<Object, Object> { 
    int DISPLAY_WAIT_FOR_TASK = 0; int DISPLAY_WAIT_FOR_GUI_UPDATE = 1; int UPDATE_TABLE_IN_GUI = 2; int SET_UP_GUI = 3; 

    private Object[][] m_dataTable; 
    private JTable m_table; 
    private JFrame m_frame; 
    private JOptionPane m_pane; 
    private JDialog m_jDialog; 
    private FontMetrics m_fontMetrics; 
    private Dimension m_intercellSpacing; 

    @Override 
    protected Object doInBackground() throws Exception { 
     publish(SET_UP_GUI); 
     publish(DISPLAY_WAIT_FOR_TASK); 
     Random rand = new Random(); 
     String s = "String for display, one two three four five six seven eight"; 
     m_dataTable = new Object[ 20000 ][]; 
     for(int i = 0; i < 20000; i++){ 
      Object[] row = new Object[ 20 ]; 
      for(int j = 0; j < 20; j++){ 
       // random length string - so column width computation has something to do... 
       int endIndex = rand.nextInt(40); 
       row[ j ] = s.substring(0, endIndex); 
      } 
      m_dataTable[ i ] = row; 
      // slow the "lengthy" non-EDT task artificially for sake of SSCCE 
      if(i % 10 == 0) 
       Thread.sleep(1L); 
     } 

     publish(DISPLAY_WAIT_FOR_GUI_UPDATE); 

     // *** LINE TO COMMENT OUT *** 
     Thread.sleep(100L); 

     publish(UPDATE_TABLE_IN_GUI); 

     return null; 
    } 



    protected void process(java.util.List<Object> chunks){ 
     p("no chunks " + chunks.size()); 

     // "CHUNK PROCESSING LOOP" 
     for(int i = 0, n_chunks = chunks.size(); i < n_chunks; i++){ 
      int value = (Integer)chunks.get(i); 

      p("processing chunk " + value); 

      if(value == SET_UP_GUI){ 
       m_frame = new JFrame(); 
       m_frame.setPreferredSize(new Dimension(800, 400)); 
       m_frame.setVisible(true); 
       JScrollPane jsp = new JScrollPane(); 
       jsp.setBounds(10, 10, 600, 300); 
       m_frame.getContentPane().setLayout(null); 
       m_frame.getContentPane().add(jsp); 
       m_table = new JTable(); 
       jsp.setViewportView(m_table); 
       m_frame.pack(); 
      m_fontMetrics = m_table.getFontMetrics(m_table.getFont()); 
      m_intercellSpacing = m_table.getIntercellSpacing(); 
      } 
      else if(value == DISPLAY_WAIT_FOR_TASK){ 
     m_pane = new JOptionPane("Waiting for results..."); 
     Object[] options = { "Cancel" }; 
     m_pane.setOptions(options); 
     // without these 2 sQLCommand, just pressing Return will not cause the "Cancel" button to fire 
     m_pane.setInitialValue("Cancel"); 
     m_pane.selectInitialValue(); 
     m_jDialog = m_pane.createDialog(m_frame, "Processing"); 
     m_jDialog.setVisible(true); 

      } 
      else if (value == DISPLAY_WAIT_FOR_GUI_UPDATE){ 
       // this if clause changes the wording of the JDialog/JOptionPane (and gets rid of its "Cancel" option button) 
       // because at this point we are waiting for the GUI (Swing) to update the display 
     m_pane.setOptions(null); 
     m_pane.setMessage("Populating..."); 
     m_jDialog.setTitle("Table being populated..."); 
      } 
      else if (value == UPDATE_TABLE_IN_GUI){ 
       Object[] headings = { "one", "two", "three", "four", "five", "six", "one", "two", "three", "four", "five", "six", 
         "one", "two", "three", "four", "five", "six", "19", "20" }; 
       m_table.setModel(new javax.swing.table.DefaultTableModel(m_dataTable, headings)); 

       // lengthy task which can only be done in the EDT: here, computing the preferred width for columns by examining 
       // the width (using FontMetrics) of each String in each cell... 
       for(int colIndex = 0, n_cols = 20; i < n_cols; i++){ 
       int prefWidth = 0; 
       javax.swing.table.TableColumn column = m_table.getColumnModel().getColumn(colIndex); 
       int modelColIndex = m_table.convertColumnIndexToModel(colIndex); 
       for(int rowIndex = 0, n_rows = m_table.getRowCount(); rowIndex < n_rows; rowIndex++){ 
       Object cellObject = m_table.getModel().getValueAt(rowIndex, modelColIndex); 
       DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)m_table.getCellRenderer(rowIndex, colIndex); 
       int margins = 0; 
       if(renderer instanceof Container){ 
        Insets insets = renderer.getInsets(); 
        margins = insets.left + insets.right ; 
       } 
       Component comp = renderer.getTableCellRendererComponent(m_table, cellObject, true, false, rowIndex, colIndex); 
       if(comp instanceof JLabel){ 
        String cellString = ((JLabel)comp).getText(); 
        int width = SwingUtilities.computeStringWidth(m_fontMetrics, cellString) + margins; 
        // if we have discovered a String which is wider than the previously set widest width String... change prefWidth 
        if(width > prefWidth){ 
        prefWidth = width; 
        } 
       } 
       } 
       prefWidth += m_intercellSpacing.width; 
       column.setPreferredWidth(prefWidth); 
      // slow things in EDT down a bit (artificially) for the sake of this SSCCE... 
      try { 
      Thread.sleep(20L); 
      } catch (InterruptedException e) { 
      e.printStackTrace(); 
      } 

       } 
       m_jDialog.dispose(); 
      } 
     } 
    } 

    public static void main(String[] a_args){ 
     Coalescence c = new Coalescence(); 
     c.execute(); 
     try { 
     c.get(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    } 

    static void p(String s){ 
     System.out.println(s); 
    } 

} 

... 프로그램이 5 단계로 구성된다 : 1))에 GUI 2를 설정 "라는 메시지를 넣어의 요청에 따라

나중에 ... 는 여기 SSCCE이다 작업이 완료 될 때까지 기다리십시오. "3)"EDT가 아닌 "긴급 작업 4) 메시지를 변경하여"GUI가 테이블을 업데이트 할 때까지 기다리십시오. "5) GUI에서 테이블 업데이트 (처분) JDialog/JOptionPane의

위의 doInBackground에서 Thread.sleep() 행을 주석 처리하면 JDialog가 이상하게 작동합니다. 제목이 업데이트되지만 JOptionPane의 텍스트는 변경되지 않습니다. "취소"버튼은 제거되지 않습니다.

차이점은 Thread.sleep() 라인이 없으면 두 개의 청크가 합쳐져서 EDT에서 하나씩 수행된다는 것입니다.나는 "청크 처리 루프"의 끝에 짧은 Timer를 실행하고 Thread.yield()를 실험하는 등의 작업을 시도했다. 기본적으로 GUI가 JDialog와 모든 구성 요소를 포괄적으로 업데이트하도록하고있다. .JTable을 업데이 트하기 전에 이동 ...

어떤 생각 감사.

+0

이 다음은 [sscce (http://sscce.org/) 해당 전시물을 제공 당신이 묘사하는 문제. – trashgod

+0

@trashgod 공정한 점 ... 그것에 작동합니다. 내가 자바보다는 자이 썬을 사용하고 있지만 하나를 부스리기 위해 노력할 것입니다 –

+1

여기에 최소한의 예가 있습니다 [여기] (http://stackoverflow.com/questions/4637215/can-a-progress-bar-be-used-in- a-class-outside-main/4637725 # 4637725) 및 [여기] (https://sites.google.com/site/drjohnbmatthews/randomdata)를 참조하십시오. 점진적으로 변경하지 않고 전체 모델을 한 번에 업데이트하는 것처럼 들립니다. – trashgod

답변