锁定老帖子 主题:Swing的SwingWorker学习
精华帖 (1) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-11-05
最后修改:2009-11-05
一开始使用swing的时候就了解过这个东西.在项目中应用的时候.发现edt操作不能在SwingWorker线程中执行.(这里的edt操作包括什么呢?我以前做的时候只要有new这个关键字.就执行不了..现在就可以了) 一直以为是swing的规范.有很多的限制.最后就没再看这个东西.直到有一天看到这篇文章 http://vearn.iteye.com/blog/344591 首先赞一下.作者写的非常详细.而且提供了demo.于是我下载了demo,开始读代码.最后终于搞定了这个东东. 于是自己做了个例子.首先是课前准备
这里就简单提下.关于更详细的介绍请看原文 http://vearn.iteye.com/blog/344591 或者 API:http://202.201.112.11/jpk/apply/teacher/preface/53/api/javax/swing/SwingWorker.html http://www.javaresearch.org/article/7787.htm http://www.javaresearch.org/article/7788.htm
这里帖下关键代码
private void button_getDataActionPerformed(java.awt.event.ActionEvent evt) { //清除表格数据 table_data.setModel(new javax.swing.table.DefaultTableModel( new Object[][]{}, new String[]{ "id", "parent_id", "node_name" })); //如果要查看EDT阻塞效果 if (checkbox_edt.isSelected()) { //在不采用SwingWorker的时候下面这句你会发现不起作用,因为这是一个EDT事件. //只有处理完了这个事件之后.别的改变组件状态的时间才会被执行.这就是EDT阻塞 label_busy.setVisible(true);//设置载入label显示 try { Thread.sleep(5000);//睡眠5秒 } catch (InterruptedException ex) { ex.printStackTrace(); } setData(); label_busy.setVisible(false);//设置载入label消失 } else {//使用SwingWroker table_data.setEnabled(false);//设置表格不可用 button_getData.setEnabled(false);//设置按钮不可用 label_busy.setVisible(true);//设置载入label显示 new SwingWorker<DefaultTableModel, Void>() { @Override protected DefaultTableModel doInBackground() throws Exception { System.out.println("开始执行后台方法..."); JLabel jLabel = new JLabel();//测试在非EDT线程中创建组件.我以前做的总是不可以.现在好了. Thread.sleep(5000);//睡眠5秒.因为效果不太明显 return getData();//返回取到的数据 } @Override protected void done() { System.out.println("后台方法运行结束"); table_data.setEnabled(true); button_getData.setEnabled(true); label_busy.setVisible(false); try { // 获取doInBackground方法的返回值 table_data.setModel(get());//用get()方法取到上面取得的值 } catch (Exception ex) { ex.printStackTrace(); } } }.execute(); } }
2009-11-5晚上. 我在回家的路上想起来上次出现edt操作不能在SwingWorker线程中执行这个问题. 是由于用了开源皮肤Substance的问题.回家一试.果真如此..
把运行的代码
public static void main(String args[]) { SwingUtilities.invokeLater(new Runnable() { public void run() { TestFrame frame = new TestFrame(); frame.setVisible(true); } }); } 改为:
public static void main(String args[]) { try { JFrame.setDefaultLookAndFeelDecorated(true); JDialog.setDefaultLookAndFeelDecorated(true); UIManager.setLookAndFeel(new SubstanceBusinessBlueSteelLookAndFeel()); } catch (Exception e) { System.out.println("Substance Raven Graphite failed to initialize"); } SwingUtilities.invokeLater(new Runnable() { public void run() { TestFrame frame = new TestFrame(); frame.setVisible(true); } }); }
添加substance.jar包..
抛出异常:
org.jvnet.substance.api.UiThreadingViolationException: Component creation must be done on Event Dispatch Thread at org.jvnet.substance.utils.SubstanceCoreUtilities.testComponentCreationThreadingViolation(SubstanceCoreUtilities.java:2368) at org.jvnet.substance.SubstanceLabelUI.createUI(SubstanceLabelUI.java:68) at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:36) at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:243) at javax.swing.UIDefaults.getUI(UIDefaults.java:751) at javax.swing.UIManager.getUI(UIManager.java:1016) at javax.swing.JLabel.updateUI(JLabel.java:256) at javax.swing.JLabel.<init>(JLabel.java:145) at javax.swing.JLabel.<init>(JLabel.java:216) at test.TestFrame$2.doInBackground(TestFrame.java:186) at test.TestFrame$2.doInBackground(TestFrame.java:181) at javax.swing.SwingWorker$1.call(SwingWorker.java:278) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at javax.swing.SwingWorker.run(SwingWorker.java:317) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619)
不知道是什么原因....为什么java默认的皮肤可以..开源的就不可以呢...
上面的代码是一个按钮点击事件中执行的代码. 详细的例子请见附件 数据库用的是derby. 效果图:
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-11-05
不光是swing,凡是牵扯到gui的,例如c#也存在这个问题!!
|
|
返回顶楼 | |
发表时间:2009-11-06
kjj 写道 不光是swing,凡是牵扯到gui的,例如c#也存在这个问题!!
您说的是edt操作不能在非EDT事件中执行的问题吗?那为什么java默认的皮肤可以呢?开源的那个不可以.. |
|
返回顶楼 | |
发表时间:2009-11-06
今天又出现问题.我数据加载和创建组件分开了 我采用swingWorker的方式加载数据.然后创建组件..但是我现在取数据的时间长.创建组件的时间更长..所以还是避免不了EDT堵塞.我该怎么办呢?因为我取到的数据是很多条.我要根据这些数据动态创建大量的组件.所以还是很费时间,创建组件的时候要给组件设置图片..还是慢 不知道有什么解决方案没
new SwingWorker<List<List<Solution>>, Void>() { @Override protected List<List<Solution>> doInBackground() throws Exception { System.out.println("开始执行后台方法..."); label_busy.setVisible(true);//这里设置一个带加载图片的label显示 getChoices(setting);//获取数据 List<List<Solution>> l = getSolutions(choices); //在执行完上面的加载数据后.又开始了EDT阻塞!..加载label的加载图片不动了... logger.info("数据获取完毕..EDT开始阻塞!"); return l; } @Override protected void done() { System.out.println("后台方法运行结束"); logger.info("开始卡屏!"); button_change.setEnabled(true); label_busy.setVisible(false);//设置 try { creatCom(get());//这个方法的执行时间居然比获取数据的时间都长. //这里的创建组件包括的操作有:首先得到一组选择题的主体.然后查看主题是否包含图片.有相应的属性.有就创建图片.放到一个label中.循环创建. //创建选择题主体后.循环取他的四个或者多个选项.如果选项有图片..设置之.. } catch (Exception ex) { logger.info("卡屏完毕!"); } }.execute(); |
|
返回顶楼 | |
发表时间:2009-11-18
这种问题的根本原因是:Java Swing不是线程安全的,原因有二个,一个是效率因素,另一个是线程安全的UI工具包通常容易创建出倾向于死锁的程序。
通常在Swing中使用线程有两个简单原则: 1、非常耗时的动作要在一个单独的线程中执行,而不要在事件分派线程(EDT)中执行。 2、在任何线程中都不要碰Swing组件,除了时间分派线程。 要在耗时的线程中操作Swing组件,需要借助EventQueue中的两个静态方法向事件分派线程发送一个事件,从而通知事件分派线程执行对于Swing组件的操作。 上述的原则,对于Java Swing多线程应用是非常非常重要的。 |
|
返回顶楼 | |
发表时间:2009-11-19
wave-labs 写道 这种问题的根本原因是:Java Swing不是线程安全的,原因有二个,一个是效率因素,另一个是线程安全的UI工具包通常容易创建出倾向于死锁的程序。
通常在Swing中使用线程有两个简单原则: 1、非常耗时的动作要在一个单独的线程中执行,而不要在事件分派线程(EDT)中执行。 2、在任何线程中都不要碰Swing组件,除了时间分派线程。 要在耗时的线程中操作Swing组件,需要借助EventQueue中的两个静态方法向事件分派线程发送一个事件,从而通知事件分派线程执行对于Swing组件的操作。 上述的原则,对于Java Swing多线程应用是非常非常重要的。 谢谢解答.我现在的疑问是为什么java默认的皮肤可以,开源的那个不可以呢?难道java默认的皮肤绘制组件的时候不碰swing组件?开源的就碰? |
|
返回顶楼 | |
发表时间:2009-12-04
看下org.jvnet.substance.utils.SubstanceCoreUtilities类下的testComponentCreationThreadingViolation()和testComponentStateChangeThreadingViolation()方法就明白了,它做了一个判断,将这两个方法的内容注释掉就不会有异常信息了。
|
|
返回顶楼 | |
发表时间:2009-12-04
HeDYn 写道 看下org.jvnet.substance.utils.SubstanceCoreUtilities类下的testComponentCreationThreadingViolation()和testComponentStateChangeThreadingViolation()方法就明白了,它做了一个判断,将这两个方法的内容注释掉就不会有异常信息了。
谢谢解答..回头看看 |
|
返回顶楼 | |
浏览 12907 次