Component state change must be done on Event Dispatch Thread,程序运行出现了这个问题,现在用swing做的是文件传输,C/S模式下的,在一条监听线程中一直监听客户端的回应,有请求就读写文件并写入socket流中去,过程中有一个进度条,进度条的改变也是在监听线程中进行的,监听线程再起了一条线程去改变进度条的状态,下面是改变进度条的一段代码:try {
final  FileInputStream fin = new FileInputStream(selectFile);
 final byte[] buff = new byte[1024];
 final int s;
final long size = selectFile.length();
 final int count = 0;
  SwingUtilities.invokeLater(new Runnable() {            public void run() {
                  bar.setMaximum((int) size);
while ((s = fin.read(buff)) > 0) {
count += s;    //这里出问题了count 显示 The final local variable count cannot be assigned, since it is defined in an enclosing type
oos.write(buff, 0, s);
String str = "" + 100 * (count / size);
bar.setString(str + " %");
bar.setValue(count);
}
               
            }
        });
oos.flush();
fin.close();
oos.close();
client.close();
server.close();
} catch (Exception e2) {
e2.printStackTrace();
}上面的代码会抛Component state change must be done on Event Dispatch Thread这个异常,只有当完全传送完后才显示100%,过程中没有变化,即没有动起来,假如我用   try {
final FileInputStream fin = new FileInputStream(selectFile);
final byte[] buff = new byte[1024];
int s;
final long size = selectFile.length();
int count = 0;
while ((s = fin.read(buff)) > 0) {
count += s;
final int count_value = count;
oos.write(buff, 0, s);
final String str = "" + 100 * (count / size);
SwingUtilities.invokeLater(new Runnable() { public void run() {
bar.setMaximum((int) size);
bar.setString(str + " %");
bar.setValue(count_value );
}
});
} oos.flush();
fin.close();
oos.close();
client.close();
server.close();
} catch (Exception e) {
e.printStackTrace();
} }这里用了 SwingUtilities.invokeLater后进度条是能动了,但是上面的那些变量都得改为final类型,bar.setString()方法在这里没用了,bar是JProgressBar~,这里面的count_value 在这里只能为final,而且也想不明白count_value 既然是final了,应该只能只能被赋值一次,赋值后值不再改变,但是bar.setValue()还是动了~如果直接bar.setValue(count)的话,count要改为final,里面就运行不来了在count+=s那里~以上是问题,有表达不到位的说下~恳请大侠们给点指点,蛋疼了2天的问题了~又是双休日~~~有空耐心的看下~

