TrayIcon
뿐만 아니라 JFrame
을 사용하는 java 응용 프로그램이 있으며 TrayIcon
에 PopupMenu
을 추가했습니다.전체 디스패처 스레드를 차지하도록 TrayIcon 팝업을 방지하는 방법
TrayIcon
을 클릭하면 팝업 메뉴가 나타나지만 PopupMenu
이 보이는 한 메인 프레임이 멈 춥니 다.
내 첫 번째 생각은 이벤트 발송 스레드가 누군가에 의해 점유되었다는 것입니다. 그래서 스윙 작업자와 진행률 막대를 사용하는 작은 예제 응용 프로그램을 작성했습니다. 당신이 진행 표시 줄과 프레임을 볼 수 예제 응용 프로그램을 시작할 때
를 재현하는 방법
public class TrayIconTest {
public static void main(String[] args) throws AWTException {
JFrame frame = new JFrame("TrayIconTest");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
JProgressBar jProgressBar = new JProgressBar();
BoundedRangeModel boundedRangeModel = jProgressBar.getModel();
contentPane.add(jProgressBar);
boundedRangeModel.setMinimum(0);
boundedRangeModel.setMaximum(100);
PopupMenu popup = new PopupMenu();
TrayIcon trayIcon =
new TrayIcon(new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB), "TEST");
// Create a popup menu components
MenuItem aboutItem = new MenuItem("About");
popup.add(aboutItem);
trayIcon.setPopupMenu(popup);
SystemTray tray = SystemTray.getSystemTray();
tray.add(trayIcon);
IndeterminateSwingWorker indeterminateSwingWorker = new IndeterminateSwingWorker(boundedRangeModel);
indeterminateSwingWorker.execute();
frame.setSize(640, 80);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class IndeterminateSwingWorker extends SwingWorker<Void, Integer> {
private BoundedRangeModel boundedRangeModel;
public IndeterminateSwingWorker(BoundedRangeModel boundedRangeModel) {
this.boundedRangeModel = boundedRangeModel;
}
@Override
protected Void doInBackground() throws Exception {
int i = 0;
long start = System.currentTimeMillis();
long runtime = TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES);
while (true) {
i++;
i %= boundedRangeModel.getMaximum();
publish(i);
Thread.sleep(20);
long now = System.currentTimeMillis();
if ((now - start) > runtime) {
break;
}
System.out.println("i = " + i);
}
return null;
}
@Override
protected void process(List<Integer> chunks) {
for (Integer chunk : chunks) {
boundedRangeModel.setValue(chunk);
}
}
}
.
SwingWorker
은 진행 작업을 시뮬레이션합니다. 진도 값을 게시하고 System.out
으로 인쇄합니다.
트레이 아이콘 ('검은 색')을 클릭하면 진행률 표시 줄이 멈추고 팝업 메뉴가 나타납니다. 진도 값을 명령 줄에 출력하기 때문에 SwingWorker가 백그라운드에서 계속 실행되고 있음을 알 수 있습니다.
조사는 그래서 jvisualvm
를 사용하여 응용 프로그램에서 확인해 보니 이벤트 디스패처 스레드가 한 팝업을 볼 수 있습니다로 매우 바쁘다을 보여줍니다.
나는 팝업에서 그 모습을 알아낼 수는 방법 sun.awt.windows.WTrayIconPeer.showPopupMenu(int, int)
에 의해 가시화된다.
이 메서드는 EventQueue.invokeLater
을 사용하여 실행 파일을 이벤트 발송 스레드에 전달합니다. 이 실행 가능 파일에서 메소드 sun.awt.windows.WPopupMenuPeer._show
이 호출됩니다. 이 메서드는 native
및 이므로이 메서드는 이벤트 처리 스레드가 완전히 채워지도록 busy wait 루프를 구현하는 것 같습니다. 다른 Ui 관련 작업은 팝업 메뉴가 표시된 동안에는 실행되지 않습니다.
누구든지 TrayIcon
팝업이 표시되는 동안 이벤트 발송 스레드가 반응하도록하는 해결 방법을 알고 있습니까?