接下的程序例子稍微復雜一些,盡管這沒有什麼價值。這個程序是一張不論鼠標何時移動都圍繞它畫一個小圓的,並且一個動作接收器被激活。畫布。當按下鼠標鍵時,我們可以改變的屬性是圓的大小,除此之外還有被顯示文字的色彩,大小,內容。BangBean同樣擁有它自己的addActionListener()和removeActionListener()方法,因此我們可以附上自己的當用戶單擊在BangBean上時會被激活的接收器。這樣,我們將能夠確認可支持的屬性和事件:
//: BangBean.java
// A graphical Bean
package bangbean;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
public class BangBean extends Canvas
implements Serializable {
protected int xm, ym;
protected int cSize = 20; // Circle size
protected String text = "Bang!";
protected int fontSize = 48;
protected Color tColor = Color.red;
protected ActionListener actionListener;
public BangBean() {
addMouseListener(new ML());
addMouseMotionListener(new MML());
}
public int getCircleSize() { return cSize; }
public void setCircleSize(int newSize) {
cSize = newSize;
}
public String getBangText() { return text; }
public void setBangText(String newText) {
text = newText;
}
public int getFontSize() { return fontSize; }
public void setFontSize(int newSize) {
fontSize = newSize;
}
public Color getTextColor() { return tColor; }
public void setTextColor(Color newColor) {
tColor = newColor;
}
public void paint(Graphics g) {
g.setColor(Color.black);
g.drawOval(xm - cSize/2, ym - cSize/2,
cSize, cSize);
}
// This is a unicast listener, which is
// the simplest form of listener management:
public void addActionListener (
ActionListener l)
throws TooManyListenersException {
if(actionListener != null)
throw new TooManyListenersException();
actionListener = l;
}
public void removeActionListener(
ActionListener l) {
actionListener = null;
}
class ML extends MouseAdapter {
public void mousePressed(MouseEvent e) {
Graphics g = getGraphics();
g.setColor(tColor);
g.setFont(
new Font(
"TimesRoman", Font.BOLD, fontSize));
int width =
g.getFontMetrics().stringWidth(text);
g.drawString(text,
(getSize().width - width) /2,
getSize().height/2);
g.dispose();
// Call the listener's method:
if(actionListener != null)
actionListener.actionPerformed(
new ActionEvent(BangBean.this,
ActionEvent.ACTION_PERFORMED, null));
}
}
class MML extends MouseMotionAdapter {
public void mouseMoved(MouseEvent e) {
xm = e.getX();
ym = e.getY();
repaint();
}
}
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
// Testing the BangBean:
public static void main(String[] args) {
BangBean bb = new BangBean();
try {
bb.addActionListener(new BBL());
} catch(TooManyListenersException e) {}
Frame aFrame = new Frame("BangBean Test");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(bb, BorderLayout.CENTER);
aFrame.setSize(300,300);
aFrame.setVisible(true);
}
// During testing, send action information
// to the console:
static class BBL implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("BangBean action");
}
}
} ///:~
最重要的是我們會注意到BangBean執行了這種串聯化的接口。這意味著應用程序構建工具可以在程序設計者調整完屬性值後利用串聯為BangBean貯藏所有的信息。當Bean作為運行的應用程序的一部分被創建時,那些被貯藏的屬性被重新恢復,因此我們可以正確地得到我們的設計。
我們能看到通常同Bean一起運行的所有的字段都是專用的——允許只能通過方法來訪問,通常利用“屬性”結構。
當我們注視著addActionListener()的簽名時,我們會注意到它可以產生出一個TooManyListenerException(太多接收器異常)。這個異常指明它是一個單一的類型的,意味著當事件發生時,它只能通知一個接收器。一般情況下,我們會使用具有多種類型的事件,以便一個事件通知多個的接收器。但是,那樣會陷入直到下一章我們才能准備好的結局中,因此這些內容會被重新回顧(下一個標題是“Java Beans 的重新回顧”)。單一類型的事件回避了這個難題。
當我們按下鼠標鍵時,文字被安入BangBean中間,並且如果動作接收器字段存在,它的actionPerformed()方法就被調用,創建一個新的ActionEvent對象在處理過程中。無論何時鼠標移動,它的新座標將被捕捉,並且畫布會被重畫(像我們所看到的抹去一些畫布上的文字)。
main()方法增加了允許我們從命令行中測試程序的功能。當一個Bean在一個開發環境中,main()方法不會被使用,但擁有它是絕對有益的,因為它提供了快捷的測試能力。無論何時一個ActionEvent發生,main()方法都將創建了一個幀並安置了一個BangBean在它裡面,還在BangBean中附上了一個簡單的動作接收器以打印到控制台。當然,一般來說應用程序構建工具將創建大多數的Bean的代碼。當我們通過BeanDumper或者安放BangBean到一個可激活Bean的開發環境中去運行BangBean時,我們會注意到會有很多額外的屬性和動作明顯超過了上面的代碼。那是因為BangBean從畫布中繼承,並且畫布就是一個Bean,因此我們看到它的屬性和事件同樣的合適。