怎么用TableModel框架簡化Swing開發(fā)

本篇內(nèi)容介紹了“怎么用TableModel框架簡化Swing開發(fā)”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)建站專業(yè)為企業(yè)提供魏縣網(wǎng)站建設(shè)、魏縣做網(wǎng)站、魏縣網(wǎng)站設(shè)計(jì)、魏縣網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、魏縣企業(yè)網(wǎng)站模板建站服務(wù),10多年魏縣做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

如果您最近沒有用過Swing開發(fā),那么您會很高興聽到其中的許多問題已經(jīng)得到解決。Swing 被重新設(shè)計(jì),它能執(zhí)行得更好,并能更好地利用 Java 2D API。Swing 開發(fā)者在 1.4 版甚至***發(fā)布的 5.0 版中提高了外觀支持。Swing 從沒像現(xiàn)在這么好過。

如果以前曾經(jīng)用過 JTable,那么您可能也同時(shí)被迫使用了TableModel。您可能還注意到,每個(gè) TableModel 中的所有代碼,與其他 TableModel 中的代碼幾乎是一樣的,在編譯的 Java 類中,有差異的代碼實(shí)際上是不存在的。本文將分析 TableModel/JTable 目前的設(shè)計(jì)方法,說明這種設(shè)計(jì)的不足,展示為什么它沒有實(shí)現(xiàn)模型-視圖-控制器(MVC)模式的真正目標(biāo)。您將看到框架和構(gòu)成 TMF 框架的代碼 —— 我以前編寫的代碼與最常用的開放源代碼項(xiàng)目的組合。使用該框架,開發(fā)人員可以把 TableModel 的大小從數(shù)百行代碼減少到只有區(qū)區(qū)一行,并把重要的表信息放在外部 XML 文件中。在讀完本文之后,只使用如下所示的一行代碼,您就可以管理您的 JTable 數(shù)據(jù):

1 TableUtilities.setViewToModel("tableconfig.xml","My Table",
2     myJTable, CollectionUtilities.observableList(myData));
3

JTable 和 TableModel 存在的 MVC 問題

MVC 已經(jīng)成為非常流行的 UI 設(shè)計(jì)模式,因?yàn)樗褬I(yè)務(wù)邏輯清晰地從數(shù)據(jù)的視圖中分離了出來。Struts 是 MVC 在 Web 上應(yīng)用的一個(gè)非常好的例子。最初,Swing ***的一個(gè)賣點(diǎn)是它采用了 MVC,將視圖從模型中分離了出來,代碼背后的想法是:代碼的模塊化程度足夠高,所以,不用修改模型中的任何代碼,就可以分離出視圖。我想,任何用過 JTables 和 TableModels 的人都會發(fā)笑,告訴您這是絕對不可能的。使用 MVC 設(shè)計(jì)模式的理想情況是,在開發(fā)人員用 JList 或 JComboBox 替換 JTable 時(shí),可以不用修改表示數(shù)據(jù)的模式中的代碼。但是,在 Swing 中做不到這點(diǎn)。Swing 使得把 JTable、 JList 和 JComboBox 熱交換到應(yīng)用程序中成為不可能,即使所有這三個(gè)組件都是用來為相同的數(shù)據(jù)模型提供視圖。對于 Swing 中的 MVC 設(shè)計(jì),這是一個(gè)嚴(yán)重的不足。如果您想為 JTable 交換 JList,就必須重寫視圖背后的全部代碼,才能實(shí)現(xiàn)該交換。

JTable/TableModel 的另一個(gè) MVC 缺陷是:模型變化的時(shí)候,視圖不會更新自身。開發(fā)人員必須保持對模型的引用,并調(diào)用一個(gè)函數(shù),這樣模型才會告訴視圖對自身進(jìn)行更新;但是,理想的情況應(yīng)當(dāng)是:不需要任何額外的代碼,就能實(shí)現(xiàn)自動更新。

***,JTable 和 TableModel 組件設(shè)計(jì)的問題是,它們彼此之間纏雜得過于密切。如果您修改了 JTable 中的代碼,那么您需要確保您沒有破壞負(fù)責(zé)處理的 TableModel,反之亦然。對于一個(gè)被認(rèn)為是在模塊化基礎(chǔ)上建立的設(shè)計(jì)模式來說,目前的實(shí)現(xiàn)顯然是一種存在過多依賴關(guān)系的設(shè)計(jì)。

