Swing框架之Model
构建应用程序应该以数据为中心,而不是以用户界面为中心,这是一个良好的编程习惯。为支持这种编程范式,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接口作为它的模型定义,因此它必须提供下面方法:
1
2
|
public BoundedRangeModel
getModel() publicvoidsetModel(BoundedRangeModelmodel) |
所有Swing组件有一个共同点:如果你不设置它的模型,组件会在内部创建/安装一个缺省模型。这些缺省模型类的命名习惯是在接口名称之前加上“Default”,比如JSlider的构造函数中初始化一个DefaultBoundedModel对象。
1
2
3
4
5
6
7
|
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(),缺省的模型就被替换了,比如下面例子:
1
2
3
4
5
6
7
8
|
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的一列表格数据发生改变时。
如果你喜欢本文, 请长按二维码,关注公众号 分布式编程.
作者:分布式编程
出处:https://zthinker.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。