Invokeandwait을 사용하여 스윙에서 값을 반환합니다
-
18-09-2019 - |
문제
다음 접근 방식을 사용하여 EDT 외부로 스윙에서/에서 구성 요소와 반환 값을 만들었습니다. 예를 들어, 다음 방법은 JFrame
, 만들기 위해 JPanel
부모에게 추가하십시오 JFrame
:
public JPanel threadSafeAddPanel() {
final JPanel[] jPanel = new JPanel[1];
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
jPanel[0] = new JPanel();
add(jPanel[0]);
}
});
} catch (InterruptedException ex) {
} catch (InvocationTargetException ex) {
}
return jPanel[0];
}
로컬 1 길이 배열은 "결과"를 내부에서 전송하는 데 사용됩니다. Runnable
, EDT에서 호출됩니다. 글쎄, 그것은 "약간"해킹 된 것처럼 보이므로 내 질문은 다음과 같습니다.
- 이게 말이 되요? 다른 사람이 이런 일을하고 있습니까?
- 1 길이 배열이 결과를 전송하는 좋은 방법입니까?
- 더 쉬운 방법이 있습니까?
해결책
- 로그인하지 않고 예외를 삼키기 : 나쁜!! - 2 시간 동안 버그 사냥을 한 후 그런 식으로 올 때 자신을 미워할 것입니다.
- 아니요, 배열은 좋은 방법이 아닙니다. 우선, 호출 코드가 EDT 스레드가 실행되기를 기다릴 수있는 쉬운 방법을 제공하지 않습니다.
Runnable
결과를 가져 오기 전에 - 이런 종류의 일에 대해 명시 적으로 설계된 수업이 있습니다.
SwingWorker
다른 팁
어떤 상황에서는 그 방법이 의미가있을 수 있지만 대부분의 시간은 쓸모가 없습니다.
그 이유는 EDT에서 항상 실행되는 사용자 조치 (메뉴 항목 또는 버튼 클릭)의 결과로 대부분의 (전부가 아닌 경우) 구성 요소의 생성이 항상 EDT에서 발생하기 때문입니다.
패널을 만들기 전에 수행해야 할 큰 작업이 있고 EDT를 차단하고 싶지 않은 경우 다른 사람이 제안한대로 Swingworker 또는 긴 작업을 지원하는 스윙 프레임 워크를 사용해야합니다 (일반적으로 어쨌든 내부적으로 스윙 워크 사람이지만 반드시는 아닙니다).
당신의 질문 2와 관련하여, 불행히도 당신은 그렇게 할 방법이 많지 않습니다.
- 당신이했던 것처럼 1 항목 배열을 사용하십시오. 그것은 가장 쉽지만 가장 추악한 솔루션입니다.
- 거의 동일한 작업을 수행하고 좀 더 많은 작업이 필요하고 더 깨끗한 항목 보유자 클래스 (아래 참조)를 만듭니다.
- 마지막으로, java.util.concurrent 시설 (미래 및 호출 가능)을 사용하십시오. 그것은 내가 생각하는 가장 깨끗한 일이지만 가장 많은 노력이 필요합니다.
다음은 단순화 된 항목 보유자 클래스입니다.
public class ItemHolder<T> {
public void set(T item) {...}
public T get() {...}
private T item;
}
- a) 의미가 있습니다. b) 내가 아는 것이 아닙니다.
- 어느 것도 좋습니다.
- 외부에서 jpanel을 만듭니다
invokeAndWait
전화
//이 줄은 MarkDown을 Leacease에 추가했습니다
public JPanel threadSafeAddPanel() {
final JPanel jPanel = new JPanel();
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
add(jPanel);
}
});
} catch (InterruptedException ex) {
} catch (InvocationTargetException ex) {
}
return jPanel;
}
현재 스레드가 EDT인지 쉽게 확인한 다음 해당 컨텍스트에서 단순히 올바르게 실행할 수 있습니다. 리턴 값을 얻기 위해 최종 배열을 사용하는 것은 익명의 내부 클래스를 사용해야하는 가장 쉬운 방법입니다.
public JPanel threadSafeAddPanel() throws InterruptedException,
InvocationTargetException {
if (EventQueue.isDispatchThread()) {
JPanel panel = new JPanel();
add(panel);
return panel;
} else {
final JPanel[] jPanel = new JPanel[1];
EventQueue.invokeAndWait(new Runnable() {
public void run() {
jPanel[0] = new JPanel();
add(jPanel[0]);
}
});
return jPanel[0];
}
}
제휴하지 않습니다 StackOverflow