TMF 框架更好地遵循了 MVC 的目標(biāo),它把 JTable 中視圖和模型的工作更加清晰地分離開來。雖然它還沒有達(dá)到讓組件能夠熱切換的更高目標(biāo),但是它已經(jīng)在正確方向上邁出了一步。

讓我們來檢視 TMF 框架,看看它是如何讓傳統(tǒng) TableModel 過時(shí)的。設(shè)計(jì)該框架的***部分是學(xué)習(xí) JTable 的使用 —— 開發(fā)人員如何使用它,它顯示了什么內(nèi)容,以便了理解哪些東西可以內(nèi)化、通用化,哪些應(yīng)當(dāng)保留可配置狀態(tài),以便開發(fā)人員配置。對于 TableModel,也要進(jìn)行同樣的思考,我必須確定哪些東西可以從代碼中移出,哪些必須留在代碼中。一旦找出這些問題,接下來要做的就是確定能夠讓代碼足夠通用的***技術(shù),以便所有人都能使用它,但是,還要讓代碼具備足夠的可配置性,這也是為了讓每個(gè)人都能使用它。

該框架分成三個(gè)基本部分:一個(gè)能夠處理任何類型數(shù)據(jù)的通用 TableModel、一個(gè)外部 XML 文件(負(fù)責(zé)對不同表中不同的表內(nèi)容進(jìn)行配置),以及模型與視圖之間的橋。

在本文中,您可以在 src 文件夾中找到文中介紹的所有源代碼。特定于 TMF 的代碼位于 com.ibm.j2x.swing.table 包中。

 com.ibm.j2x.swing.table.BeanTableModel

BeanTableModel 是框架的***部分。它充當(dāng)?shù)氖峭ㄓ?TableModel ,您可以用它來處理任何類型的數(shù)據(jù)。我知道,您可能會說,“您怎么這么肯定它適用于所有的數(shù)據(jù)呢?”確實(shí),很明顯,我不能這么肯定,而且實(shí)際上,我確信有一些它不適用的例子。但是從我使用 JTables 的經(jīng)驗(yàn)來說,我愿意打賭(即使看起來我有點(diǎn)抬杠),實(shí)際使用中的 JTables,99% 都是用來顯示數(shù)據(jù)對象列表(也就是說,JavaBeans 組件的 ArrayList)?;谶@個(gè)假設(shè),我建立了一個(gè)通用表模型,它可以顯示任何數(shù)據(jù)對象列表,它就是 BeanTableModel。

BeanTableModel 大量使用了 Java 的內(nèi)省機(jī)制,來檢查 bean 中的字段,顯示正確的數(shù)據(jù)。它還使用了來自 Jakarta Commons Collections 框架的兩個(gè)類來輔助設(shè)計(jì)。

在我深入研究代碼之前,請讓我解釋來自類的幾個(gè)概念。因?yàn)槲铱梢栽?bean 上使用內(nèi)省機(jī)制,所以我需要了解 bean 本身的信息,主要是了解字段的名稱是什么。我可以通過普通的內(nèi)省機(jī)制來完成這項(xiàng)工作:我可以檢查 bean ,找出其字段。但是,對于表來說,這還不夠好,因?yàn)槎鄶?shù)開發(fā)人員想讓他們的表按照指定順序顯示字段。除此之外,還有一項(xiàng)表需要的信息,我無法通過內(nèi)省機(jī)制從 bean 中獲得,即列名消息。所以,為了獲得正確顯示,對于表中的每個(gè)列,您需要兩條信息:列名和將要顯示的 bean 中的字段。我用鍵-值對的格式表示該信息,其中,將列名用作鍵,字段作為值。

正因?yàn)槿绱耍以谶@里使用了來自 Collections 框架的適合這項(xiàng)工作的兩個(gè)類。 BeanMap 用作實(shí)用工具類,負(fù)責(zé)處理內(nèi)省機(jī)制,它接手了內(nèi)省機(jī)制的所有繁瑣工作。普通的內(nèi)省機(jī)制開發(fā)需要大量的 try / catch 塊,對于表來說,這是沒有必要的。 BeanMap 把 bean 作為輸入,像處理 HashMap 那樣來處理它,在這里,鍵是 bean 中的字段(例如, firstName ),值是 get 方法(例如, getFirstName() )的結(jié)果。BeanTableModel 廣泛地運(yùn)用 BeanMap ,消除了操作內(nèi)省機(jī)制的麻煩,也使得訪問 bean 中的信息更加容易。

