最近在做一个C/S的通行软件,其中涉及到文件传输的功能,希望能够显示文件的上传进度,但是遇到一些问题无法解决:
当传输文件时,进度条必须不断更新,但是Swing好像是单线程的,而且对Swing界面的更改不能在其他线程中进行(如果有错请指教),结果我现在的问题就是文件传输的过程中进度条不能更新,而且整个界面被阻塞,导致对界面无法进行其他操作,只有文件传输完成后才突然显示100%,下面贴出部分代码:包含进度条的类:
public class TransmitBar extends JPanel{
private File file;
private JProgressBar progressBar;
public TransmitBar(File file){
this.file=file;
progressBar=new JProgressBar(0, (int)file.length());
progressBar.setStringPainted(true);
progressBar.setValue(0);
progressBar.setPreferredSize(new Dimension(215,20));

this.setLayout(null);
progressBar.setBounds(0,0,215,15);
this.add(progressBar);
this.setPreferredSize(new Dimension(215,15));
}
public TransmitBar getObj(){
return this;
}
public void start(){
SwingUtilities.invokeLater(new Runnable() {
 public void run() {
 try{
FileInputStream fis=new FileInputStream(file);
FileOutputStream fos=new FileOutputStream("D:\\"+file.getName());
int data;
int i=0;
while((data=fis.read())!=-1){
fos.write(data);
i++;
progressBar.setValue(i);
//getObj().repaint();
//getObj().updateUI();
}
//Thread.interrupted();
}catch(Exception e){

}
 }
}); 
}
}主窗体中通过按钮激发文件选择,将选择的文件传入上面类的构造方法中,然后调用类的start()方法,现在文件可以传输,但是进度条无法更新:

解决方案 »

  1.   

    使用 SwingWorker 。
    具体用法请 google
      

  2.   

    我一直这么用。            Thread thread = new Thread(new Runnable() {
                      public void run() {
                       for(int pos=0;pos<100;pos++){
                                jProgressBar1.setValue(pos);
                         }
                      }
                });
                thread.start();
      

  3.   

    还是不行,我把start()方法改成如下:
    public void start(){
    Thread thread = new Thread(new Runnable() {
                public void run() {
                 try{
    FileInputStream fis=new FileInputStream(file);
    FileOutputStream fos=new FileOutputStream("D:\\"+file.getName());
    int data;
    int i=0;
    while((data=fis.read())!=-1){
    fos.write(data);
    i++;
    progressBar.setValue(i); getObj().repaint();
    getObj().updateUI();
    } }catch(Exception e){

    }
                   }
          });
    thread.start();
    }结构出现异常(我使用了Substance来美化界面):
    org.jvnet.substance.api.UiThreadingViolationException: Component state change must be done on Event Dispatch Thread
    at org.jvnet.substance.utils.SubstanceCoreUtilities.testComponentStateChangeThreadingViolation(SubstanceCoreUtilities.java:2386)
    at org.jvnet.substance.SubstanceProgressBarUI$1.stateChanged(SubstanceProgressBarUI.java:156)
    at javax.swing.DefaultBoundedRangeModel.fireStateChanged(Unknown Source)
    at javax.swing.DefaultBoundedRangeModel.setRangeProperties(Unknown Source)
    at javax.swing.DefaultBoundedRangeModel.setValue(Unknown Source)
    at javax.swing.JProgressBar.setValue(Unknown Source)
    at client.ui.file.TransmitBar$1.run(TransmitBar.java:85)
    at java.lang.Thread.run(Unknown Source)
    错误就是progressBar.setValue(i);这一句,在网上看到这样一句话:Swing界面的更改不能在其他线程中进行,不知道是不是这个原因
      

  4.   

    还是不行,我把start()方法改成如下:
    public void start(){
    Thread thread = new Thread(new Runnable() {
                public void run() {
                 try{
    FileInputStream fis=new FileInputStream(file);
    FileOutputStream fos=new FileOutputStream("D:\\"+file.getName());
    int data;
    int i=0;
    while((data=fis.read())!=-1){
    fos.write(data);
    i++;
    progressBar.setValue(i); getObj().repaint();
    getObj().updateUI();
    } }catch(Exception e){

    }
                   }
          });
    thread.start();
    }结构出现异常(我使用了Substance来美化界面):
    org.jvnet.substance.api.UiThreadingViolationException: Component state change must be done on Event Dispatch Thread
    at org.jvnet.substance.utils.SubstanceCoreUtilities.testComponentStateChangeThreadingViolation(SubstanceCoreUtilities.java:2386)
    at org.jvnet.substance.SubstanceProgressBarUI$1.stateChanged(SubstanceProgressBarUI.java:156)
    at javax.swing.DefaultBoundedRangeModel.fireStateChanged(Unknown Source)
    at javax.swing.DefaultBoundedRangeModel.setRangeProperties(Unknown Source)
    at javax.swing.DefaultBoundedRangeModel.setValue(Unknown Source)
    at javax.swing.JProgressBar.setValue(Unknown Source)
    at client.ui.file.TransmitBar$1.run(TransmitBar.java:85)
    at java.lang.Thread.run(Unknown Source)
    错误就是progressBar.setValue(i);这一句,在网上看到这样一句话:Swing界面的更改不能在其他线程中进行,不知道是不是这个原因
      

  5.   

    原来还用了 substance 啊,这个真的不好说了
    这个LookAndFeel还要用一个单独的线程来启动才行
    它用线程实现了一些减隐,渐变的特效,也用HighLighter实现了不少效果
    但是相对的,Swing本身的对UI进行改变的很多方法都会被Substance的效果所覆盖
    HighLighter也完全失效,
    也就是说,如果你用了Substance就要完全接受它的一切,除非你能自己修改它的核心代码我以前也试过这个LookAndFeel,
    但是我发现它把我很多自己优化界面的东西覆盖掉了,只能放弃
      

  6.   

    14. 32. 14. SwingWorker and ProgressBar
      

  7.   

    还是用swingworker 比较好,很不错
      

  8.   

    你把更新界面的代码放在
     SwingUtilities.invokeLater(new Runnable(){
                        public void run(){
                          processBar.setValue(i);                    }
                    });
    不要把IO相关的操作放到界面更新队列里面去
      

  9.   

    顶这个。将上传的逻辑处理放在doInBackground方法中,在publish方法中可以更新你的JProgressBar组件,详见API中的SwingWoker说明。
      

  10.   

    除了SwingWorker,其他Thread实现都是不安全的
      

  11.   

    这个可以算的 。
       但swing也可以多线程啊 !!
      

  12.   


    Swing的多线程和其他服务器程序的多线程还是有些差别的,Swing在考虑多线程的同时还要注意界面变化和更新,这些都是要在EDT线程中去实现的。