lda*_*dam 1 java swing multithreading jprogressbar event-dispatch-thread
我想让用户了解I/O操作的进度.目前我有一个内部课程,在我启动I/O之前启动,并在完成后停止.它看起来像这样:
class ProgressUpdater implements Runnable {
private Thread thread;
private long last = 0;
private boolean update = true;
private long size;
public ProgressUpdater(long size) {
this.size = size;
thread = new Thread(this);
}
@Override
public void run() {
while (update) {
if (position > last) {
last = position;
double progress = (double) position / (double) size * 100d;
parent.setProgress((int) progress);
}
}
}
public void start() {
thread.start();
}
public void stop() {
update = false;
parent.setProgress(100);
}
}
Run Code Online (Sandbox Code Playgroud)
parent是我对UI的引用,position是我外部类中的一个字段,表示我们在I/O中取得的进展.我在停止时将进度设置为100%,因为有时I/O会完成并停止我的更新程序,然后才能完成更新上一个增量.这只是确保它达到100%.
目前,这是有效的,我使用它像这样:
ProgressUpdater updater = new ProgressUpdater(file.length());
updater.start();
//do I/O
//...
updater.stop();
Run Code Online (Sandbox Code Playgroud)
问题是循环吃CPU非常糟糕.我尝试在那里抛出一个锁(带有等待/通知)但我不知道在使用wait/notify时我正在做什么所以它只是挂了我的线程.我该怎么做才能阻止它使用如此多的CPU周期?
您应该考虑使用SwingWorker.基本上你在SwingWorker提供的后台线程上执行所有IO ,并且有内置的方法向swing线程报告进度.
然后,无论何时更新该位置,您都可以自动更新进度,而不是连续轮询,这是您迄今为止所做的.
看看的SwingWorker超时或SwingWorker的用的FileReader,看看要么会有所帮助.
另一种解决方案,如果您不想使用a SwingWorker,可能只是通过这样position的调用,而不是更新该值,直接更新进度条:
SwingUtilities.invokeLater(new Runnable() {
@Override public void run() {
getMyProgressBar().setValue(position);
}
});
Run Code Online (Sandbox Code Playgroud)
假设您已设置进度条,以使其最大值为文件大小.
首先,永远不要Thread用来更新java中的GUI(Swing组件).而是使用javax.swing.Timer或javax.swing.SwingWorker.对于Basic I/O操作,请使用
ProgressMonitorInputStream.
作为读取文件并在JTextArea中使用progrressbar显示文件的简单示例.请查看下面给出的代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.io.*;
import java.beans.*;
class ProgressBarFrame extends JFrame
{
JProgressBar progressBar;
int BUFFERSIZE = 10;
JTextArea textArea;
MyWorker worker;
private void createAndShowGUI()
{
progressBar = new JProgressBar(0,100);
progressBar.setStringPainted(true);
JButton button = new JButton("Read File");
textArea = new JTextArea(30,100);
JScrollPane jsp = new JScrollPane(textArea);
Container c = getContentPane();
c.add(jsp);
c.add(progressBar,BorderLayout.NORTH);
c.add(button,BorderLayout.SOUTH);
worker = new MyWorker();
button.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent evt)
{
textArea.setText("");
progressBar.setValue(0);
if (worker.getState()== SwingWorker.StateValue.DONE || worker.getState()==SwingWorker.StateValue.STARTED)
{
worker.cancel(true);
worker = new MyWorker();
}
worker.execute();
}
});
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
class MyWorker extends SwingWorker<Void, String>
{
MyWorker()
{
addPropertyChangeListener(new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent evt)
{
if ("progress".equals(evt.getPropertyName()))
{
progressBar.setValue((Integer)evt.getNewValue());
}
}
});
}
@Override
public Void doInBackground() throws IOException
{
File file = new File("ProgressBarFrame.java");
long size = file.length();
long temp = 0;
BufferedInputStream bfin = new BufferedInputStream(new FileInputStream(file));
byte[] buffer=new byte[BUFFERSIZE];
int totalRead = -1;
while ((totalRead=bfin.read(buffer))!=-1 && ! isCancelled())
{
temp = temp + totalRead;
publish(new String(buffer));
if (bfin.available()<BUFFERSIZE && bfin.available()!= 0)
buffer = new byte[bfin.available()];
else if(bfin.available()==0)
buffer = new byte[1];
else
buffer=new byte[BUFFERSIZE];
setProgress((int)((temp/(float)size) * 100));
try{Thread.sleep(1);}catch(Exception ex){}
}
setProgress(100);
return null;
}
@Override
protected void process(List<String> chunks)
{
for (String value : chunks)
{
textArea.append(value);
}
}
}
public static void main(String st[])
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
ProgressBarFrame pf = new ProgressBarFrame();
pf.createAndShowGUI();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1030 次 |
| 最近记录: |