LinkedMap 是另外一個(gè)在 BeanTableModel 中全面應(yīng)用的類。我們還是回到為列名-字段映射所進(jìn)行的鍵-值數(shù)據(jù)設(shè)置,對于數(shù)據(jù)對象來說,很明顯應(yīng)當(dāng)選擇 HashMap。但是,HashPap 沒有保留插入的順序,對于表來說,這是非常重要的一部分,開發(fā)人員希望在每次顯示表的時(shí)候,都能以指定的順序顯示列。這樣,插入的順序就必須保留。解決方案是 LinkedMap ,它是 LinkedList 與 HashMap 的組合,它既保留了列,也保留了列的順序信息。參見清單 1,可以查看我是如何用 LinkedMap 和 BeanMap 來設(shè)置表的信息的。

清單1. 用 LinkedMap 和 BeanMap 設(shè)置表信息

1 protected List mapValues=new ArrayList();
2   protected LinkedMap columnInfo=new LinkedMap();  
3   
4   protectedvoid initializeValues(Collection values)
5    {
6       List listValues=new ArrayList(values);
7       mapValues.clear();
8       for (Iterator i=listValues.iterator(); i.hasNext();)
9       {
10          mapValues.add(new BeanMap(i.next()));
11       }
12    }

在 BeanTableModel 中比較有趣的檢查代碼實(shí)際上是通用 TableModel 的那一部分,這部分代碼擴(kuò)展了 AbstractTableModel 。將清單 2 中的代碼與您通常用來建立傳統(tǒng) TableModel 的代碼進(jìn)行比較,您可以看到一些類似之處。

清單 2. BeanTableModel 中的通用 TableModel 代碼

1   /**
2     * Returns the number of BeanMaps, therefore the number of JavaBeans
3     */    
4   publicint getRowCount()
5    {
6       return mapValues.size();
7    }
8   /**
9     * Returns the number of key-value pairings in the column LinkedMap
10     */    
11   publicint getColumnCount()
12    {
13       return columnInfo.size();
14    }
15   
16   /**
17     * Gets the key from the LinkedMap at the specified index (and a
18     * good example of why a LinkedMap is needed instead of a HashMap)
19     */  
20   public String getColumnName(int col)
21    {
22       return columnInfo.get(col).toString();
23    }
24   /**
25     * Gets the class of the column.  A lot of developers wonder what
26     * this is even used for.  It is used by the JTable to use custom
27     * cell renderers, some of which are built into JTables already
28     * (Boolean, Integer, String for example).  If you  write a custom cell
29     * renderer it would get loaded by the JTable for use in display  if that
30     * specified class were returned here.
31     * The function uses the BeanMap to get the actual value out of the
32     * JavaBean and determine its class.  However, because the BeanMap
33     * autoboxes things -- it converts the primitives to Objects for you
34     * (e.g. ints to Integers) -- the code needs to unautobox it, since the
35     * function must return a Class Object.  Thus, it recognizes any primitives
36     * and converts them to their respective Object class.
37     */  
38   public Class getColumnClass(int col)
39    {
40       BeanMap map= (BeanMap)mapValues.get(0);
41       Class c= map.getType(columnInfo.getValue(col).toString());
42       if (c==null)
43         return Object.class;
44       elseif (c.isPrimitive())
45         return ClassUtilities.convertPrimitiveToObject(c);
46       else
47         return c;
48    }
49   /**
50     * The BeanTableModel automatically returns false, and if you
51     * need to make an editable table, you'll have to subclass
52     * BeanTableModel and override this function.
53     */    
54   publicboolean isCellEditable(int row,int col)
55    {
56       returnfalse;
57    }
58   /**
59     * The function that returns the value that you see in the JTable.  It gets
60     * the BeanMap wrapping the JavaBean based on the row, it uses the
61     * column number to get the field from the column information LinkedMap,
62     * and then uses the field to retrieve the value out of the BeanMap.  
63     */
64   public Object getValueAt(int row,int col)
65    {
66       BeanMap map= (BeanMap)mapValues.get(row);
67       return map.get(columnInfo.getValue(col));
68    }
69   /**
70     * The opposite function of the getValueAt -- it duplicates the work of the
71     * getValueAt, but instead puts the Object value into the BeanMap instead
72     * of retrieving its value.
73     */
74   publicvoid setValueAt(Object value,int row,int col)
75    {
76       BeanMap map= (BeanMap)mapValues.get(row);
77       map.put(columnInfo.getValue(col), value);
78       super.fireTableRowsUpdated(row, row);
79    }
80   
81   /**
82     * The BeanTableModel implements the CollectionListener interface
83     * (1 of the 3 parts of the framework) and thus listens for changes in the
84     * data it is modeling and automatically updates the JTable and the
85     * model when a change occurs to the data.
86     */  
87   publicvoid collectionChanged(CollectionEvent e)
88    {
89       initializeValues((Collection)e.getSource());
90       super.fireTableDataChanged();
91    }

