看板java
标 题Re: [问题] 多个panel和ActionListener的问题
发信站SayYA 资讯站 (Fri Nov 24 21:14:57 2006)
转信站ptt!ctu-reader!news.nctu!SayYa
※ 引述《[email protected] (痞子军团团长)》之铭言:
> ※ 引述《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