2014-05-21 1 views
2

내 응용 프로그램에서 보고서를 생성합니다. 작업 시간은 몇 초에서 최대 몇 시간입니다. 사용자에게 알리기 위해 ProgressMonitorDialog을 사용합니다. 항상 약 70 분 후 InvocationTargetException이 던졌습니다. 왜 이런 일이 일어나는지 모르겠습니다.ProgressMonitorDialog 및 InvocationTargetException의 취소 단추

try { 
    new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() { 
     @Override 
     public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { 
      monitor.beginTask("Something...", IProgressMonitor.UNKNOWN); 
      controller.generate(model); 
      monitor.done(); 
     } 
    }); 
} catch (InvocationTargetException | InterruptedException e) { 
    logger.error(e); 
} 

스택 추적은 :

java.lang.reflect.InvocationTargetException 
    at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:421) 
    at org.eclipse.jface.dialogs.ProgressMonitorDialog.run(ProgressMonitorDialog.java:507) 
    at pl.edu.prz.allegroapi.gui.report.ProductReport$4.widgetSelected(ProductReport.java:323) 
    at org.eclipse.swt.widgets.TypedListener.handleEvent(Unknown Source) 
    at org.eclipse.swt.widgets.EventTable.sendEvent(Unknown Source) 
    at org.eclipse.swt.widgets.Widget.sendEvent(Unknown Source) 
    at org.eclipse.swt.widgets.Display.runDeferredEvents(Unknown Source) 
    at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source) 
    at pl.edu.prz.allegroapi.gui.report.ProductReport.open(ProductReport.java:91) 
    at pl.edu.prz.allegroapi.gui.MainWindow$2.widgetSelected(MainWindow.java:126) 
    at org.eclipse.swt.widgets.TypedListener.handleEvent(Unknown Source) 
    at org.eclipse.swt.widgets.EventTable.sendEvent(Unknown Source) 
    at org.eclipse.swt.widgets.Widget.sendEvent(Unknown Source) 
    at org.eclipse.swt.widgets.Display.runDeferredEvents(Unknown Source) 
    at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source) 
    at pl.edu.prz.allegroapi.gui.MainWindow.open(MainWindow.java:75) 
    at pl.edu.prz.allegroapi.tasks.CreateGuiTask.doStartup(CreateGuiTask.java:46) 
    at pl.edu.prz.allegroapi.tasks.CreateGuiTask.access$0(CreateGuiTask.java:42) 
    at pl.edu.prz.allegroapi.tasks.CreateGuiTask$1.run(CreateGuiTask.java:31) 
    at java.lang.Thread.run(Unknown Source) 
Caused by: org.eclipse.swt.SWTException: Invalid thread access 
    at org.eclipse.swt.SWT.error(Unknown Source) 
    at org.eclipse.swt.SWT.error(Unknown Source) 
    at org.eclipse.swt.SWT.error(Unknown Source) 
    at org.eclipse.swt.widgets.Widget.error(Unknown Source) 
    at org.eclipse.swt.widgets.Widget.checkWidget(Unknown Source) 
    at org.eclipse.swt.widgets.Dialog.checkParent(Unknown Source) 
    at org.eclipse.swt.widgets.Dialog.<init>(Unknown Source) 
    at org.eclipse.swt.widgets.MessageBox.<init>(Unknown Source) 
    at pl.edu.prz.allegroapi.gui.report.ProductReportController.generate(ProductReportController.java:59) 
    at pl.edu.prz.allegroapi.gui.report.ProductReport$4$1.run(ProductReport.java:335) 
    at org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:121) 

두 번째 문제는 일의 진행 창을 취소 할 수 있습니다. "취소"버튼을 누르면, isCanceled() 메서드는 true를 반환합니다. 나는 다음과 같은 해결책을 시도했지만 변수 출구가 최종이 될 수는 없으므로 작동하지 않는다.

Boolean exit = false; 
display.asyncExec(new Runnable() { 
    public void run() { 
     controller.generate(model); 
     exit=true; 
    } 
}); 
try { 
    new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() { 
     @Override 
     public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { 
      try { 
       monitor.beginTask("Something...", IProgressMonitor.UNKNOWN); 
       while(!monitor.isCanceled() && !exit) { 
        Thread.sleep(1000); 
       } 
      } finally { 
       monitor.done(); 
      } 
     } 
    }); 
} catch (InvocationTargetException | InterruptedException e) { 
    e.printStackTrace(); 
} 
+0