正如您所看到的,BeanTableModel 的整個(gè) TableModel 足夠通用化,可以在任何表中使用。它充分利用了內(nèi)省機(jī)制,省去了所有特定于 bean 的編碼工作,在傳統(tǒng)的 TableModel 中,這類編碼工作絕對是必需的 —— 同時(shí)也是完全冗余的。BeanTableModel 還可以在 TMF 框架之外使用,雖然在外面使用會喪失一些威力和靈活性。

看過這段代碼之后,您會提出兩個(gè)問題。首先,BeanTableModel 從哪里獲得列名-字段與鍵-值配對的信息?第二,到底什么是 ObservableCollection ?這些問題會將我們引入框架的接下來的兩個(gè)部分。這些問題的答案以及更多的內(nèi)容,將在本文后面接下來的章節(jié)中出現(xiàn)。

 Castor XML 解析器

保存必需的列名-字段信息的最合理的位置位于 Java 類之外,這樣,不需要再重新編譯 Java 代碼,就可以修改這個(gè)信息。因?yàn)殛P(guān)于列名和字段的信息是 TMF 框架中惟一明確與表有關(guān)的信息,這意味著整個(gè)表格都可以在外部進(jìn)行配置。

顯然,該解決方案會自然而然把 XML 作為配置文件的語言選擇。配置文件必須為多種表模型保存信息;您還需要能夠用這個(gè)文件指定每個(gè)列中的數(shù)據(jù)。配置文件還應(yīng)當(dāng)盡可能地易于閱讀,因?yàn)殚_發(fā)人員之外的人員有可能要修改它。

這些問題的***解決方案是 Castor XML 解析器。查看 Castor 實(shí)際使用的***方法就是查看如何在框架中使用它。

讓我們來考慮一下配置文件的目的:保存表模型和表中列的信息。 XML 文件應(yīng)當(dāng)盡可能簡單地顯示這些信息。TMF 框架中的 XML 文件用清單 3 所示的格式來保存表模型信息。

清單3. TMF 配置文件示例

1 <model>
2       <className>demo.hr.TableModelFreeExampleclassName>
3       <name>Hirename>
4       <column>
5         <name>First Namename>
6         <field>firstNamefield>
7       column>
8       <column>
9         <name>Last Namename>
10         <field>lastNamefield>
11       column>
12   model>
13

與這個(gè)目的相反的目標(biāo)是,開發(fā)人員必須處理的 Java 對象應(yīng)當(dāng)像 XML 文件一樣容易理解。通過 Castor XML 解析器用來存儲列信息的三個(gè) Java 對象,就可以看到這一點(diǎn),這三個(gè)對象是: TableData (存儲文件中的所有表模型)、 TableModelData (存儲特定于表模型的信息)和 TableModelColumnData (存儲列信息)。這三個(gè)類提供了 Java 開發(fā)人員所需的所有包裝器,以便得到有關(guān) TableModel 的所有必要信息。

將所有這些包裝在一起所缺少的一個(gè)環(huán)節(jié)就是 映射文件,它是一個(gè) XML 文件,Castor 用它把簡單的 XML 映射到簡單的 Java 對象中。在***的世界中,映射文件也應(yīng)當(dāng)很簡單,但事實(shí)要比這復(fù)雜得多。良好的映射文件要使別的一切東西都保持簡單;所以一般來說,映射文件越復(fù)雜,配置文件和 Java 對象就越容易處理。映射文件所做的工作顧名思義就是把 XML 對象映射到 Java 對象。清單 4 顯示了 TMF 框架使用的映射文件。

