Swing이 내부적으로 스레드를 사용하는 방식에서 내 문제가 발생하는 것으로 보입니다. 응용 프로그램이 Spinner라고 부르는 시간이 많이 걸리는 작업을 수행 할 때 Busy Indicator를 보여주고 싶습니다. Swing JDialog를 사용하여 코드를 변경했습니다. Oracle TutorialJava Swing은 시간이 많이 걸리는 작업 중에 BusyIndicator를 표시합니다.
어떻게 수정합니까?
startSpinner() - 및 stopSpinner() - 메서드가 있습니다. 그들은 완벽하게 작동하고 있습니다. 2 개의 JButton을 표시하거나 숨 깁니다. 하지만 문제는 startSpinner() 메서드를 호출 할 때 약 5 초 동안 실행되는 작업을 수행하는 동안 스피너 이 표시되지 않는다는 것입니다. 나는 SwingUtilities.invokeLater를 다루어야한다고 생각한다. 하지만 나는 그것에 대한 경험이 없습니다. 스피너의 디스플레이를 시작하는 나의 방법.
StartSpinner 방법 :
private void startSpinner() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
layerUI.start();
if (!stopper.isRunning()) {
stopper.start();
setTitle("Working...");
}
}
});
}
정지 스피너 방법 :
public void stopSpinner() {
logger.info("stopSpinner");
layerUI.stop();
}
WaitLayerUI 클래스 : 나는 주요 방법을 제외하고, 튜토리얼의 코드를 사용하고
package view;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import javax.swing.JComponent;
import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.plaf.LayerUI;
@SuppressWarnings("serial")
class WaitLayerUI extends LayerUI<JPanel> implements ActionListener {
private boolean mIsRunning;
private boolean mIsFadingOut;
private Timer mTimer;
private int mAngle;
private int mFadeCount;
private int mFadeLimit = 15;
@Override
public void paint(Graphics g, JComponent c) {
int w = c.getWidth();
int h = c.getHeight();
// Paint the view.
super.paint(g, c);
if (!mIsRunning) {
return;
}
Graphics2D g2 = (Graphics2D) g.create();
float fade = (float) mFadeCount/(float) mFadeLimit;
// Gray it out.
Composite urComposite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f * fade));
g2.fillRect(0, 0, w, h);
g2.setComposite(urComposite);
// Paint the wait indicator.
int s = Math.min(w, h)/5;
int cx = w/2;
int cy = h/2;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(s/4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.setPaint(Color.white);
g2.rotate(Math.PI * mAngle/180, cx, cy);
for (int i = 0; i < 12; i++) {
float scale = (11.0f - i)/11.0f;
g2.drawLine(cx + s, cy, cx + s * 2, cy);
g2.rotate(-Math.PI/6, cx, cy);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, scale * fade));
}
g2.dispose();
}
@Override
public void actionPerformed(ActionEvent e) {
if (mIsRunning) {
firePropertyChange("tick", 0, 1);
mAngle += 3;
if (mAngle >= 360) {
mAngle = 0;
}
if (mIsFadingOut) {
if (--mFadeCount == 0) {
mIsRunning = false;
mTimer.stop();
}
} else if (mFadeCount < mFadeLimit) {
mFadeCount++;
}
}
}
public void start() {
if (mIsRunning) {
return;
}
// Run a thread for animation.
mIsRunning = true;
mIsFadingOut = false;
mFadeCount = 0;
int fps = 24;
int tick = 1000/fps;
mTimer = new Timer(tick, this);
mTimer.start();
}
public void stop() {
mIsFadingOut = true;
}
@Override
public void applyPropertyChange(PropertyChangeEvent pce, JLayer l) {
if ("tick".equals(pce.getPropertyName())) {
l.repaint();
}
}
}
, 어쩌면 이것이 문제의 원인입니다. 해결책은 다음과 같아야합니다.
private void save(){
startSpinner();
performTimeConsumingSave();
stopSpinner();
}
현재 스피너가 표시되지 않습니다. 그러나 JOptionPane (현재 스레드를 일시 중지)을 표시하면 나타납니다. Thread.sleep (100)도 시도했지만 좋은 생각이 아니 었습니다.
내가 performTimeConsumingSave은 EDT에서 실행되어 있지 않은지 확인합니다 : 다음은 PostWorker 코드입니다. 어쩌면 당신의 회 전자가 시작되도록 설정되어 있지만, 당신의 행동이 EDT에 있기 때문에 아무 것도하지 않을 것입니다. 그리고 바로 stopSpinner()가 호출 된 직후에 끝납니다. 또한 stopSpinner()는 이상하게 보입니다. 메시지를 기록하는 것이 유일한 방법일까요? – NESPowerGlove
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html을보십시오 – Michal
아, 죄송합니다 @ NESPowerGlove 제가 코드를 줄이는 동안 너무 많이 지워 버렸습니다. stop() 메서드를 호출하고 타이머를 중지합니다. –