Java Can';无法从SwingWorker类获取要更新的JProgressBar
我有一个主要的GUI线程,其中有一个JprogressBar,正在实现propertyChangeListener 当按下一个按钮时,另一个扩展SwingWorker的类将启动并执行一系列可能很长的计算。 我需要类A中的进度条根据类B中的变量显示进度 我的代码如下(可能有点混乱,因为我所有的尝试都失败了…) 非常感谢您的帮助 GUI类:Java Can';无法从SwingWorker类获取要更新的JProgressBar,java,swing,swingworker,jprogressbar,Java,Swing,Swingworker,Jprogressbar,我有一个主要的GUI线程,其中有一个JprogressBar,正在实现propertyChangeListener 当按下一个按钮时,另一个扩展SwingWorker的类将启动并执行一系列可能很长的计算。 我需要类A中的进度条根据类B中的变量显示进度 我的代码如下(可能有点混乱,因为我所有的尝试都失败了…) 非常感谢您的帮助 GUI类: SignalSimulator signalSimulator = new SignalSimulator( path, num
SignalSimulator signalSimulator = new SignalSimulator(
path, numOfdataPoints, numOfLocalSpikes,
numOfExpSpikes, noiseAmp, slope, offset,
rdbtnSineWave.isSelected());
signalSimulator.addPropertyChangeListener( new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
String property = evt.getPropertyName();
if ("progress".equals(property)) {
int progress = (Integer) evt.getNewValue();
System.out.println("value in PropertChangeListener is: " + progress);
progressBar.setValue(progress);
}
}
});
signalSimulator.execute();
计算类别:
protected Integer doInBackground() throws Exception {
if (isSine){
data = generateSineWave(numOfDataPoints, noiseAmp, offset);
data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
} else {
data = generateLinearSignal(numOfDataPoints, noiseAmp, slope, offset);
data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
}
writeLogFile(path, ".txt", data);
firePropertyChange("progress", 1, 1);
setProgress((int)progress);
publish(progress);
System.out.println("value in doInBackground is: " + progress);
return 1;
}
编辑
原来的问题仍然存在。由于某些原因,进度条仍然没有更新,
我确信progressBar.setValue(progress)中的“progress”变量正在更新,但GUI中的进度条保持不变(固定为0)
这是我的新代码:
GUI类:
SignalSimulator signalSimulator = new SignalSimulator(path, numOfdataPoints, numOfLocalSpikes, numOfExpSpikes, noiseAmp, slope, offset, rdbtnSineWave.isSelected());
signalSimulator.addPropertyChangeListener( new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
String property = evt.getPropertyName();
if ("progress".equals(property)) {
int progress = (Integer) evt.getNewValue();
System.out.println("value in PropertChangeListener is: " + progress);
progressBar.setValue(progress);
}
}
});
signalSimulator.execute();
SwingWorker类:
@Override
protected Integer doInBackground() throws Exception {
if (isSine){
data = generateSineWave(numOfDataPoints, noiseAmp, offset);
data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
}
else{
data = generateLinearSignal(numOfDataPoints, noiseAmp, slope, offset);
data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
}
writeLogFile(path, ".txt", data);
return 1;}
public double[] generateSineWave(int numOfDataPoints, double noiseAmp, double offset){
Random rnd = new Random();
double[] dataArray = new double[numOfDataPoints];
for (int i=0;i<numOfDataPoints;i++){
dataArray[i] = Math.sin(Math.toRadians(i))+rnd.nextDouble()*noiseAmp+offset;
progress = ((double)i)/(double)numOfDataPoints*100;
//firePropertyChange("progress", 1, 1);
setProgress((int)progress);
//publish(progress);
System.out.println("value in doInBackground is: " + progress);
}
return dataArray;
还有SwingWorker:
import javax.swing.SwingWorker;
public class LongRunner extends SwingWorker<Integer, Double>{
int numOfPoints;
double progress;
public LongRunner(int numOfPoints) {
this.numOfPoints = numOfPoints;
this.progress = 0;
}
private void runLong(int bigNum){
for (int i=0; i< bigNum; i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
progress = (((double)i*100)/(double)bigNum);
setProgress((int)progress);
System.out.println("Value in setProgress: "+progress);
}
}
@Override
protected Integer doInBackground() throws Exception {
runLong(numOfPoints);
return null;
}
}
import javax.swing.SwingWorker;
公共类LongRunner扩展SwingWorker{
整数点;
双重进步;
公共长跑者(国际点数){
this.numOfPoints=numOfPoints;
这个进度=0;
}
私有void runLong(int-bigNum){
for(int i=0;i
我做错了什么?您直接从代码调用
doInBackground()
,这类似于在runnable中直接调用run()
。这意味着您的代码实际上不是在后台线程上运行的,因此您可能会用长时间运行的代码来破坏事件线程,从而阻止Swing GUI和进度条的更新
解决方案:不要这样做。当您希望worker运行时,对其调用execute()
如果你需要进一步的帮助,你首先得帮助我们。你知道你有大量的代码发布,其中大部分与你手头的问题完全无关,当然比你应该要求志愿者完成的还要多。请删除所有无关的代码,创建并发布一个合适的
编辑
您似乎还直接从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);
您似乎只创建了一个工作者对象,这是不正确的,因为您不能重复使用SwingWorker对象
我建议您仅在需要时创建SwingWorker对象,并将所需信号类型的信息传递到其构造函数中。通过这种方式,可以从SwingWorker的doInBackground方法调用上述方法
e、 g
请注意,在您发布的代码中还有一些其他重要的无关问题,但必须在其他时间解决,但它们包括使用null布局和setBounds,这几乎总是一个非常糟糕的主意
编辑 再次澄清一下,您的主要问题是在Swing事件线程上调用长时间运行的代码。仅仅因为方法位于Worker类中,并不意味着调用它将自动在后台线程上运行。保证这一点的唯一方法是从
doInBackground()
方法中调用代码。同样,您要做的是在需要时创建新的worker对象,例如,在某个ActionListener内部,并在创建时将需要运行的所有信息传递给它。然后添加您的PropertyChangeListener,然后添加您的工作者。这样做,我敢打赌你的代码会工作得更好
编辑
比如说
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;
}
}
按照这样的速度,您的进度值将达到1,并在下一个冰河时代来临时对PropertyChangeListener和JProgressBar造成可见的更改。所以首先,改变你的睡眠时间,把你的大数字改成更合理的数字
接下来,对重要变量进行阴影处理,尤其是JProgressBar变量progressBar。下面是在类中声明和初始化它的位置:
public class ProgressBarTest implements PropertyChangeListener {
private JFrame frame;
private JButton btnRun;
static JProgressBar progressBar = new JProgressBar(0, 100);
作为旁注,这个变量绝对不应该声明为静态的,但这不是当前问题的原因。原因是您实际上在initialize方法的其他地方重新声明了相同的变量,然后将这个新对象添加到GUI中:
private void initialize() {
frame = new JFrame();
// .....
JProgressBar progressBar = new JProgressBar();
// .....
frame.getContentPane().add(progressBar);
请理解,这个新的progressBar变量引用了一个完全不同的JProgressBar,因此,如果您提升在类中创建的对象的值,您的GUI将不会显示任何内容,因为它显示的是一个完全不同的对象。要解决此问题,**不要在initialize方法中重新声明和初始化新变量。而是使用在类中创建的对象
代码中的其他问题:您经常使用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;
}
}
import java.awt.*;
导入java.awt.event.*;
导入java.beans。*;
导入javax.swing.*;
//!! 无需实现PropertyChangeListener
//!! 公共类ProgressBarTest实现PropertyChangeListener{
公共课进度表2{
私有JFrame;
public class ProgressBarTest implements PropertyChangeListener {
private JFrame frame;
private JButton btnRun;
static JProgressBar progressBar = new JProgressBar(0, 100);
private void initialize() {
frame = new JFrame();
// .....
JProgressBar progressBar = new JProgressBar();
// .....
frame.getContentPane().add(progressBar);
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;
}
}