清單 4. TMF 框架使用的 Castor 映射文件

1 <?xml version="1.0"?>
2   <mapping>
3       <description>A mapping filefor externalized table modelsdescription>
4     
5       <class name="com.ibm.j2x.swing.table.TableData">
6         <map-to xml="data"/>
7         <field name="tableModelData" collection="arraylist" type=
8           "com.ibm.j2x.swing.table.TableModelData">
9             <bind-xml name="tableModelData"/>
10         field>
11       class>
12     
13       <class name="com.ibm.j2x.swing.table.TableModelData">
14         <map-to xml="model"/>
15         <field name="className" type="string">
16             <bind-xml name="className"/>
17         field>
18         <field name="name" type="string">
19             <bind-xml name="name"/>
20         field>
21         <field name="columns" collection="arraylist" type=
22           "com.ibm.j2x.swing.table.TableModelColumnData">
23             <bind-xml name="columns"/>
24         field>
25       class>
26     
27       <class name="com.ibm.j2x.swing.table.TableModelColumnData">
28         <map-to xml="column"/>
29         <field name="name" type="string">
30             <bind-xml name="name"/>
31         field>
32         <field name="field" type="string">
33             <bind-xml name="field"/>
34         field>        
35       class>
36     
37   mapping>
38

僅僅通過觀察這段代碼,您就可以看出,映射文件清晰地勾劃出了每個(gè)用來存儲表模型信息的類,定義了類的類型,并將 XML 文件中的名稱連接到了 Java 對象中的字段。請保持相同的名稱,這樣會讓事情簡單、更好管理一些,但是沒必要保持名稱相同。

到現(xiàn)在為止,列名和字段信息都已外部化,可以讀入包含列信息的 Java 對象中,并且可以很容易地把信息發(fā)送給 BeanTableModel,并用它來設(shè)置列。

 ObservableCollection

TMF 框架的***一個(gè)關(guān)鍵部分,就是 ObservableCollection 。您們當(dāng)中的某些人可能熟悉 ObservableCollection 的概念,它是 Java Collections 框架的一個(gè)成員,在被修改的時(shí)候,它會拋出事件,從而允許其偵聽器根據(jù)這些事件執(zhí)行操作。雖然從來沒有將它引入 Java 語言的正式發(fā)行版中,但在 Internet 上,這個(gè)概念已經(jīng)有了一些第三方實(shí)現(xiàn)。就本文而言,我使用了自己的 ObservableCollection 實(shí)現(xiàn),因?yàn)榭蚣苤恍枰恍┳罨镜墓δ?。我的?shí)現(xiàn)使用了一個(gè)稱為 collectionChanged() 的方法,每次發(fā)生修改時(shí), ObservableCollection 都會在自己的偵聽器上調(diào)用該方法。也可以將該用法稱為 Collection 類的 Decorator(有關(guān) Collections 的 Decorator 更多信息,請參閱 Collections 框架的站點(diǎn)),只需要增加幾行代碼,您就可以在普通的 Collection 類中創(chuàng)建 Collection 類的 Observable 實(shí)例。 清單 5 顯示了 ObservableCollection 用法的示例。(這只是一個(gè)示例,沒有包含在 j2x.zip 中。)

 清單 5. ObservableCollection 用法示例

1 // convert a normal list to an ObservableList
2    ObservableList oList= CollectionUtilities.observableList(list);
3   // A listener could then register for events from this list by calling
4    oList.addCollectionListener(this);
5   // trigger event
6    oList.add(new Integer(3));
7   // listener receives event
8   publicvoid collectionChanged(CollectionEvent e)
9    {
10       // event received here
11    }
12

ObservableCollection 有許多 TMF 框架之外的應(yīng)用程序。如果您決定采用 TMF 框架,您會發(fā)現(xiàn),在開發(fā)代碼期間, ObservableCollection 框架有許多實(shí)際的用途。