내 대답에 대한 의견이 있으십니까? – Baz

+0

잘못된 액세스 문제가 해결되었습니다. 예외 발생시 generate() 메소드가 MessageBox로 표시되었습니다. 불행히도, 우리는 여전히 긴 작업을 취소 할 수있는 가능성에 문제가 있습니다 (문제의 두 번째 부분에 설명 된 문제). – Giver

+0

내 대답이 업데이트되었습니다. – Baz

답변

2

"잘못된 스레드 액세스"라는 가장 일반적인 SWT 예외가 발생했습니다.

기본적으로 UI 스레드가 아닌 스레드에서 UI를 업데이트하려고한다는 것을 의미합니다. 특정 기술을 사용하지 않는 한 SWT에서는 허용되지 않습니다.

자세한 내용은 in the official wiki을 참조하십시오.


당신이 게시 코드는 아마 다른 곳 controller.generate(model);에서, 당신은 문제가있어 확인 될 것으로 보인다. 관련 코드를 보지 않고는 더 이상 당신을 도울 수 없습니다. 한편

, 이것은이 아닌 UI 스레드에서 UI와 상호 작용하는 방법입니다 :

확인

Display.getDefault().asyncExec(new Runnable() { 
    public void run() { 
     ... do any work that updates the screen ... 
    } 
}); 

UPDATE, 여기 업데이트는해야하다 을 Display#asyncExec()과 조합하여 사용하는 방법을 보여줍니다.

public static void main(String[] args) 
{ 
    final Display display = new Display(); 
    final Shell shell = new Shell(display); 
    shell.setText("StackOverflow"); 
    shell.setLayout(new GridLayout(1, false)); 

    final Label label = new Label(shell, SWT.NONE); 

    Button button = new Button(shell, SWT.PUSH); 
    button.setText("Start"); 
    button.addListener(SWT.Selection, new Listener() 
    { 
     @Override 
     public void handleEvent(Event arg0) 
     { 
      try 
      { 
       new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() 
       { 
        @Override 
        public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException 
        { 
         try 
         { 
          monitor.beginTask("Something...", IProgressMonitor.UNKNOWN); 

          for (int i = 0; i < 100; i++) 
          { 
           /* Check if the monitor has been canceled */ 
           if (monitor.isCanceled()) 
            return; 

           try 
           {/* Only wrap the UI interaction in the asyncExec */ 
            doFancyUIStuff(label, i); 
            Thread.sleep(100); 
           } 
           catch (InterruptedException e) 
           { 
            e.printStackTrace(); 
           } 
          } 
         } 
         finally 
         { 
          monitor.done(); 
         } 
        } 
       }); 
      } 
      catch (InvocationTargetException e) 
      { 
       e.printStackTrace(); 
      } 
      catch (InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 
     } 
    }); 

    shell.pack(); 
    shell.open(); 

    while (!shell.isDisposed()) 
    { 
     while (!display.readAndDispatch()) 
     { 
      display.sleep(); 
     } 
    } 
} 

private static void doFancyUIStuff(final Label label, final int index) 
{ 
    Display.getDefault().asyncExec(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      label.setText(index + ""); 
      label.getParent().layout(); 
     } 
    }); 
} 

실제 UI 상호 작용 만이 Display.asyncExec()에 래핑됩니다. 이렇게하면 각 반복에서 monitor.isCanceled()을 계속 확인할 수 있습니다.

+0

나는 당신에게 대답하려고했습니다. 그렇지 않으면 SWT 스레드 오류가 발생합니다. 어떤 이유로 asyncExec가 활성화되지 않고 취소 버튼을 누를 수 없습니다. 아마 모든 문제의 근원은 포크이지만 길을 찾을 수는 없습니다. [링크] (http://stackoverflow.com/questions/26756068/eclipse-rcp-stopping-a-thread-job-that-freezes) – 2c00L

관련 문제