(转载开始)
Model的设计
一个按钮的model所应该具备的行为由一个接口ButtonModel来完成。一个按钮model实例封装了其内部的状态,并且定义了按钮的行为。它的所有方法可以分为四类:
1、查询内部状态
2、操作内部状态
3、添加和删除事件监听器
4、发生事件
程序员通常并不会直接和model以及view/controller打交道,他们通常隐藏于那些继承自java.awt.Component的组件里面了,这些组件就像胶水一样把MVC三者合三为一。也正是由于这些继承的组件对象,一个程序员可以很方便的混合使用Swing组件和AWT组件,然后,我们知道,Swing组件有很多都是直接继承自相应的AWT组件,它能提供比AWT组件更加方便易用的功能,所以通常情况下,我们没有必要混合使用两者。
ButtonModel oldModel = getModel();
if (oldModel != null) {
oldModel.removeChangeListener(changeListener);
oldModel.removeActionListener(actionListener);
changeListener = null;
actionListener = null;
}
model = newModel;
if (newModel != null) {
changeListener = createChangeListener();
actionListener = createActionListener();
itemListener = createItemListener();
newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener);
newModel.addItemListener(itemListener);
mnemonic = newModel.getMnemonic();
} else {
mnemonic = '\0';
}
updateDisplayedMnemonicIndex(getText(), mnemonic);
firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel);
if (newModel != oldModel) {
revalidate();
repaint();}
}注:你可以多花一些时间按我上面提供的链接地址来仔细阅读一下Button类及其它相关类的源代码。
ButtonModel类
ButtonModel维护着三种类型的状态信息:是否被按下(pressed),是否“武装上了”(armed),是否被选择(selected)。它们都是boolean类型的值。
一个按钮被按下(pressed)是指当鼠标在按钮上面的时候,按下鼠标但是还没有松开鼠标按钮的状态,即使用户此时把鼠标拖拽到按钮的外面也没有改变这种状态。
一个按钮是否“武装了”(armed)是指按钮被按下,并且鼠标还在按钮的上面。
一些按钮还可能被选择(selected),这种状态通过重复的点击按钮取得true或者false的值。
注:查看ButtonModel源代码我们可以看到它是一个接口,定义了一组方法:public interface ButtonModel extends ItemSelectable {boolean isArmed();
boolean isPressed();
…
boolean isRollover();
void addActionListener(ActionListener l);void removeActionListener(ActionListener l);void addItemListener(ItemListener l);…
void removeChangeListener(ChangeListener l);其实看到这里,如果你再回头看下这个例子刚开始时“ Model 的设计” 以及前面的内容 ,就会明白什么是“Mod封装的是数据源和所有基于对这些数据的操作。在一个组件中,Model往往表示组件的状态和操作这些状态的方法,往往是一系列的公开方法。通过这些公开方法,便可以取得模型端的所有功能”我们再来看看 AbstractButton 的源代码:1. public abstract class implements ItemSelectable, SwingConstants { AbstractButton extends JComponent2. protected ButtonModel model= null;3. protected ChangeListener changeListener = null;4. protected ActionListener actionListener = null;5. protected ItemListener itemListener = null;6. protected transient ChangeEvent changeEvent;7. public boolean isSelected() {8. return model.isSelected();9. }
10.public void doClick() {11.doClick(68);
12. }13.public void doClick(int pressTime) {14. Dimension size = getSize();15.model.setArmed(true);16. model.setPressed(true);17. paintImmediately(new Rectangle(0,0, size.width, size.height));18.try {19.Thread.currentThread().sleep(pressTime);20. } catch(InterruptedException ie) {21.}
22.model.setPressed(false);23.model.setArmed(false);24.}
25.//其它代码
26.}
上面的代码setArmed等方法是由DefaultButtonModel定义的,它是ButtonModel接口的一个默认实现。我们如果继承了DefaultButtonModel,这样可以覆盖缺省的状态定义,实现有个性的按钮。ButtonUI类
按钮的view/controller是负责构建表示层的。缺省情况下它仅仅是用背景色画一个矩形而已,他们的子类继承了他们并且覆盖了绘制的方法,使得按钮可以有许多不同的表现,例如MOTIF,Windows 95,Java样式等等。
注:在javax.swing.plaf这个包里我们可以找到ButtonUI,这是一个抽象类,类内部是空的,而在javax.swing.plaf.basic这个包里我们可以找到BasicButtonUI,它继承自ButtonUI,其实我们观察下包结构会发现有javax.swing.plaf.metal,javax.swing.plaf.multi等,这几个就是来控制Button在不同系统间的不同的显示效果。:
public void update(Button button, Graphics graphics)
{
}
public void paint(Button button, Graphics graphics)
{
Dimension dimension = button.getSize();
Color color = button.getBackground();
graphics.setColor(color);
graphics.fillRect(0, 0, dimension.width, dimension.height);
}
ButtonUI类并不自己处理AWT事件,他们会使用一个定制的事件监听器把低级的AWT事件翻译为高级的Button模型期望的语义事件。下面就是安装/卸载事件监听器的代码。
private static ButtonUIListener buttonuilistener = null;
public void uninstallUI(Button button)
{
button.removeMouseListener(buttonuilistener);
button.removeMouseMotionListener(buttonuilistener);
button.removeChangeListener(buttonuilistener);
}
View/Controller实际上就是一些方法。他们不维护任何自己的状态信息。因此,许多按钮的实例可以共享一个ButtonUI实例。ButtonUI是通过在方便的参数列表里面加上按钮的引用来区分各个不同的按钮。
ButtonUIListener类
ButtonUIListener类可以帮助Button类去转变鼠标或者键盘的输入为对按钮模型的操作。这个监听器类实现了:MouseListener,MouseMotionListener,ChangeListener接口,并且处理一下事件:
public void mouseDragged(MouseEvent mouseevent)
{
Button button = (Button)mouseevent.getSource();
ButtonModel buttonmodel = button.getModel();
if (buttonmodel.isPressed())
{
if (button.getUI().contains(button, mouseevent.getPoint()))
{
buttonmodel.setArmed(true);
}
else
{
buttonmodel.setArmed(false);
}
}
}
public void mousePressed(MouseEvent mouseevent)
{
Button button = (Button)mouseevent.getSource();
ButtonModel buttonmodel = button.getModel();
buttonmodel.setPressed(true);
buttonmodel.setArmed(true);
}
public void mouseReleased(MouseEvent mouseevent)
{
Button button = (Button)mouseevent.getSource();
ButtonModel buttonmodel = button.getModel();
buttonmodel.setPressed(false);
buttonmodel.setArmed(false);
}
public void stateChanged(ChangeEvent changeevent)
{
Button button = (Button)changeevent.getSource();
button.repaint();
}(转载完)通过这些相信大家能够感受到Swing的设计是MVC的典范,这是一点都不假的。下一节将要看看在基于B/S的应用中MVC模式是如何被应用的。