但是,它在 TMF 框架中的用途,重點(diǎn)在于它能更好地定義視圖和模型之間的關(guān)系,當(dāng)數(shù)據(jù)發(fā)生變化時(shí),可以自動更新視圖。您可以回想一下,這正是傳統(tǒng) TableModel 的***限制,因?yàn)槊慨?dāng)數(shù)據(jù)發(fā)生變化時(shí),都必須用表模型的引用來更新視圖。而在 TMF 框架中使用 ObservableCollection 時(shí),當(dāng)數(shù)據(jù)發(fā)生變化時(shí),視圖會自動更新,不需要維護(hù)一個(gè)到模型的引用。在 BeanTableModel 的 collectionChanged() 方法的實(shí)現(xiàn)中,您可以看到這一點(diǎn)。

TableUtilities

在該框架中執(zhí)行的***一步操作,是將所有內(nèi)容集成到一些實(shí)用方法中,讓 TMF 框架使用起來簡單明了。這些實(shí)用方法可以在 com.ibm.j2x.swing.table.TableUtilities 類中找到,該類提供了您將需要的所有輔助函數(shù):

getColumnInfo() :該實(shí)用方法用 Castor XML 文件解析指定的文件,并返回指定表模型的所有列信息,返回的形式是 BeanTableModel 所需的 LinkedMap 。當(dāng)開發(fā)人員選擇從 BeanTableModel 中派生子類時(shí),這個(gè)方法很重要。

getTableModel() :該實(shí)用方法是建立在上面的 getColumnInfo() 方法之上,它獲得列的信息,然后把信息傳遞給 BeanTableModel,返回已經(jīng)設(shè)置好所有信息的 BeanTableModel。

setViewToModel() :該實(shí)用方法是最重要的函數(shù),也是 TMF 框架的主要吸引人的地方。它也是建立在 getTableModel() 方法之上,也有一個(gè)到 JTable 的引用(JTable 中有這個(gè)表的模型),以及一個(gè)到數(shù)據(jù)(要在表中顯示)的引用。它對 JTable 上的 TableModel 進(jìn)行設(shè)置,并把數(shù)據(jù)傳遞給 TableModel,結(jié)果是:只需一行代碼,就為 JTable 完成了 TableModel 的設(shè)置。TMF 框架在該方法上得到了***印證,TableModel 將永遠(yuǎn)地被下面這個(gè)簡單的方法所代替:

1 TableUtilities.setViewToModel("table_config.xml","Table", myJTable, myList);

每篇關(guān)于 GUI 編程的文章都需要一個(gè)示例,本文當(dāng)然也不例外。該示例的目的是指出使用 TMF 框架代替?zhèn)鹘y(tǒng) TableModel 設(shè)計(jì)的主要優(yōu)勢所在。示例中的應(yīng)用程序?qū)⒃谄聊簧巷@示多個(gè)表,并且可以添加或刪除表,表中可以包含不同類型的信息( String 類型、 int 類型、 Boolean 類型和 BigDecimal 類型),而且最重要的是,其中還包含可配置的列信息,必須定期更改它們。

示例應(yīng)用程序的代碼從 J2X 包中分離了出來,您可以 HR 文件夾的 src 目錄中找到源代碼。還可以雙擊 build/lib 文件中編譯好的 JAR 文件,通過 JRE 運(yùn)行應(yīng)用程序。

在示例應(yīng)用程序中,有兩個(gè)類可以相互交換,一個(gè)叫作 TableModelFreeExample ,另一個(gè)叫作 TableModelExample 。這兩個(gè)類在應(yīng)用程序中做的是同樣的事,使應(yīng)用程序產(chǎn)生的行為也相同。但是,它們的設(shè)計(jì)不同,一個(gè)使用的是 TMF 框架,另外一個(gè)則使用傳統(tǒng)的 TableModel。您從它們身上注意到的***件事可能是 TMF 類 TableModelFreeExample ,該類由 63 行代碼構(gòu)成,而在傳統(tǒng) TableModel 版本 TableModelExample 中,它長達(dá) 285 行。

Evil HR Director 應(yīng)用程序

我要使用的示例應(yīng)用程序是 Evil HR Director 應(yīng)用程序,它允許人力資源總監(jiān)(可能很可怕,戴著眼鏡)在 JTable 中查看潛在雇員的列表,然后從表中選出雇傭的人。新雇傭的員工的資料會轉(zhuǎn)移到當(dāng)前雇員使用的兩個(gè) JTable 中;其中一個(gè)表包含個(gè)人信息,另外一個(gè)表包含財(cái)務(wù)信息。在當(dāng)前雇員表中,總監(jiān)可以隨意選擇解雇誰。您可以在圖 1 中看到該應(yīng)用程序的 UI。

