Posted on 2007-10-12 16:16
zht 阅读(809)
评论(0) 编辑 收藏 所属分类:
Swing
构建应用程序应该以数据为中心,而不是以用户界面为中心,这是一个良好的编程习惯。为支持这种编程范式,Swing为每种带有逻辑数据或值的组件定义了独立的模型接口,这种分割使程序可以选择向Swing组件中嵌入自己的模型实现。
下面表格列出Swing中组件及其模型的映射关系:
组件 |
Model接口 |
Model类型 |
JButton |
ButtonModel |
GUI状态 |
JToggleButton |
ButtonModel |
GUI状态/应用数据 |
JCheckBox |
ButtonModel |
GUI状态/应用数据 |
JRadioButton |
ButtonModel |
GUI状态/应用数据 |
JMenu |
ButtonModel |
GUI状态 |
JMenuItem |
ButtonModel |
GUI状态 |
JCheckBoxMenuItem |
ButtonModel |
GUI状态/应用数据 |
JRadioButtonMenuItem |
ButtonModel |
GUI状态/应用数据 |
JComboBox |
ComboBoxModel |
应用数据 |
JProgressBar |
BoundedRangeModel |
GUI状态/应用数据 |
JScrollBar |
BoundedRangeModel |
GUI状态/应用数据 |
JSlider |
BoundedRangeModel |
GUI状态/应用数据 |
JTabbedPane |
SingleSelectionModel |
GUI状态 |
JList |
ListModel |
应用数据 |
JList |
ListSelectionModel |
GUI状态 |
JTable |
TableModel |
应用数据 |
JTable |
TableColumnModel |
GUI状态 |
JTree |
TreeModel |
应用数据 |
JTree |
TreeSelectionModel |
GUI状态 |
JEditorPane |
Document |
应用数据 |
JTextPane |
Document |
应用数据 |
JTextArea |
Document |
应用数据 |
JTextField |
Document |
应用数据 |
JPasswordField |
Document |
应用数据 |
Swing模型分类
Swing提供的模型分为两大类:GUI状态模型和应用数据模型。
GUI状态模型是描述GUI控件可视化状态的接口,如按钮是否按下,或列表中那一项被选中。GUI状态模型通常仅在图形用户界面(GUI)环境中用到。通常来说,虽然编写使用GUI状态模型分离程序,尤其是当多个GUI控件共享状态,或当操作一个控件自动更新另一个的值时比较有用,但GUI状态模型在Swing中并不是必需的,完全可以通过组件顶层方法操作GUI控件的状态,而不必和模型直接交互。
应用数据模型是描述具有应用程序含义数据的接口,比如表格中的数据,或列表显示的选项。这些数据模型为Swing提供了一个清晰分割应用程序界面和数据逻辑的强大编程模式。对于以数据为核心的Swing组件,比如JTree和JTable,强烈推荐使用数据模型进行交互。
当然一些组件的模型根据应用场景的不同其分类介于GUI状态模型和应用数据模型之间,比如JSlider和JProgressBar 的BoundedRangeModel。
Swing的可分离模型接口并没有明确界定GUI状态模型和应用数据模型。这儿所以做此说明,目的是让你更好的理解何时以及为何要需要使用分离的模型。
共享模型定义
值得注意的是,上文中表格中,许多组件的数据抽象相似,只需一个接口而不用过分泛化时,组件可以共享同一模型定义。共享模型定义允许在不同组件之间自动连接。比如,JSlider和JScrollBar都使用BoundedRangeModel接口,因此可以在一个JScrollBar和一个JSlider之间共享同一个BoundedRangeModel实例,这样它们之间的状态就总是同步的。
分离模型编程接口
使用模型的Swing组件必须提供访问修改模型的set/get方法,即模型必须是该组件的限定性属性。比如,JSlider使用BoundedRangeModel接口作为它的模型定义,因此它必须提供下面方法:
public BoundedRangeModel getModel()
publicvoidsetModel(BoundedRangeModelmodel)
所有Swing组件有一个共同点:如果你不设置它的模型,组件会在内部创建/安装一个缺省模型。这些缺省模型类的命名习惯是在接口名称之前加上“Default”,比如JSlider的构造函数中初始化一个DefaultBoundedModel对象。
public JSlider(int orientation, int min, int max, intvalue){
checkOrientation(orientation);
this.orientation = orientation;
this.model = newDefaultBoundedRangeModel(value, 0, min, max);
this.model.addChangeListener(changeListener);
updateUI();
}
如果程序接着调用setModel(),缺省的模型就被替换了,比如下面例子:
JSlider slider = new JSlider();
BoundedRangeModel myModel = new DefaultBoundedRangeModel() {
public void setValue(int n){
System.out.println("SetValue: "+ n);
super.setValue(n);
}
});
slider.setModel(myModel);
对于更复杂的模型(如JTable和JList),Swing还提供一个抽象模型实现,让开发者不需要从头开始创建自己的模型。
如JList的模型接口是ListModel,Swing同时提供了DefaultListModel和AbstractListModel两个类来协助开发者创建自定义的列表模型。
模型改变通知
当数据或者发生变动时,模型必须通知所有相关方(比如视图)。Swing模型使用前面文章所讲述的事件模型来实现这种触发。Swing中有两种方法发送这种通知:
发送轻量级通知,表明状态已经改变,需要Listener通过查询模型,发现什么改变了并做出响应。此方法的优点是单独事件实例能用作该模型的所有通知,同时对于需要频繁通知的事件非常有用(比如JScrollBar被拖动时)。
发送状态化通知,详细描述模型如何改变。这种方法需要为每个通知创建一个新的事件实例。当通知通过查询模型不能有效地给Listener提供足够的信息时,此方法非常有用。比如当JTable的一列表格数据发生改变时。