解决方案 »

  1.   

    1.多线程问题,从我的角度来看,很有可能是因为
     SwingUtilities.invokeLater(new Runnable(){//...});这个方法造成的,其官方API解释为:导致 doRun.run() 在 AWT 事件指派线程上异步执行。在所有挂起的 AWT 事件被处理后才发生。此方法应该在应用程序线程需要更新该 GUI 时使用。在下面的示例中,invokeLater 调用将事件指派线程上的 Runnable 对象 doHelloWorld 加入队列,然后输出一条信息。 
     Runnable doHelloWorld = new Runnable() {
         public void run() {
             System.out.println("Hello World on " + Thread.currentThread());
         }
     }; SwingUtilities.invokeLater(doHelloWorld);
     System.out.println("This might well be displayed before the other message.");
     
    这样就导致了你的第一段代码的结果,就是进度条没有动。2.你的意图很明显,就是用多线程读写文件、发送socket,然后用一个进度条去监听进度。这是多线程的应用个,你可以直接继承Thread类或者实现Runnable接口来进行多线程处理,同时注意一下线程同步。对进度条的控制,可以通过估算进度的方式来显示。其实进度条的作用无非就是告诉用户:"我的程序正在帮你积极处理一些事情,马上就好了"。3.使用SwingUtilities.invokeLater方法后,在run方法中的count必须要定义为final类型的。这是因为你在SwingUtilities.invokeLater方法中传递了一个匿名内部类new Runnable(){//...},因此count属于外部类的属性,在内部类中使用就必须是final标示的。4.通常来说被赋予为final类型的变量,我们都说它是最终变量。从某种角度来说,它是不可更改的。但如果你清楚private final int iCount = 10;这条语句的执行过程后,你就会改变看法。另外,在你的这段代码中while ((s = fin.read(buff)) > 0) {
                    count += s;
                    final int count_value = count;
                    oos.write(buff, 0, s);
                    final String str = "" + 100 * (count / size);
                    SwingUtilities.invokeLater(new Runnable() {                    public void run() {
                            bar.setMaximum((int) size);
                            bar.setString(str + " %");
                            bar.setValue(count_value );
                        }
                    });
                }
    每循环一次,你就定义了一个变量count_value,并赋值为count,由于count在变化,count_value每次都是新定义的,所有你的进度条当然就会改变。5.建议:将thinking in java多看几遍!!6.期望:结贴吧。如有问题可继续发帖问~~  兄弟回复打字手都打软了~~
      

  2.   

    1.第一段代码导致进度条不变的原因是使用了SwingUtilities.invokeLater,官方定义为:导致 doRun.run() 在 AWT 事件指派线程上异步执行。在所有挂起的 AWT 事件被处理后才发生。此方法应该在应用程序线程需要更新该 GUI 时使用。在下面的示例中,invokeLater 调用将事件指派线程上的 Runnable 对象 doHelloWorld 加入队列,然后输出一条信息。 
     Runnable doHelloWorld = new Runnable() {
         public void run() {
             System.out.println("Hello World on " + Thread.currentThread());
         }
     }; SwingUtilities.invokeLater(doHelloWorld);
     System.out.println("This might well be displayed before the other message.");
    2.楼主是想用多线程实现文件读写、socket传送,并使用进度条显示进度。其实可以直接使用Thread类或者Runnable接口。只要注意线程状态和同步控制就可以了。其实进度条的目的是告诉客户:“我的程序正在努力为你工作,请你等候一下”。另外,注意swing组件不具有线程安全,有些地方你需要自己去控制。3.第一段代码中:final int count = 0;
                  SwingUtilities.invokeLater(new Runnable() {            public void run() {
                      bar.setMaximum((int) size);
                while ((s = fin.read(buff)) > 0) {
                    count += s;    //这里出问题了count 显示 The final local variable count cannot be assigned, since it is defined in an enclosing type
                    oos.write(buff, 0, s);
                    String str = "" + 100 * (count / size);
                    bar.setString(str + " %");
                    bar.setValue(count);
                }
                   
                }
            });你的count是在外部定义的,且为final标示,因此你在while循环中试图改变其值,就必然会出现错误。
    而第二段代码中:
    while ((s = fin.read(buff)) > 0) {
                    count += s;
                    final int count_value = count;
                    oos.write(buff, 0, s);
                    final String str = "" + 100 * (count / size);
                    SwingUtilities.invokeLater(new Runnable() {                    public void run() {
                            bar.setMaximum((int) size);
                            bar.setString(str + " %");
                            bar.setValue(count_value );
                        }
                    });
                }你是在每次循环中都定义了一个final标示的count_value变量,也就是说循环多少次就有多少个count_value变量产生,且将之赋值为count,由于count是变化的,因此会常出现进度条有反应的状况。4.SwingUtilities.invokeLater(new Runnable() {                    public void run() {
                            bar.setMaximum((int) size);
                            bar.setString(str + " %");
                            bar.setValue(count_value );
                        }
                    });这样的代码使用了匿名内部类,且count_value不是在该匿名内部类中进行定义的,也就属于外部类,因此java要求必须标示为final。5.通常我们都说final标示的变量不可更改,从某种意义上说这没错。但如果你彻底理解了private final int count = 29;的执行步骤和顺序,你会改变自己的看法。建议楼主多看看《thinking in java》。6.打字手都打软了,第一次没发送成功,打了两遍。楼主结贴吧...
      

  3.   

    靠~~  现在才发现第一次是发送成功了的~~  悲剧呀~~ 打了两次~~~
    不知道该说csdn太贰,还是我自己~~~
      

  4.   

    顶,我在SwingUtilities.invokeLater()里面写了个自定义的线程做到了,还是很感谢仁兄的教诲,受教了~!