怎么用TableModel框架簡化Swing開發(fā)

為了進(jìn)一步證明 TMF 框架的簡單性,請看清單 6。這個(gè)清單只包含三行必需的代碼,就可以創(chuàng)建 Evil HR Director 應(yīng)用程序中包含的三個(gè)表的模型。這些代碼可以在 TableModelFreeExample 中找到。

清單 6.在 Evil HR Director 應(yīng)用程序中創(chuàng)建模型所需要的代碼

1 TableUtilities.setViewToModel("demo/hr/resources/evil_hr_table.xml",
2     "Hire", hireTable, candidates);    
3    TableUtilities.setViewToModel("demo/hr/resources/evil_hr_table.xml",
4     "Personal", personalTable, employees);
5    TableUtilities.setViewToModel("demo/hr/resources/evil_hr_table.xml",
6     "Financial", financialTable, employees);
7

為了進(jìn)行比較, TableModelExample 中包含用傳統(tǒng) TableModel 方法為三個(gè)表格創(chuàng)建模型所需要的代碼。請查看示例包中的代碼。不過,我不想在這里列出所有代碼,因?yàn)樗阕阌?205 行!

 演示 TMF 框架的靈活性

TMF 框架的巨大優(yōu)勢之一,是它能更加容易地基于 JTable 的應(yīng)用程序在其發(fā)布之后進(jìn)行修改。為了證實(shí)這一點(diǎn),讓我們來看兩個(gè)可能的場景,這兩個(gè)場景在使用 Evil HR Director 應(yīng)用程序中每天都可能出現(xiàn)。在每個(gè)場景中,您都會看到框架是如何讓應(yīng)用程序更加容易地適應(yīng)不斷變化的用戶需求。

場景 1:公司的策略發(fā)生變化,規(guī)定在公司的應(yīng)用程序中查看私人的婚姻信息是非法的。

TMF:最終用戶需要從 XML 配置文件中刪除Married?married 。

傳統(tǒng) TableModel:開發(fā)人員必須深入研究 Java 代碼,修改 getColumnName() ,讓它無法返回列名“Married?”;修改 getColumnCount() ,讓它返回的結(jié)果比以前返回的結(jié)果少一列;修改 getValueAt() ,不讓它返回 isMarried() 。然后開發(fā)人員必須重新編譯 Java 代碼,并重新部署應(yīng)用程序。

場景 2:公司策略發(fā)生變化,公司覺得有必要在潛在雇員表中包含居住地所在的州的信息。

TMF:: 最終用戶需要將Statestate 添加到 XML 配置文件中。

傳統(tǒng) TableModel:開發(fā)人員必須深入研究 Java 代碼,修改 getColumnName() ,添加一個(gè)叫作 “State” 新列;修改 getColumnCount() ,讓它返回的列數(shù)加 1 ;修改 getValueAt() ,讓它返回 getState() 。然后開發(fā)人員必須重新編譯 Java 代碼,并重新部署應(yīng)用程序。

您可以看到,當(dāng)應(yīng)用程序中的表發(fā)生變化時(shí)(尤其在碰到一個(gè)總是朝令夕改的老板時(shí),更改更加頻繁),編輯 XML 文件要比重新部署整個(gè)應(yīng)用程序容易得多。

使用代碼

在您飛奔過去刪除所有 TableModel 代碼之前,我想我還得占用您一分鐘解釋一下 j2x.zip 文件的內(nèi)容,以及您怎樣才能在您自己的項(xiàng)目中使用它。(請記住,特定于 TMF 的代碼可以在 com.ibm.j2x.swing.table 包中找到;您還會在 J2X 包中找到我在以前的文章“Go state-of-the-art with IFrame.”中介紹的其他代碼。)

j2x.zip 文件包含兩上文件夾:

src—— 包含本文中使用的源代碼。在 src 文件夾中,還有兩個(gè)文件夾:一個(gè)是 HR,包含構(gòu)成 Evil HR Director 應(yīng)用程序的源代碼;另一個(gè)是 J2X,包含 J2X 項(xiàng)目中使用的所有源代碼。

