Posted on 2007-10-12 16:16
zht 閱讀(818)
評論(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的一列表格數據發生改變時。