GEF入門系列(五、淺談布局).doc_第1頁
GEF入門系列(五、淺談布局).doc_第2頁
GEF入門系列(五、淺談布局).doc_第3頁
GEF入門系列(五、淺談布局).doc_第4頁
GEF入門系列(五、淺談布局).doc_第5頁
已閱讀5頁,還剩1頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

GEF入門系列(五、淺談布局)雖然很多GEF應(yīng)用程序里都會(huì)用到連接(Connection),但也有一些應(yīng)用是不需要用連接 來表達(dá)關(guān)系的,我們目前正在做的這個(gè)項(xiàng)目就是這樣一個(gè)例子。在這類應(yīng)用中,模型對(duì)象間 的關(guān)系主要通過圖形的包含來表達(dá),所以大多是一對(duì)多關(guān)系。 圖1 不使用連接的GEF應(yīng)用先簡單描述一下我們這個(gè)項(xiàng)目,該項(xiàng)目需要一個(gè)圖形化的模型編輯器,主要功能是在一個(gè) 具有三行N列的表格中自由增加/刪除節(jié)點(diǎn),節(jié)點(diǎn)可在不同單元格間拖動(dòng),可以合并相鄰節(jié)點(diǎn) ,表格列可增減、拖動(dòng)等等。由于SWT/Jface提供的表格很難實(shí)現(xiàn)這些功能,所以我們選擇了 使用GEF開發(fā),目前看來效果還是很不錯(cuò)的(見下圖),這里就簡單介紹一下實(shí)現(xiàn)過程中與圖 形和布局有關(guān)的一些問題。在動(dòng)手之前首先還是要考慮模型的構(gòu)造。由于Draw2D只提供了很有限的Layout,如 ToolbarLayout、FlowLayout和XYLayout,并沒有一個(gè)GridLayout,所以不能把整個(gè)表格作為 一個(gè)EditPart,而應(yīng)該把每一列看作一個(gè)EditPart(因?yàn)閷?duì)列的操作比對(duì)行的操作多,所以 不把行作為EditPart),這樣才能實(shí)現(xiàn)列的拖動(dòng)。另外,從需求中可以看出,每個(gè)節(jié)點(diǎn)都包 含在一個(gè)列中,但仔細(xì)再研究一下會(huì)發(fā)現(xiàn),實(shí)際上節(jié)點(diǎn)并非直接包含在列中,而是有一個(gè)單 元格對(duì)象作為中間的橋梁,即每個(gè)列包含固定的三個(gè)單元格,每個(gè)單元格可以包含任意個(gè)節(jié) 點(diǎn)。經(jīng)過以上分析,我們的模型、EditPart和Figure應(yīng)該已經(jīng)初步成形了,見下表:模型EditPartFigure畫布DiagramDiagramPartFreeformLayer列ColumnColumnPartColumnFigure單元格CellCellPartCellFigure節(jié)點(diǎn)NodeNodePartNodeFigure表中從上到下是包含關(guān)系,也就是一對(duì)多關(guān)系,下圖簡單顯示了這些關(guān)系:圖2 圖形包含關(guān)系圖讓我們從畫布開始考慮。在畫布上,列顯示為一個(gè)縱向(高大于寬)的矩形,每個(gè)列有一 個(gè)頭(Header)用來顯示列名,所有列在畫布上是橫向排列的。因此,畫布應(yīng)該使用 ToolbarLayout或FlowLayout中的一種。這兩種Layout有很多相似之處,尤其它們都是按指定 的方向排列顯示圖形,不同之處主要在于:當(dāng)圖形太多容納不下的時(shí)候,ToolbarLayout會(huì)犧 牲一些圖形來保持一行(列),而FlowLayout則允許換行(列)顯示。對(duì)于我們的畫布來說,顯然應(yīng)該使用ToolbarLayout作為布局管理器,因?yàn)樗淖訄D形 ColumnFigure是不應(yīng)該出現(xiàn)換行的。以下是定義畫布圖形的代碼:Figure f = new FreeformLayer();ToolbarLayout layout=new ToolbarLayout();layout.setVertical(false);layout.setSpacing(5);layout.setStretchMinorAxis(true);f.setLayoutManager(layout);f.setBorder(new MarginBorder(5);其中setVertical(false)指定橫向排列子圖形,setSpacing(5)指定子圖形之間保留5象素 的距離,setStretchMinorAxis(true) 指定每個(gè)子圖形的高度都保持一致。ColumnFigure的情況要稍微復(fù)雜一些,因?yàn)樗幸粋€(gè)頭部區(qū)域,而且它的三個(gè)子圖形( CellFigure)合在一起要能夠充滿下部區(qū)域,并且適應(yīng)其高度的變化。一開始我用Draw2D提 供的Label來實(shí)現(xiàn)列頭,但有一個(gè)不足,那就是你無法設(shè)置它的高度,因?yàn)長abel類覆蓋了 Figure的getPreferedSize()方法,使得它的高度只與里面的文本有關(guān)。解決方法是構(gòu)造一個(gè) HeaderFigure,讓它維護(hù)一個(gè)Label,設(shè)置列頭高度時(shí)實(shí)際設(shè)置的是HeaderFigure的高度;或 者直接讓HeaderFiguer繼承Label并重新覆蓋getPreferedSize()也可以。我在項(xiàng)目里使用的 是前者。第二個(gè)問題花了我一些時(shí)間才搞定,一開始我是在CellPart的refreshVisuals()方法里手 動(dòng)設(shè)置CellFigure的高度為ColumnFigure下部區(qū)域高度的三分之一,但這樣很勉強(qiáng),而且還 需要額外考慮spacing帶來的影響。后來通過自定義Layout的方式比較圓滿的解決了這個(gè)問題 ,我讓ColumnFigure使用自定義的ColumnLayout,這個(gè)Layout繼承自ToolbarLayout,但覆蓋 了layout()方法,內(nèi)容如下:class ColumnLayout extends ToolbarLayout public void layout(IFigure parent) IFigure nameFigure=(IFigure)parent.getChildren().get(0);IFigure childrenFigure=(IFigure)parent.getChildren().get(1);Rectangle clientArea=parent.getClientArea();nameFigure.setBounds(new Rectangle (clientArea.x,clientArea.y,clientArea.width,30);childrenFigure.setBounds(new Rectangle(clientArea.x,nameFigure.getBounds ().height+clientArea.y,clientArea.width,clientArea.height-nameFigure.getBounds ().height);也就是說,在layout里控制列頭和下部的高度分別為30和剩下的高度。但這還沒有完,為 了讓單元格正確的定位在表格列中,我們還要指定列下部圖形(childrenFigure)的布局管 理器,因?yàn)閷?shí)際上單元格都是放在這個(gè)圖形里的。前面說過,Draw2D并沒有提供一個(gè)像SWT中 FillLayout那樣的布局管理器,所以我們要再自定義另一個(gè)layout,我暫時(shí)給它起名為 FillLayout(與SWT的FillLayout同名),還是要覆蓋layout方法,如下所示(因?yàn)橛昧?transposer所以horizontal和vertical兩種情況可以統(tǒng)一處理,這個(gè)transposer只在 horizontal時(shí)才起作用):public void layout(IFigure parent) List children = parent.getChildren();int numChildren = children.size();Rectangle clientArea = transposer.t(parent.getClientArea();int x = clientArea.x;int y = clientArea.y;for (int i = 0; i numChildren; i+) IFigure child = (IFigure) children.get(i);Rectangle newBounds = new Rectangle(x, y, clientArea.width, -1);int divided = (clientArea.height - (numChildren - 1) * spacing) / numChildren;if (i = numChildren - 1)divided = clientArea.height - (divided + spacing) * (numChildren - 1);newBounds.height = divided;child.setBounds(transposer.t(newBounds);y += newBounds.height + spacing;上面這些語句的作用是將父圖形的高(寬)度平均分配給每個(gè)子圖形,如果是處于最后的 一位的子圖形,讓它占據(jù)所有剩下的空間(防止除不盡的情況留下空白)。完成了這個(gè) FillLayout,只要讓childrenFigure使用它作為布局管理器即可,下面是ColumnFigure的大 部分代碼,列頭圖形(HeaderFigure)和列下部圖形(ChildrenFigure)作為內(nèi)部類存在:private HeaderFigure name = new HeaderFigure();private ChildrenFigure childrenFigure = new ChildrenFigure();public ColumnFigure() ToolbarLayout layout = new ColumnLayout();layout.setVertical(true);layout.setStretchMinorAxis(true);setLayoutManager(layout);setBorder(new LineBorder();setBackgroundColor(color);setOpaque(true);add(name);add(childrenFigure);setPreferredSize(100, -1);class ChildrenFigure extends Figure public ChildrenFigure() ToolbarLayout layout = new FillLayout();layout.setMinorAlignment(ToolbarLayout.ALIGN_CENTER);layout.setStretchMinorAxis(true);layout.setVertical(true);layout.setSpacing(5);setLayoutManager(layout);class HeaderFigure extends Figure private String text;private Label label;public HeaderFigure() this.label = new Label();this.add(label);setOpaque(true);public String getText() return this.label.getText();public Rectangle getTextBounds() return this.label.getTextBounds();public void setText(String text) this.text = text;this.label.setText(text);this.repaint();public void setBounds(Rectangle rect) super.setBounds(rect);this.label.setBounds(rect);單元格的布局管理器同樣使用FillLayout,因?yàn)樵谛枨笾校脩粝騿卧窭锾砑拥谝粋€(gè)節(jié) 點(diǎn)時(shí),該節(jié)點(diǎn)要充滿單元格;當(dāng)單元格里有兩個(gè)節(jié)點(diǎn)時(shí),每個(gè)節(jié)點(diǎn)占二分之一的高度;依次 類推。下面的表格總結(jié)了各個(gè)圖形使用的布局管理。由表可見,只有包含子圖形的那些圖形 才需要布局管理器,原因很明顯:布局管理器關(guān)心和管理的是子圖形,請(qǐng)時(shí)刻 牢記這一點(diǎn)。布局管理器直接子圖形畫布ToolbarLayout列列ColumnLayout列頭部、列下部-列頭部無無-列下部FillLayout單元格單元格FillLayout節(jié)點(diǎn)節(jié)點(diǎn)無無這里需要特別提醒一點(diǎn):在一個(gè)圖形使用ToolbarLayout或子類作為布局管理器時(shí),圖形 對(duì)應(yīng)的EditPart上如果安裝了FlowLayoutEditPolicy或子類,你可能會(huì)得到一個(gè) ClassCastException異常。例如例子中的CellFigure,它對(duì)應(yīng)的EditPart是CellPart,其上 安裝了CellLayoutEditPolicy是FlowLayoutEditPolicy的一個(gè)子類。出現(xiàn)這個(gè)異常的原因是 在FlowLayoutEditPolicy的isHorizontal()方法中會(huì)將圖形的layout強(qiáng)制轉(zhuǎn)換為FlowLayout ,而我們使用的是ToolbarLayout。我認(rèn)為這是GEF的一個(gè)疏忽,因?yàn)樽髡咴f過FlowLayout 可應(yīng)用于ToolbarLayout。幸好解決方法也不復(fù)雜:在你的那個(gè)EditPolicy中覆蓋 isHorizontal()方法,在這個(gè)方法里先判斷l(xiāng)ayout是ToolbarLayout還是FlowLayout,再根據(jù) 結(jié)果返回合適的boolean值即可。最后,關(guān)于我們的畫布還有一個(gè)問題沒有解決,我們希望表格列增多到一定程度后,畫布 可以向右邊擴(kuò)展尺寸,前面說過畫布使用的是FreeformLayer作為圖形。為了達(dá)到目的,還必 須在editor里設(shè)置rootEditPart為ScalableRootEd

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論