我的问题似乎来自于Swing在内部使用线程的方式。当应用程序执行耗时的任务时,我想显示一个忙碌的指示器,我称之为Spinner。我有一个Swing JDialog并调整了Oracle Tutorial
中的代码如何解决问题?
我有一个startSpinner() - 和一个stopSpinner()方法。他们工作得很好。我有两个显示或隐藏它的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...");
}
}
});
}
停止Spinner方法:
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();
}
}
}
我正在使用教程中的代码,除了main方法,也许这就是问题的原因。解决方案应该是这样的:
private void save(){
startSpinner();
performTimeConsumingSave();
stopSpinner();
}
目前,微调器根本没有显示出来。但是当我显示一个JOptionPane(暂停当前线程)时,它会显示出来。我也试过Thread.sleep(100)但这不是个好主意。
答案 0 :(得分:1)
感谢Michal的评论和帖子How do I use SwingWorker in Java?我能够解决这个问题。现在,SwingWorker会调用具有长时间运行权限的performTimeConsumingSave()。我确实喜欢建议的教程。因此,现在从ActionListener的actionPerformed方法调用SwingWorkers方法doInBackground()。而不是直接从EDT调用save(),而是由SwingWorker完成对save()的调用。为了确定保存是否成功,我正在检查retval。现在,微调器正在显示,系统正在同时执行耗时长的任务(save())。 这是PostWorker代码:
class PostWorker extends SwingWorker<Integer, Integer> {
@Override
protected Integer doInBackground() throws Exception {
// Do a time-consuming task.
starteSpinner();
int status = save();
stopSpinner();
return status;
}
@Override
protected void done() {
try {
if (get()== SAVE_OK) {
JOptionPane.showMessageDialog(PostAusDetailDialog.this, "Mail saved.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}