Re: [問題] 多個panel和ActionListener的問題

看板java作者時間19年前 (2006/11/25 06:01), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串3/6 (看更多)
※ 引述《PsMonkey.bbs@ptt.cc (痞子軍團團長)》之銘言: > ※ 引述《neigence (心夜)》之銘言: > : 假如我有一個程式 > : public class myFrame extends JFrame{ > : public AAA(){ > : Container con=getContentPane(); > : con.add(myPanelA); > : con.add(myPanelB); > : con.add(myPanelC); > : ..... > : } > : } > : 每一個panel都也許具有許多的gui元件 像JButton JTextfield > : 每一個panel都在不同的class > : 比方說 我按下myPanelB上的某個button 會影響讓myPanelA畫出 > : 什麼東西 或發生某些行為 或更動變數狀態 > : 那..理論上? 這幾個myPanel下所有gui元件的ActionListener > : 都要寫在myFrame這個程式下面嚕?..這樣子光這個檔下面的 > : actionPerformed 真的會太多了 ++myFrame+++++++++++++++++ | | | A panel Button | | | +------------------------- | | | B panel Text | | | +------------------------- | | | C panel Label | | | +------------------------- 你可能在B text填了什麼, 按了A的Button之後,想透過C的Label顯示點什麼訊息 所以直覺想幫A加了一個ActionListener { 取得ORZ = B.text 經過謎樣的邏輯運算後 XD = cal(ORZ) 顯示結果在C之中 C.label = XD } 這只是一種初步的想法,當你的Component很多的時候 就會難以控制。因為任何的Component都可能產生關係 要站在某一方(ex. A's Listener)的觀點去操控其他所有的元件 會增加程式設計師的負擔。 for example: ActionListener { t1 = A.xd; B.label = func1(t1) C.label = func2(t1) D.label = func3(t1) t2 = sum({B, C, D}.label) ............ ........ .... . } 這樣一來計算過還可能有些用處的資料,都散落在各個元件之中。 還要一一再收回? 可能會瘋掉。 =========================================================== Tip 1 :: GUI的資料要獨立且唯一 為了解決資料散落於各元件的問題,我們應該建立新的Class來表現 我們所用來展示、算計、暫存用的資料,有續存的需求更可以實作 Serializable。 所以,先讓資料獨立出來。 public class CheckableData { private String foo; public void setData(String f){foo=f;} } Tip 2 :: 不要讓運算邏輯散落於Listener之中 讓Data的歸Data的,使用者介面的歸使用者介面的 假設我們要讓資料可序列化,你不可以把序列化的主要部分寫在 Action之中。應該擺在CheckableData這裡才對 (ex. save method) ========================================================== 以提供base64 encode為例: import sun.misc.BASE64Encoder; public class CheckableData { private String foo; public void setData(String f) { foo = f; } public String getEncodeAsBase64() { return new BASE64Encoder().encode(foo.getBytes()); } } (bad style) encode_button.addActionListener(){ ......................... xd.label = new BASE64Encoder().encode(foo.getBytes()); } 這樣做的好處是,邏輯運算的部分幾乎都可以回歸資料本身。 達到純粹send message來溝通。 ======================================================== 即使經過了Tip 1、Tip 2資料獨立了,邏輯計算都歸位了。 你可能還是望著內容不少的Listener而懊惱。 這是怎麼一回事呢? 我們還需要改變些什麼!? 回過頭來看一下Listener { 取得ORZ = B.text 經過謎樣的邏輯運算後 XD = cal(ORZ) 顯示結果在C之中 C.label = XD } 這是在按了某個東西,觸發了事件。 最後導致了C.label更新 許多入門的書可能都是這樣寫了 按了foo,計算一下,直接更新了bar 這是個很直覺的構想,也不用覺得寫書的人有什麼不錯 因為他的重點在介面GUI,而我們今天的重點在 怎麼讓自己程式寫起來負擔小一點, 不會把code都擠在一起。 所以,為了我們的睡眠品質與減輕壓力應該想一想 是否有較好的方式,懶人思維: 是不是能讓C.label 自己更新自己 (general case: 讓(..)自己更新自己) 如果成真了這樣一來,就能讓Listener中更新 其他元件的code消失,而Listener只要通知Data object 去計算資料即可 ===================================================== Tip 3 :: 讓需要取得資料者成為觀察者 (提供資料的為被觀察者) j2se提供了這樣的機制 Interface Observer void update(Observable o, Object arg) Class Observable addObserver(Observer o) notifyObservers() setChanged() 這要怎麼用呢!? Observer --> 需要取用資料者 Observable --> 持有/產生資料者 以我們的例子,CheckableData是產生資料者: import java.util.Observable; import sun.misc.BASE64Encoder; public class CheckableData extends Observable { private String foo; public void setData(String f) { foo = f; this.setChanged(); // 標示,我"變"了 this.notifyObservers(); // 昭告天下,我真的"變了" } public String getEncodeAsBase64() { return new BASE64Encoder().encode(foo.getBytes()); } } ====================================================== import java.util.Observable; import java.util.Observer; import javax.swing.JLabel; public class ObLabel extends JLabel implements Observer { private String label; public ObLabel(Observable o , String s) { o.addObserver(this); label = s; } public void setLabel(String s) { this.label = s; this.setText(s); } public void update(Observable o, Object arg) { if (o instanceof CheckableData) { CheckableData cd = (CheckableData) o; // 取得資料 setLabel(cd.getEncodeAsBase64()); // 自己更新自己 } } } 如此一來,則所有元件可以透過觀察CheckableData來自動更新。 Listener所負擔的code也就少了,複雜的元件關係也獲得了解脫。 -- 偷偷講,其實這是簡單的講怎麼做mvc @"@ mvc 是策略模式+觀察著模式與一些互動的規範而成。 此篇稍略了策略模式,但大致上還算可用 -- ※ Origin: SayYA 資訊站 <bbs.sayya.org> ◆ From: pc210-59-94-161.nutn.edu.tw
文章代碼(AID): #15PskW00 (java)
討論串 (同標題文章)
文章代碼(AID): #15PskW00 (java)