build—— 包含 Evil HR Director 應(yīng)用程序和 J2X 項(xiàng)目編譯后的類文件。該文件夾中的 lib 文件夾則包含 HR 應(yīng)用程序和 J2X 項(xiàng)目的 JAR 文件。

lib.zip 文件包含以下文件夾:

lib—— 包含所有的第三方 JAR 文件,運(yùn)行應(yīng)用程序或者任何使用 J2X 項(xiàng)目的項(xiàng)目,需要使用這些文件。在這個(gè)文件夾中,您還會找到第三方項(xiàng)目的許可。

docs.zip 文件包含下列文件夾:

docs—— 包含 J2X 項(xiàng)目的所有 JavaDoc 信息。

要在應(yīng)用程序中使用 J2X 包,則需要把 CLASSPATH 指向 build/lib 文件夾中的 j2x.jar 以及 lib 文件中包含的所有三個(gè)第三方 JAR 文件。第三方包的許可條款允許您重新發(fā)布本文包含的所有包,但是如果有興趣對這些包做些修改,請閱讀許可條款。

結(jié)束語

使用 TableModel Free 框架,就不用再編寫傳統(tǒng) TableModel 了。TMF 框架改進(jìn)了 JTable 和 TableModel 模型之間的 MVC 關(guān)系,更清楚地分離了它們。在日后的發(fā)布中,您甚至可以在不修改任何模型代碼的情況下,對組件進(jìn)行熱交換??蚣苓€允許您在模型發(fā)生變化時(shí),自動更新視圖,從而消除傳統(tǒng) TableModel 設(shè)計(jì)中所必需的視圖和模型之間的通信。

TMF 框架還會極大地減少開發(fā) GUI 所需的時(shí)間,特別是在處理 JTable 時(shí)。幾年以前,我處理的一個(gè)應(yīng)用程序中有 150 多個(gè) JTable,每個(gè)表都來自同一個(gè)原始表模型,該應(yīng)用程序可以作為示例。使用 TMF 框架,我們只用 150 行代碼就能解決問題;但是不幸的是,當(dāng)時(shí)還沒有 TMF,所以我們***編寫了 15,000 行額外的代碼,才生成必需的表模型。這不但增加了開發(fā)時(shí)間,還增加了測試和調(diào)試的時(shí)間。

與使用傳統(tǒng) TableModel 相比,使用 TMF 框架使您到了一個(gè)更加容易配置所有 JTable 的時(shí)代。請想像這樣一個(gè) POS 應(yīng)用程序:該應(yīng)用程序被銷售給了 5 個(gè)不同的客戶,每個(gè)客戶都有一套特定的信息,所以每個(gè)用戶都想有一組顯示在 GUI 上的特定的列。如果沒有 TMF 框架,您就必須為每個(gè)客戶都生成一組特定的 TableModel —— 由此,也就生成了一組特定的應(yīng)用程序。而使用可配置的 XML 文件,每個(gè)客戶都可以使用相同的應(yīng)用程序,客戶所在地的業(yè)務(wù)分析師可以根據(jù)需要修改 XML 文件。請想像一下,這節(jié)約了多少開發(fā)和支持成本!

TableModel Free 框架解決了 Swing 開發(fā)人員社區(qū)的特定需求:減少了處理 JTable 時(shí)的開發(fā)時(shí)間和維護(hù)開銷,提高了它們對終端用戶的易用性。Swing 桌面正在回歸,使用像 TMF 框架這樣的工具,開發(fā)人員會發(fā)現(xiàn)可以更容易地使用 Swing 和開發(fā) GUI 應(yīng)用程序。您要做的***步就是用 TMF 框架的一行代碼代替您所有的 TableModel,把所有 TableModel 都永遠(yuǎn)地拋到虛擬空間的黑洞中去吧。

“怎么用TableModel框架簡化Swing開發(fā)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

當(dāng)前文章:怎么用TableModel框架簡化Swing開發(fā)
網(wǎng)站鏈接:http://muchs.cn/article6/pdjgig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營銷推廣、面包屑導(dǎo)航網(wǎng)站改版、網(wǎng)站維護(hù)自適應(yīng)網(wǎng)站、靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)