| |
注:根据yigemaser、jfml、crazyjavar的建议更新,对三位的帮助表示感谢!
在写ui应用时,通常会在一些事件处理的过程中,尤其当这个处理比较耗时的时候,希望能够及时把一些进度信息显示给用户。这时通常大家都会使用一个文本控件来显示这些进度信息。比如下面的程序中,有一个jtextpane和jbutton,在jbutton中的action事件中需要进行一些耗时的处理,例子程序中使用了thread.sleep()使当前线程休眠3秒来模拟耗时的操作。action事件处理分为3步,我们希望及时把当前的进度显示在jtextpane上。 代码如下:
package bruce.test;import javax.swing.*;import java.awt.container;import java.awt.borderlayout;import java.awt.dimension;import java.awt.event.windowadapter;import java.awt.event.actionlistener;import java.awt.event.actionevent;/** * 事件处理过程中ui的刷新 * @author bruce * @version 1.0 */public class testuiupdate2 { public testuiupdate2() { testuiupdate2frame frame = new testuiupdate2frame(); frame.pack(); frame.setvisible(true); } public static void main(string[] args) { new testuiupdate2(); }}class testuiupdate2frame extends jframe { jtextpane pane = new jtextpane(); jbutton button = new jbutton("action..."); testuiupdate2frame() { init(); this.setdefaultcloseoperation(jframe.exit_on_close); button.addactionlistener(new actionlistener() { public void actionperformed(actionevent e){ try { pane.settext("step one..."); thread.sleep(3000); pane.settext("step two..."); thread.sleep(3000); pane.settext("finished."); thread.sleep(3000); } catch (interruptedexception ie) { //ignored } } }); } private void init() { pane.setpreferredsize(new dimension(300,200)); container content = getcontentpane(); content.setlayout(new borderlayout()); content.add(pane, borderlayout.center); content.add(button, borderlayout.south); }} 但在实际运行过程中可以发现,点击jbutton后,jtextpane并不能及时更新,而是在整个jbutton的action事件处理完毕后才能显示出最后的信息。为什么会出现这种情况呢?因为在处理jbutton的action事件过程中,虽然更新了jtextpane的内容,但由于jbutton的事件处理是在当前main线程中运行,虽然jtextpane更新了内容,但没有得到刷新显示的执行机会。
解决这个问题的方法非常简单,只需要把jbutton的action处理代码放入一个新的线程,然后启动这个线程。另外,由于swing的操作大部分是非线程安全的,所以对swing界面的刷新也单独放在一个线程,并调用swingutilities.invokelater()执行。这样action事件处理、更新jtextpane的界面和main主线程就分别运行在各自的线程中,都可以及时得到执行。jbutton的 actionperformed(actionevent e)的处理代码修改如下:[code] button.addactionlistener(new actionlistener() { public void actionperformed(actionevent e){ try { new thread() { public void run() { try { showmessage("step one..."); thread.sleep(3000); showmessage("step two..."); thread.sleep(3000); showmessage("finished."); thread.sleep(3000); } catch (interruptedexception ie) { //ignored } } }.start(); } catch (exception ex) { ex.printstacktrace(); } } });
showmessage方法如下:
private void showmessage (final string msg) { swingutilities.invokelater(new runnable() { public void run() { pane.settext(pane.gettext() + msg); } }); } 大家可以测试运行观察效果。这样也使界面更加友好,因为如果不把action的处理代码放在一个单独的线程中,用户点击jbutton后,界面就停止一切响应,直到action处理代码执行完毕。大家可以扩展这种方法,允许用户随时停止该耗时的操作,使界面更加友好。
|
|