窗口組件動態刷新問題,在dotnet中根本不算什麼問題,用幾句代碼很輕鬆就能搞定,可是在Swing中,實現動態刷新組件內容倒是一件頗爲吃力的事情。譬如針對咱們常常用到的刷新JLable、JTextField等組件內容,這些組件自己也提供有諸如updateUI()、validate()以及paintImmediately()等等與界面刷新和組件重繪相關的方法, 可是在常規狀況下都不起做用。多線程
咱們先看個基本的例子,JLabel內容動態刷新的例子,代碼以下。ide
try { for(int i=0;i<5;i++) { this.lbInfo.setText(String.format("當前進度:%s", i)); this.lbInfo.paintImmediately(this.lbInfo.getBounds()); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); }
咱們在一個for循環內每間隔一秒鐘刷新一下Label內容,以指望實現Label內容動態刷新效果,可是並無出現咱們想象中的效果,Label內容一直保持不變,直到最後才顯示最終的效果,中間的動態內容徹底被忽略過去了。這是由於每次調用setText都是運行在主線程中,並且是順序的執行的。在前面幾回調用setText後,線程並無退出,因此界面刷新線程不能得到執行刷新的機會。而當最後一次setText後,線程退出,界面才能執行刷新。因此咱們只能看到最後一次setText的值。測試
原來,在Java Swing中,界面刷新是線程同步的,也便是說,在同一時間,只有一個線程可以執行刷新界面的代碼。若是要屢次不斷地刷新界面,必須在多線程中調用刷新的方法。咱們將以上的代碼更改成多線程模式,從新運行,結果就徹底實現了咱們所指望的動態刷新效果。代碼以下。this
new Thread(new Runnable(){ @Override public void run() { try { for(int i=0;i<5;i++) { lbInfo.setText(String.format("當前進度:%s", i)); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } }).start();
那麼,除了這種採用顯式多線程模式外,還有沒有其餘方法實現內容動態刷新效果呢?咱們進行了測試,還真的找到了一種方法,就是結合JScrollPane實現及時動態刷新。在窗體區域建立一個JScrollPane組件,而後將JLabel組件放入JScrollPane中,執行如下代碼,一樣能夠實現內容及時動態刷新。代碼以下:spa
try { for(int i=0;i<5;i++) { this.lbInfo.setText(String.format("當前進度:%s", i)); this.lbInfo.paintImmediately(this.lbInfo.getBounds()); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); }
作一個小小的總結,針對JLableJ、TextField和JTextArea等組件內容的及時動態刷新問題,基本上採用多線程或者JScrollPane方式均可以實現。可是,對於JTextArea組件,若是不採用多線程模式,在內容動態刷新的時候,JTextArea的滾動條將沒法與內容區域保持同步。因此最穩妥可靠的作法,就是採用多線程模式實現內容的及時動態刷新。在下一章節中,咱們將利用JScrollPane、JTextArea、多線程和Java自定義事件機制,設計實現一個「日誌信息前臺監控器」,利用前臺窗體實時監控顯示後臺服務的日誌信息。線程
做者:商兵兵設計
單位:河南省電力科學研究院智能電網所日誌
QQ:52190634code