2006年10月17日
#
在swing中
FileSystemView.getFileSystemView().getSystemDisplayName(file);
FileSystemView.getFileSystemView().getSystemIcon(file);
可以采用上面的方法得到。
那SWT中如何做到呢?
說到GUI類庫的重用有一個很著名的模式:Composite模式。對,一個現(xiàn)代面向?qū)ο驡UI類庫基本上都有這個模式的實(shí)現(xiàn),當(dāng)然也包括swing.不
過早一點(diǎn)如MFC就沒有完整的實(shí)現(xiàn),現(xiàn)在來看如果一個GUI類庫連基本的Composite模式都沒有實(shí)現(xiàn)基本上感覺是出土的文物啦!
但是我們來看即便有了Composite模式,但Composite模式通常是構(gòu)建靜態(tài)組合,如果要動態(tài)的替換一個復(fù)合組件內(nèi)部的子元素如何辦呢?如此一來這個組件就只能定義自己的布局形式,而不能定死在這個布局形式內(nèi)的元素。
其實(shí)從用戶角度來說一個GUI元素通常就是兩種情況要么就是表現(xiàn),要么就是處于和用戶交互狀態(tài),這是它們的形態(tài)通常不一樣。所以組件不僅僅要只定義自己的布局形式,還要給于外部機(jī)會來配置當(dāng)自己的子元素處于這兩種狀態(tài)時相應(yīng)的UI組件是什么!
swing通過renderer/editor達(dá)到了這種靈活性。如swing中JTable,JList,JTree等組件都只是定義了自
己的布局形式。并且都可以配置renderer/editor,這樣你的renderer/editor實(shí)現(xiàn)就接管了組件里面元素的表現(xiàn)形式和交互形態(tài)。
理論上你可以用任何JComponent作為組件里面元素的表現(xiàn)形式和交互形態(tài)。其靈活性和重用性達(dá)到了一個巔峰!
以前還聊過一個JTable的例子!
http://www.douban.com/group/topic/1112689/
public class Perspective implements IPerspectiveFactory {
public void createInitialLayout(IPageLayout layout) {
String er = layout.getEditorArea();
layout.setEditorAreaVisible(false);
layout.addView(FileTransfersView.DownloadID,IPageLayout.TOP , 0.25f, er);
layout.addView(FileTransfersView.UploadID,IPageLayout.BOTTOM , 0.25f, er);
}
}
比如有以上代碼,那么我如何獲得被加到layout的viewer實(shí)例呢?我發(fā)現(xiàn)本更無法獲得viewer實(shí)例的引用了。
plugin.xml文件的片斷
<extension
point="org.eclipse.ui.views">
<view
class="com.mt.ui.FileTransfersView"
id="com.mt.ui.FileTransfersView.Upload"
name="test1"/>
<view
class="com.mt.ui.FileTransfersView"
id="com.mt.ui.FileTransfersView.Download"
name="test2"/>
</extension>
很明顯兩個view的class是一個,因?yàn)槲乙赜眠@個view,它們只是有些屬性和背后的數(shù)據(jù)不一樣!我需要在初始化時將這些不一樣設(shè)定。
如果我的機(jī)會只有在這里
public void createPartControl(Composite parent) {
}
那么難道不同的View就要都通過繼承,然后重寫上面這個方法來做,這樣的話是不是過于呆板了!
還請熟悉eclipse RCP的指點(diǎn)。
最近看Eclipse RCP稍微了解一下JFace,看了它的MVC架構(gòu)有感!
在JFace的ContentViewer抽象中下面的三個方法反映它對待模型的思路:
public void setContentProvider(IContentProvidercontentProvider)
public void setInput(Object input)
public void setLabelProvider(IBaseLabelProvider labelProvider)
顯然setInput是用來配置view背后的數(shù)據(jù),從它的參數(shù)類型(Object)來講應(yīng)該是你的與view無關(guān)的領(lǐng)域模型.
從這里就可以看出它和swing的根本差異.swing各種不同viewer(在swing的世界叫JComponent)背后的模型是因不同組件而不同的,模型的接口是反應(yīng)了該組件特征的.
如 JTable 背后的TableModel,TableModel接口的定義基本表達(dá)了作為一個二維表格期望獲得數(shù)據(jù)的方式如TableModel中有定義這樣的方法:
Objetc getValueAt(int row,int column)
在JFace中直接可以放入Object類型數(shù)據(jù),但各種viewer不一樣對于拿數(shù)據(jù)的期望也不一樣,
ContentProvider,LabelProvider解決了上述問題,不同ContentProvider定義了該viewer所期望的拿數(shù)據(jù)的接口,其實(shí)我覺得swing中的model在意義上類似于ContentProvider.
其實(shí)感覺JFace的做法在盡量強(qiáng)制你必須構(gòu)建獨(dú)立于GUI的模型.
而swing的話并沒有這種侵入性,你可以直接實(shí)現(xiàn)viewer的模型接口如
class Mymodel implenents TableModel{
}
也可以定義比較獨(dú)立的模型然后用對象適配器模式將它們適配到viewer model上!
http://www.douban.com/group/topic/1159250/
我很希望B/S快點(diǎn)退出歷史舞臺!
建設(shè)一個client and server多對多的互聯(lián)網(wǎng)環(huán)境。并且client的部署和B/S一樣方便,甚至你可以沒有client的概念,而只有獲得服務(wù)的概念。
放眼過去,.net戰(zhàn)略最為接近。
我不明白為什么很多認(rèn)為基于瀏覽器等的所謂Web OS會大放光彩。
顯然由OS延伸來構(gòu)造一個互聯(lián)網(wǎng)應(yīng)用平臺合理的多。
傳統(tǒng)we作為運(yùn)行平臺有先天的不足!
就從傳統(tǒng)web說起,一個html瀏覽器(client)<---->html提供者(web服務(wù)器)。也就是它也只是傳統(tǒng)C/S架構(gòu)一
種,只是它基于標(biāo)準(zhǔn)而帶來了普及性,使得html瀏覽器(client)逐步演變?yōu)橐粋€基礎(chǔ)設(shè)施(平臺)。很多應(yīng)用在往這個架構(gòu)上移,于是基于這個架構(gòu)的
被稱為B/S的架構(gòu)出現(xiàn)了。然而很遺憾,它原先并不是作為互聯(lián)網(wǎng)應(yīng)用平臺角度而設(shè)計(jì)的,于是就有了以下的感慨:
縱觀web的歷程,就是在一個不適合交互的基礎(chǔ)架構(gòu)上搭建交互。
扭曲的發(fā)展!
強(qiáng)扭的瓜的感覺。
所以我們要的是一個更為通用的互聯(lián)網(wǎng)應(yīng)用平臺,它應(yīng)該吸取B/S的URL的想法,但是他指向的是實(shí)際的程序,并被下載到本地運(yùn)行。但這個過程某種程度上被透明,所以對用戶來說他完全可以沒有client的概念!當(dāng)然他首先應(yīng)該有這樣一個互聯(lián)網(wǎng)應(yīng)用平臺。
其實(shí)這就是讓用戶直接可以面向服務(wù),面向服務(wù)是個好概念,所以它并不局限于人于機(jī)器之間。軟件不同的組件之間或不同應(yīng)用之間(可分布在不同物理設(shè)備上)可以面向服務(wù)的概念集成在一起------即SOA.其中已多對多,松耦合為特點(diǎn)。
實(shí)際上通過一個執(zhí)行環(huán)境(運(yùn)行時)去統(tǒng)一所有的計(jì)算設(shè)備已經(jīng)被認(rèn)為是不可行的,曾經(jīng)的很多分布式架構(gòu)以及java都試圖這樣做,java希望世界所有的計(jì)算設(shè)備上都運(yùn)行著java,并都通過java來交流。很遺憾,java沒有做到。
所以SOA來了,就目前來說 web 服務(wù) 被認(rèn)為是實(shí)現(xiàn)SOA的良好架構(gòu),而 web
服務(wù)的核心是什么,不管怎么說我覺得XML必是其一,而XML又是基于公共標(biāo)準(zhǔn)的。這里的關(guān)鍵為了實(shí)現(xiàn)應(yīng)用之間的互聯(lián)互通,我們無需要兩個應(yīng)用都構(gòu)架于同
一個執(zhí)行環(huán)境(運(yùn)行時),因?yàn)槲覀儍H將我們將要在線上交換的信息達(dá)成一致。
這就帶來了松耦合,及強(qiáng)大的靈活性。在SOA下信息孤島確實(shí)可以被很好的解決。
所以有人說SOA之于企業(yè)應(yīng)用,就如同TCP/IP之于互聯(lián)網(wǎng)。
其實(shí)html有今天的普及,也是因?yàn)樗且粋€基于文本的公共標(biāo)準(zhǔn)的消息格式不依賴于執(zhí)行環(huán)境,但是它的設(shè)計(jì)目標(biāo)性太強(qiáng)不具有通用性的要求。因?yàn)樗婚_始就是為一個具體的應(yīng)用架構(gòu)而設(shè)計(jì)的。然而后面對于它的要求不斷拓寬,甚至希望它能變
成一個運(yùn)行平臺于是xxxscript開始了,但是這時實(shí)際上已經(jīng)存在了執(zhí)行環(huán)境的依賴了,因?yàn)椴煌瑇xxscript有不同的執(zhí)行環(huán)境
所以這時就有這個網(wǎng)頁怎么在這個瀏覽器上不能打開的這樣的說法了。而反過來雖然有了xxxscript但是還是受到B/S架構(gòu)的很多
限制(B/S的頁面模型)。所以與其不倫不類還不如將與人打交道的最終客戶端直接置身于本地的執(zhí)行環(huán)境中,并且這個執(zhí)行環(huán)境要具備“使得client的部
署和 B/S一樣方便,甚至你可以沒有client的概念,而只有獲得服務(wù)的概念。”
如果對這個執(zhí)行環(huán)境美其名曰一下:那么就叫它RIA平臺吧!
顯然這個東西沒有一個公共的標(biāo)準(zhǔn),所以幾路人馬現(xiàn)在是各自而戰(zhàn),來打造這一平臺,并且進(jìn)行部署。
如Flex那一路,在部署的時候搞的是:悄悄的進(jìn)行,打搶的不要。因?yàn)槭悄壳爸髁鳛g覽器都裝有flash player,等于無形中它的RIA平臺已經(jīng)部署好了。
而MS顯然是大張旗鼓:我是老大我怕誰。一句話,因?yàn)閷S來說vista就是RIA平臺。當(dāng)然細(xì)分一下應(yīng)該是其上的.net平臺來支撐RIA。因?yàn)镸S原有在桌面OS的壟斷地位,使得它將.net融于vista以大兵團(tuán)作戰(zhàn),成敗在此一舉!
不管怎么說,vista比起其他幾路人馬,確實(shí)是最完整,最強(qiáng)大的RIA平臺。
b/s增強(qiáng)前臺交互能力的方向意味著什么,意味著在要有更強(qiáng)的描述行為邏輯的語言(程序設(shè)計(jì)語言)寫的東西在本地執(zhí)行,那么這些描述行為邏輯的語言是不是有好多,。。。。。。???!!!!
其二,有很多應(yīng)用僅憑Http(請求---響應(yīng))這種交互方式不夠,比如有些是要請求----回調(diào),還有一些是觀察者模型的交互等
等.比如報(bào)價系統(tǒng)就是屬于這種觀察者模型的,客戶端發(fā)送某個報(bào)價信息的請求,那么以后這個報(bào)價一有變化服務(wù)器端就要立刻通知客戶端(這里TGP連接要一直
保持著).
其三,是UI,采用HTML描述的UI過于不足,很多應(yīng)用需要構(gòu)建豐富的UI.
如果B/S架構(gòu)做到了以上說的,那么還是B嗎???平臺無關(guān)性又如何保證???
其實(shí)對于這個問題應(yīng)該這么說: b/s向基礎(chǔ)平臺發(fā)展是一個扭曲的發(fā)展,
因?yàn)樗且粋€應(yīng)用架構(gòu).
而由OS延伸則更為合理.
當(dāng)然如果某個應(yīng)用符合B/S架構(gòu),那么b/s當(dāng)然是不錯的選擇.只是它向基礎(chǔ)平臺發(fā)展是一個扭曲的發(fā)展.(再次強(qiáng)調(diào)!)
或者這個話題可以這么說:
希望b/s向基礎(chǔ)平臺發(fā)展可以快點(diǎn)結(jié)束了!
我們來看一個問題。
定義一個描述信息(內(nèi)容)的語言的標(biāo)準(zhǔn)(HTML,XML...),和定義一個一統(tǒng)的程序語言(java ,c,c++,c#,.................)的標(biāo)準(zhǔn)哪一個容易。
事實(shí)告述我們應(yīng)該是前者。也就是說Application背后的運(yùn)行環(huán)境注定是多樣性的。
那么web為什么能跨平臺呢?因?yàn)樗鼈児蚕淼氖乔罢撸粋€HTML標(biāo)準(zhǔn),HTML不是Application。然而扭曲就從這里開始,HTML不斷擴(kuò)展在向Application演進(jìn),隨之跨平臺特性不斷削弱。
那么這樣一個演化說明了什么呢?說明我們需要Application,且它要像web一樣易部署。我們可以稱使得這樣的Application得以運(yùn)行的平臺為互聯(lián)網(wǎng)應(yīng)用平臺。
但Application終究有很多不同的平臺,互聯(lián)網(wǎng)應(yīng)用平臺也不例外。但我們想想web演化的最后是不是還是難逃Application平臺的多樣性呢!(而且它走的路扭曲的多)
所以問題關(guān)鍵回到了誰將最有可能成為互聯(lián)網(wǎng)應(yīng)用平臺的老大,目前來看實(shí)力最強(qiáng)還是vista.
其實(shí)個人感覺vista一大使命就是要將傳統(tǒng)OS延伸成一個互聯(lián)網(wǎng)應(yīng)用平臺,很多人似乎忽略了MS的這個野心。
Tim Berners-Lee的說Web是一個"信息空間"。很精辟!
但我們更需要互聯(lián)網(wǎng)是一個"服務(wù)空間",技術(shù)一點(diǎn)的話叫"Application空間",只是這些Application要以服務(wù)的方式提供出去.所以人性化的講法叫"服務(wù)空間".
當(dāng)然提供信息也是服務(wù),所以前者是后者的一個子集!
都知道java的字符編碼方案是采用unicode的。
比如 String test = "test 編碼";
那么"test 編碼"是采用unicode編碼后的二進(jìn)制形式保存。
然而如果要把test輸出到系統(tǒng)邊界以外的地方,那么都可能要涉及到編碼轉(zhuǎn)換問題,無論是文件還是網(wǎng)絡(luò)的另一端。
不過沒關(guān)系,java提供了強(qiáng)大的I/O庫,有Reader 和 Writer兩個適配器體系,我們可以將test以我們想要的編碼方案輸出。
但是如果將test的東西輸出到界面時到有些問題了,本來從概念上界面也是系統(tǒng)的邊界,所以unix有一切皆文件的抽象,當(dāng)然如果界面是交互
性GUI時這個抽象顯然是不夠的,這就不論了。關(guān)鍵是GUI系統(tǒng)并沒有提供類似javaI/O的這種能力,java也沒有直接以unicode形式輸出給
GUI系統(tǒng),而是好像會把內(nèi)存中變量字符再通過系統(tǒng)默認(rèn)語言(字符集)編碼去轉(zhuǎn)換,然后扔給繪圖系統(tǒng)吧!
這樣的話如果 JLable label = new JLabel(test);
那么這個label的顯示在簡體中文版的OS上沒問題,但如果在繁體中文版的OS可能就有問題了。
按理說swing是獨(dú)立于本地OS的GUI系統(tǒng),但是他還是建立在java2D上,而java2D還是要利用本地的繪圖系統(tǒng),像渲染文字這種繪圖是不是java2D還是利用了本地繪圖系統(tǒng)呢!
java GUI “?” “口” 這兩個我都碰到過。
如果某中編碼方案里沒有這個文字,java會用" ?"這個代替。
如果某種文字沒有相應(yīng)的字體,java會用"口"代替。
java在輸出到系統(tǒng)界面時會把內(nèi)存中變量字符再通過系統(tǒng)默認(rèn)語言(字符集)編碼去轉(zhuǎn)換!
我覺得如果java自己實(shí)現(xiàn)所有unicode支持的文字的繪圖(基于更低級的圖形API),那么他沒有必要轉(zhuǎn),因?yàn)閡nicode字符給java圖形系統(tǒng),他都能把它表現(xiàn)出來,當(dāng)然java圖形系統(tǒng)基于OS的更低級的圖形API。
是不是java自己實(shí)現(xiàn)所有unicode支持的文字的繪圖這項(xiàng)任務(wù)比比較困難。
如果java能做到這樣真的很強(qiáng)大啊!
這樣的話JLable label = new JLabel(test); 無論在什么語言版的OS 都OK。
說到MVC,大家都知道他是構(gòu)建GUI的有力模型。不過MVC本身比較抽象和寬泛,所以對于它的實(shí)現(xiàn)有很多。
swing對于MVC的實(shí)現(xiàn)用一句話來說就是:一個GUI組件對應(yīng)著一個MVC體系。
在這個體系當(dāng)中JComponent這樣的組件就扮演者M(jìn)VC中的C,那拿JTable來說,MVC 就是 TableModel JTable TableUI.
這種將MVC幾乎實(shí)施到每一個GUI元素的設(shè)計(jì)相當(dāng)?shù)撵`活.對于swing 的MVC還有一個重要的特點(diǎn)就是它對于model
作了進(jìn)一步的區(qū)分,那就是真正表達(dá)程序數(shù)據(jù)的model,和僅僅表達(dá)界面狀態(tài)的model.還拿JTable 來說就是: TableModel 與
TableColumnModel.
在很多地方看到都說swing的這種MVC的劃分多被科學(xué)家欣賞,這我就不能茍同了,我是普通人,不過我也很欣賞.swing高雅而又不失實(shí)用.
當(dāng)然也有人會說盡管swing的MVC很精彩,不過通常我們程序中model都不是僅僅對應(yīng)在一個GUI元素上,甚至不能確定要對應(yīng)在哪些GUI元素上.
定義這樣的類通常仍然很死:
class MyModel implements TableModel,ListModel{
}
我覺得對于swing的設(shè)計(jì)沒有什么錯,它為每一個組件期待的model定義了相應(yīng)的接口.但是我們程序當(dāng)中的model又希望更獨(dú)立于GUI.
為了達(dá)到兩全其美,到可以使用Eclipse里面的IAdaptable
機(jī)制.讓你的model具有 IAdaptable能力,這樣你就可以將它隨便適配到哪個swing model 上.如此的組合真是從頭到腳的靈活性.
還有swing的這種MVC設(shè)計(jì)也促成了swing的可插拔外觀特性.
不管你的項(xiàng)目是否用到了Swing技術(shù),我都要說,Swing是一個設(shè)計(jì)優(yōu)秀的Java包,它充滿了大師的智慧。如果你學(xué)了Java卻連一個
Button還不會寫,就象你學(xué)習(xí)Visual
Basic卻不會用Button,那可絕對是不能被原諒的。Swing技術(shù)的應(yīng)用已經(jīng)在國外大行其道,由于java的免費(fèi)、易學(xué)以及大家對于java技術(shù)
的充分信賴,好多公司早早的就把應(yīng)用程序的一切,從后臺服務(wù)到前臺人機(jī)交互界面,統(tǒng)統(tǒng)移到了java開發(fā)上。Swing出現(xiàn)了快10年了,憑借其先進(jìn)的設(shè)
計(jì)思想,一直未曾落后于哪種語言的界面開發(fā)技術(shù),使用和理解Swing的設(shè)計(jì)思想,對軟件開發(fā)者大有裨益。
Swing的設(shè)計(jì)是MVC的典范。雖然MVC的概念有點(diǎn)泛濫,可是真正能夠理解并熟練掌握、在設(shè)計(jì)和開發(fā)里面自然流露的并不多見。記得用VC
++開發(fā)程序時候,MFC向?qū)б彩巧蒁ocument和View兩個類,當(dāng)時一直奇怪為什么這么繞圈子。再看Swing的設(shè)計(jì),則到處充滿了MVC的痕
跡。仔細(xì)研究Swing中事件監(jiān)聽、Model-View分離、Renderer/Editor機(jī)制、可插拔的LookAndFeel等機(jī)制,簡直就是一
門藝術(shù),充滿了美感。而如果你非常痛恨這些設(shè)計(jì)并覺得他們怪異,很可能你是剛從VB或者Delphi轉(zhuǎn)過來,這些快速開發(fā)工具幫助了你也“害”了你。
Swing設(shè)計(jì)的不錯,不過可能過度學(xué)術(shù)化的設(shè)計(jì)也使得Swing跑起來并不靈巧,學(xué)習(xí)難度也大。這客觀上確實(shí)使得Swing一直沒有被廣泛
使用,而且廣受詬病。記得以前“Swing有什么成功的應(yīng)用嗎?”之類的帖子一直是熱門話題。IBM等則趁機(jī)抓住小辮子弄了SWT吸引了不少人,使得
Java GUI技術(shù)面臨分裂的危險(xiǎn)。
不過隨著JAVA的不斷升級和優(yōu)化,Swing的速度一直在提高,美觀性也在改善,基于Swing的成功應(yīng)用也越來越多了。關(guān)于Swing是否消亡或被SWT代替或是否能作桌面應(yīng)用的爭論逐漸少了。不過喜歡并精通Swing技術(shù)的開發(fā)者,尤其在國內(nèi),依舊非常少。
好在情況在轉(zhuǎn)好。Sun正意識到Eclipse和SWT所帶來的威脅,下了大力氣發(fā)展NetBeans,其最新版本對Swing
GUI可視化設(shè)計(jì)的支持已經(jīng)超過了所有對手,其Rich
Client框架也走向成熟,這對Swing的發(fā)展和應(yīng)用是一個很大的推動。隨著WEB熱潮的減退,人們又更多的開始理性的思考B/S和C/S架構(gòu)的選
擇,某些領(lǐng)域Swing技術(shù)已經(jīng)成為首選的解決方案。
隨著JGoodies、JIDE、TWaver等優(yōu)秀Swing產(chǎn)品的不斷涌現(xiàn),Swing會以更快速度在桌面應(yīng)用中普及。
轉(zhuǎn)載之
http://blog.csdn.net/solo/archive/2006/05/12/725635.aspx
領(lǐng)域視圖是指:某個領(lǐng)域功能對應(yīng)的交互界面。
界面體系視圖是指:是指某種組織這些領(lǐng)域視圖的UI方案。如MDI(多內(nèi)部窗口)如以前的word等,還有像現(xiàn)在eclipse的面板分割方案,docking等等。
那么將兩者做嚴(yán)格的區(qū)分有什么好處呢?
很顯然可以獲得領(lǐng)域視圖的獨(dú)立性,以達(dá)到適應(yīng)多種界面體系的靈活性,甚至在運(yùn)行時進(jìn)行界面體系的切換。
在swing中有時候我們常常有這樣的寫法;
MyInternalFrame extends JInternalFrame{
}
其實(shí)這種寫法是比較死的,因?yàn)橄馢InternalFrame這種view是屬于界面體系視圖范疇的東西。
如果我們的界面體系不采用InternalFrame風(fēng)格時,改動量是很大的。
其實(shí)如果這樣是不是更好呢!
interface DomainObject{
JComponent getDomainView();
}
不同的界面體系模塊拿到DomainView時以自己的方式對DomainView進(jìn)行包裝。比如是內(nèi)部桌面的話就將DomainView塞到JInternalFrame里,以JInternalFrame包裝之。
在文檔中對JTable 解釋是:用來顯示和編輯規(guī)則的二維單元表。
也就是說JTable的類型定義決定了它是一個規(guī)則的二維單元表,但是對于二維單元表內(nèi)單元格的顯示和編輯組件的選擇又是極其靈活的.
有如下兩個接口:
TableCellEditor
Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column);
TableCellRenderer
Component getTableCellRendererComponent(JTable table, Object
value, boolean isSelected, boolean hasFocus, int row, int column)
所有實(shí)現(xiàn)這兩個接口的對象都可以配置到JTable.JTable自身定義了單元格的狀態(tài):表現(xiàn)或編輯.
當(dāng)JTabel處于表現(xiàn)狀態(tài)時它會調(diào)用
ableCellRenderer的Component getTableCellRendererComponent(JTable
table, Object value, boolean isSelected, boolean hasFocus, int row, int
column)請求表現(xiàn)組件.
當(dāng)JTabel處于編輯狀態(tài)時它會調(diào)用TableCellEditor的Component
getTableCellEditorComponent(JTable table, Object value, boolean
isSelected, int row, int column);請求編輯組件.
這樣我們實(shí)現(xiàn)TableCellEditor,TableCellRenderer這兩個接口就可以靈活的控制表格單元格的編輯和顯示.
當(dāng)然為了方便swing已經(jīng)定義了這兩個接口的默認(rèn)實(shí)現(xiàn),如DefaultCellEditor,DefaultTableCellRenderer.
雖然我們有了靈活控制編輯和表現(xiàn)的接口,但是如何控制編輯和表現(xiàn)狀態(tài)的轉(zhuǎn)換呢!
首先單元格可不可以編輯由表格的模型控制。因?yàn)橥ǔ?刹豢梢跃庉嬋Q于數(shù)據(jù)內(nèi)容,所以將它定義在模型中是合理的!
TableModel 接口有如下一個方法:
boolean isCellEditable(int rowIndex, int columnIndex) ;
JTabel會通過他來確定可不可以編輯。
在可編輯的情況下,通過JTabel的 boolean editCellAt(int row, int column) ,可以啟動單元格進(jìn)入編輯狀態(tài)。那么如何控制從編輯狀態(tài)退出呢?
這個稍微復(fù)雜一點(diǎn),因?yàn)閺木庉嫚顟B(tài)退出還很可能意味著要將編輯器的內(nèi)容放入表格模型。
這里有一個接口
public interface CellEditor{
void addCellEditorListener(CellEditorListener l)
Object getCellEditorValue()
void removeCellEditorListener(CellEditorListener l)
void cancelCellEditing()
boolean stopCellEditing()
.................
}
TableCellEditor繼承自它,也就是說swing對單元格編輯器作了更抽象的定義。因?yàn)椴粌H僅是表格需要編輯。這里有個監(jiān)聽器的注冊方法,看一下CellEditorListener的定義
public interface CellEditorListener extends EventListener
{
void editingCanceled(ChangeEvent e)
void editingStopped(ChangeEvent e)
}
很顯然編輯狀態(tài)結(jié)束的關(guān)鍵在CellEditor上。你可以主動發(fā)出事件通知CellEditorListener說結(jié)束了。也可以由外部調(diào)用
void cancelCellEditing()
boolean stopCellEditing()
觸發(fā)。而CellEditorListener得到通知后通常可以調(diào)用
Object getCellEditorValue()來獲得編輯器的值。例如JTable 就實(shí)現(xiàn)了CellEditorListener,當(dāng)你將你的TableCellEditor設(shè)置到JTable時,JTable就會注冊上去。
有了靈活控制編輯和表現(xiàn)的接口,也有了控制編輯和表現(xiàn)狀態(tài)的轉(zhuǎn)換機(jī)制.不過完全從這些接口開始構(gòu)建一套自己的實(shí)現(xiàn),也是很累的。顯然swing已經(jīng)有一套比較通用的實(shí)現(xiàn)。
首先看一下對于控制編輯和表現(xiàn)狀態(tài)的轉(zhuǎn)換,JTable有自己的一套定義,在外部事件觸發(fā)下單元格編輯和表現(xiàn)狀態(tài)的轉(zhuǎn)換,比如在單元格上雙擊
會使得該單元格進(jìn)入編輯狀態(tài),當(dāng)編輯狀態(tài)的單元格失去焦點(diǎn)時,該單元格離開編輯狀態(tài)進(jìn)入表現(xiàn)狀態(tài)。在同一時刻只有一個單元格可以進(jìn)入編輯狀態(tài)等。
再來看一下DefaultTableCellRenderer和DefaultCellEditor
DefaultTableCellRenderer繼承JLabel實(shí)現(xiàn)TableCellRenderer 接口。也就是說表格通常的單元格表現(xiàn)都是JLabel組件。
這個實(shí)現(xiàn)其實(shí)有一個巧妙之處,在實(shí)現(xiàn)
Component getTableCellRendererComponent(JTable table, Object
value, boolean isSelected, boolean hasFocus, int row, int column) {
。。。。。。。。。。。
return this;
}這個方法中
最后一句return this;表明不管單元格有多少,JLabel對象一直只有一個,只是針對不同的單元格JLabel對象的狀態(tài)不一樣,但實(shí)例只有一個,儉省很多資源。
DefaultCellEditor繼承AbstractCellEditor,而AbstractCellEditor
實(shí)現(xiàn)了TableCellEditor。這里順便講一下,swing對很多接口的實(shí)現(xiàn)都有這兩個層次,對于default的都是一個可用的實(shí)現(xiàn),而
Abstract多是抽象類,他只實(shí)現(xiàn)了接口的一部分,而這一部分通常都是很通用的。如果覺得default不能滿足要求,而覺得實(shí)現(xiàn)整個接口又麻煩,
Abstract的就很有用。
DefaultCellEditor有三個構(gòu)造函數(shù):
DefaultCellEditor(JCheckBox checkBox)
DefaultCellEditor(JComboBox comboBox)
DefaultCellEditor(JTextField textField)
因?yàn)榫庉嫴幌癖憩F(xiàn)那么單純,通常使用編輯器的對象(如JTable)都要獲得編輯器的值,然而不同編輯器的對外接口又是非常繁多的,所以CellEditor有這樣一個方法
Object getCellEditorValue()
;也就是說使用編輯器的對象(如JTable)不管實(shí)際編輯器有多繁雜,它就只通過Object
getCellEditorValue()這個方法獲取值。那么當(dāng)你要把你的編輯器用到比如JTable上,那么就要考慮如何將你的編輯器接口適配到
JTable期望的Object getCellEditorValue() 上。
DefaultCellEditor的構(gòu)造函數(shù)就是一個提供了可以將三種編輯器進(jìn)行適配。其實(shí)這是一種適配器模式。也就是DefaultCellEditor可以適配三種編輯器。
忽略了一個很重要的問題,就是如何將我們的編輯器或表現(xiàn)器注冊到JTable上?
這個看是很簡單的問題,其實(shí)也并非想象當(dāng)中那么簡單。
先看一下JTable提供的明顯的注冊接口
void setCellEditor(TableCellEditor anEditor) ;
void setDefaultEditor(Class<?> columnClass, TableCellEditor editor)
void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer)
第一個接口很顯然整個表格單元格的編輯器將由這個注冊的編輯器接管。
后面兩個是基于數(shù)據(jù)類型進(jìn)行配置的,也就是說這種數(shù)據(jù)類型的單元格編輯器將由注冊的編輯器接管。
那么如何決定數(shù)據(jù)類型呢?看表格模型TableModel里有一個方法
Class<?> getColumnClass(int columnIndex);
很明顯和是否可編輯一樣,數(shù)據(jù)類型由模型決定。
除此之外還有另外的注冊方法,那就是表格本身也是有其他元素組成,在JTable中下一級元素是列,TableColumn。它有這兩個方法
void setCellEditor(TableCellEditor cellEditor)
void setCellRenderer(TableCellRenderer cellRenderer)
可以將編輯器和表現(xiàn)器直接注冊在列上,那么這一列的編輯或表現(xiàn)將由你注冊的東西接管。