你正在呼唤doInBackground()
直接从您的代码中,类似于调用run()
直接在可运行程序中。这意味着您的代码实际上并不是在后台线程上运行,因此您可能会用长时间运行的代码破坏事件线程,从而阻止 Swing GUI 和进度栏更新。
解决方案:不要这样做。称呼execute()
当您希望它运行时,在您的工作人员上。
如果您需要进一步的帮助,您首先必须帮助我们。您知道您发布了大量代码,其中大部分与您手头的问题完全无关,而且肯定超出了您应该要求志愿者完成的代码。请删除所有无关的不相关代码,而是创建并发布适当的代码MCVE https://stackoverflow.com/help/mcve.
Edit
您似乎还直接从 EDT 调用代码,这些代码应该留给您的工作线程:
signalSimulator.execute();
// ************* all these signalSimulator calls below ***********
if (rdbtnSineWave.isSelected()) {
data = signalSimulator.generateSineWave(numOfdataPoints,
noiseAmp, offset);
data = signalSimulator.addAnomalies(data, numOfLocalSpikes,
numOfExpSpikes);
} else { // Linear signal is selected
data = signalSimulator.generateLinearSignal(numOfdataPoints,
noiseAmp, slope, offset);
data = signalSimulator.addAnomalies(data, numOfLocalSpikes,
numOfExpSpikes);
}
signalSimulator.writeLogFile(path, ".txt", data);
您似乎也只创建oneworker 对象,这是不正确的,因为您无法重用 SwingWorker 对象。
我建议您仅在需要时创建 SwingWorker 对象,并将需要什么类型的信号的信息传递到其构造函数中。这样,上述方法就可以从它们所属的 SwingWorker 的 doInBackground 方法中调用。
e.g.,
signalSimulator = SignalSimulator(rdbtnSineWave.isSelected())
signalSimulator.addPropertyChangeListener(...);
signalSimulator.execute();
请注意,您发布的代码中还有一些其他重要的不相关问题,但它们必须在其他时间解决,但它们包括使用 null 布局和 setBounds,这几乎总是一个非常糟糕的主意。
Edit
再次澄清一下,您的主要问题是您在 Swing 事件线程上调用长时间运行的代码。仅仅因为方法位于 Worker 类中并不意味着调用它会自动使其在后台线程上运行。保证这一点的唯一方法是从您的内部调用代码doInBackground()
方法。同样,您要做的是创建新的工作对象当需要的时候例如,在某个 ActionListener 内部,在创建它时,将其运行所需的所有信息传递给它。然后添加您的 PropertyChangeListener,然后.execute()
你的工人。这样做,我敢打赌你的代码会工作得更好。
Edit
例如
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class ProgressExampleGui {
private JPanel mainPanel = new JPanel();
private JProgressBar progressBar = new JProgressBar();
private JButton pressMeBtn = new JButton(new MyAction("Press Me", KeyEvent.VK_P, this));
public ProgressExampleGui() {
progressBar.setStringPainted(true);
progressBar.setString("");
mainPanel.add(pressMeBtn);
mainPanel.add(progressBar);
}
public void setProgress(int progress) {
progressBar.setValue(progress);
progressBar.setString(progress + "%");
}
public JComponent getMainComponent() {
return mainPanel;
}
public void setEnabled(boolean enabled) {
pressMeBtn.setEnabled(enabled);
}
private static void createAndShowGui() {
ProgressExampleGui progExampleGui = new ProgressExampleGui();
JFrame frame = new JFrame("Progress Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(progExampleGui.getMainComponent());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
@SuppressWarnings("serial")
class MyAction extends AbstractAction {
private ProgressExampleGui gui;
public MyAction(String name, int mnemonic, ProgressExampleGui gui) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
this.gui = gui;
}
@Override
public void actionPerformed(ActionEvent e) {
AbstractButton source = (AbstractButton) e.getSource();
gui.setProgress(0);
source.setEnabled(false);
MyWorker myWorker = new MyWorker();
myWorker.addPropertyChangeListener(new WorkerPropChngListener(gui));
myWorker.execute();
}
}
class WorkerPropChngListener implements PropertyChangeListener {
private ProgressExampleGui gui;
public WorkerPropChngListener(ProgressExampleGui gui) {
this.gui = gui;
}
@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
MyWorker myWorker = (MyWorker) pcEvt.getSource();
if ("progress".equals(pcEvt.getPropertyName())) {
int progress = ((Integer)pcEvt.getNewValue()).intValue();
gui.setProgress(progress);
}
if (SwingWorker.StateValue.DONE.equals(pcEvt.getNewValue())) {
try {
myWorker.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
gui.setEnabled(true);
}
}
}
class MyWorker extends SwingWorker<Void, Void> {
private static final int MAX_INCR = 8;
private static final long SLEEP_TIME = 200;
private static final int MAX_VALUE = 100;
private int value = 0;
private Random random = new Random();
@Override
protected Void doInBackground() throws Exception {
while (value < MAX_VALUE) {
value += random.nextInt(MAX_INCR);
value = Math.min(value, MAX_VALUE);
Thread.sleep(SLEEP_TIME);
setProgress(value);
}
return null;
}
}
Edit
关于你的新代码,你有两个main问题:
看看你的数据输出结果:
Value in setProgress: 0.0
Value in setProgress: 0.001
Value in setProgress: 0.002
Value in setProgress: 0.003
Value in setProgress: 0.004
Value in setProgress: 0.005
Value in setProgress: 0.006
Value in setProgress: 0.007
Value in setProgress: 0.008
Value in setProgress: 0.009
Value in setProgress: 0.01
Value in setProgress: 0.011
Value in setProgress: 0.012
Value in setProgress: 0.013
Value in setProgress: 0.014
Value in setProgress: 0.015
Value in setProgress: 0.016
Value in setProgress: 0.017
Value in setProgress: 0.018
Value in setProgress: 0.019
Value in setProgress: 0.02
Value in setProgress: 0.021
Value in setProgress: 0.022
Value in setProgress: 0.023
Value in setProgress: 0.024
Value in setProgress: 0.025
Value in setProgress: 0.026
Value in setProgress: 0.027
Value in setProgress: 0.028
Value in setProgress: 0.029
按照这个速度,当下一个冰河时代到来时,您的进度值将达到 1,并导致 PropertyChangeListener 和 JProgressBar 发生明显变化。所以首先,改变你的睡眠时间,并将你的大数字改为更合理的数字。
接下来,隐藏重要的变量,特别是 JProgressBar 变量,progressBar。这是在类中声明它并初始化它的位置:
public class ProgressBarTest implements PropertyChangeListener {
private JFrame frame;
private JButton btnRun;
static JProgressBar progressBar = new JProgressBar(0, 100);
附带说明一下,这个变量绝对不应该被声明static
,但这不是您当前问题的原因。原因是你事实上重新声明在初始化方法中的其他地方使用相同的变量,然后将这个新对象添加到 GUI 中:
private void initialize() {
frame = new JFrame();
// .....
JProgressBar progressBar = new JProgressBar();
// .....
frame.getContentPane().add(progressBar);
请理解,这个新的 ProgressBar 变量引用了一个完全不同的 JProgressBar,因此,如果您提前在类中创建的对象的值,您的 GUI 将不会显示任何内容,因为它正在显示一个完全不同的对象。要解决这个问题,**不要在初始化方法中重新声明和初始化新变量。而是使用在类中创建的对象。
代码的其他问题:您经常使用 null 布局和 setBounds。这将向所有人表明您是一名新手 Swing 程序员,因为这意味着您喜欢创建极其难以升级的死板程序,并且可能在所有系统上看起来都不太好。而是使用布局管理器。例如,这是您的代码,进行了一些更改,所有更改均由注释注明:
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
//!! no need to implement PropertyChangeListener
//!! public class ProgressBarTest implements PropertyChangeListener {
public class ProgressBarTest2 {
private JFrame frame;
private JButton btnRun;
// !! this shouldn't be static!
// !! static JProgressBar progressBar = new JProgressBar(0, 100);
private JProgressBar progressBar = new JProgressBar(0, 100); // !!
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager
.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
ProgressBarTest2 window = new ProgressBarTest2();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public ProgressBarTest2() {
initialize();
}
private void initialize() {
frame = new JFrame();
// !!frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//!! frame.getContentPane().setLayout(null); //!! never use null layouts
frame.setResizable(false);
// !! don't create a shadowed variable
// !! JProgressBar progressBar = new JProgressBar();
progressBar.setAlignmentX(Component.RIGHT_ALIGNMENT);
//!! progressBar.setBounds(0, 252, 444, 20);
progressBar.setStringPainted(true);
//!! frame.getContentPane().add(progressBar);
frame.getContentPane().add(progressBar, BorderLayout.SOUTH);
btnRun = new JButton("Start Long Run"); //!! no shadowing
//!! btnRun.setBounds(167, 214, 159, 31);
JPanel panel = new JPanel(); //!!
panel.setPreferredSize(new Dimension(450, 300)); //!!
panel.setLayout(new GridBagLayout()); //!!
panel.add(btnRun); //!!
frame.getContentPane().add(panel, BorderLayout.CENTER); //!!
btnRun.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
longRun();
}
});
//!!
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void longRun() {
//!! use a more realistic value, one that should show change in listener
//!! LongRunner longRunner = new LongRunner(100000);
LongRunner2 longRunner = new LongRunner2(10000);
longRunner.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
int progress = (int) evt.getNewValue();
System.out.println("Value in propertyChangeListener: "
+ progress);
progressBar.setValue(progress);
}
}
});
longRunner.execute();
}
// !! @Override // !! not needed
// public void propertyChange(PropertyChangeEvent evt) {
// }
}
class LongRunner2 extends SwingWorker<Integer, Double> {
private static final long SLEEP_TIME = 15; // !!
int numOfPoints;
double progress;
public LongRunner2(int numOfPoints) {
this.numOfPoints = numOfPoints;
this.progress = 0;
}
private void runLong(int bigNum) {
for (int i = 0; i < bigNum; i++) {
try {
// !! quicker turn-over so that our bigNum can change
// in a realistic way
// !! Thread.sleep(100);
Thread.sleep(SLEEP_TIME);// !!
} catch (InterruptedException e) {
e.printStackTrace();
}
progress = (((double) i * 100) / (double) bigNum);
setProgress((int) progress);
// !! System.out.println("Value in setProgress: " + progress); //!! This will slow us down
}
}
@Override
protected Integer doInBackground() throws Exception {
runLong(numOfPoints);
return null;
}
}