<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    月蝕傳說

    浮躁讓人失去理智
    posts - 25, comments - 101, trackbacks - 0, articles - 0
      BlogJava :: 首頁 ::  :: 聯系 :: 聚合  :: 管理

    能夠拖動的矩形

    Posted on 2006-10-09 18:59 Dart 閱讀(1694) 評論(6)  編輯  收藏 所屬分類: GEF

    這章我將說一下如何去實現一個數據表在編輯器上顯示,并且能夠進行位置和尺寸的改變。我們將涉及到的內容有:Figure,EditPolicy,Command。示例代碼下載

    1.在Editor上實現一個簡單的數據表

    上一章中,我們實現了一個空的Editor,畫布上什么都沒有,今天我會讓它顯示點東西。
    我們已經說過了,Editor要顯示一個圖形,是根據我們給Viewer設置的模型,找到對應的EditPart,然后調用EditPart的createFigure得到圖形,最后繪制在Editor上,大致如下:

    http://album.sina.com.cn/pic/5414465b02000419



    我們需要做的事情就讓我們的TableEditPart復寫基類的createFigure方法,然后返回一個Figure圖形,最后再在代碼中更改我們最初設置的模型內容。

    創建TableFigure

    一般來說,當我們需要生成一個Figure圖形的時候,最好的辦法就是從Figure類繼承一個新的類出來,然后復寫Figure的paintFigure方法,繪制出我們想要的圖案。見下代碼:

    public ? class ?TableFigure?extends?Figure?{

    ????
    protected ? void ?paintFigure(Graphics?graphics)?{
    ????????super.paintFigure(graphics);
    ????????
    // ?得到Figure的Bounds
    ????????Rectangle?bounds? = ?getBounds();
    ????????
    // ?在它周圍繪制一個矩形,寬度和高度稍微小一點,以便能全部顯示
    ????????graphics.drawRectangle(bounds.x,bounds.y,bounds.width? - ? 1 ?,?bounds.height? - ? 1 );
    ????}
    }


    TableFigure 顯示的是一個矩形圖形。getBounds方法是得到的是Figure的范圍對象,這個對象是一個Recangle類型,包括有圖形的坐標(Point),以及尺寸(Dimension),而這個范圍對象并不是我們去指定的,而是根據TableFigure的父Figure來給它設定的。這里需要說一下,在GEF中,EditPart在繪制Figure的時候,步驟是先繪制好自己的Figure,然后查看自己的子EditPart,獲得他們的Figure,確定他們的大小位置(根據默認或者是本身Figure的布局管理器來得到)繪制在自身Figure之上,也就是說,這是一個遞歸的過程。

    修改TableEditPart代碼

    我們已經生成了一個TableFigure類,現在我們需要讓TableEditPart的createFigure方法返回這個類的一個實例。

    public ? class ?TableEditPart?extends?DBEditPartBase?{

    ????
    protected ?IFigure?createFigure()?{
    ????????
    // ?返回Table的Figure
    ???????? return ? new ?TableFigure();
    ????}
    }


    重新設置模型

    我們創建Editor的時候,在初始化Viewer的方法中,生成了一個Schema模型給它,現在我們需要把我們的Table模型添加上去,也就是說,讓新的Table模型作為Schema的子對象添加進去

    protected ? void ?initializeGraphicalViewer()?{
    ????????
    // ?硬編碼生成一個數據庫模型
    ????????
    // ?這個數據庫中有一個表
    ????????Schema?schema? = ? new ?Schema();
    ????????Table?table?
    = ? new ?Table();
    ????????
    ????????schema.addChild(table);
    ????????
    this .getGraphicalViewer().setContents(schema);
    ????}


    可以看得出來,我們其實只是修改了我們的模型,但是圖形顯示是和EditPart相關的,SchemaEditPart是如何得知它會擁有一個子EditPart —— TableEditPart的呢?仔細看下DBBaseEditPart就可以很清楚了。
    由于我們復寫了EditPart的getModelChildren,返回的是DBBaseEditPart對應模型的子模型,所以EditPart就可以通過這些子模型來得到子編輯單元(Chilren EditPart)

    ???? protected ?List?getModelChildren()?{

    ????????
    if (getModel()?instanceof?DBBase){
    ????????????
    return ?((DBBase)getModel()).getChildren();
    ????????}
    ????????
    return ?super.getModelChildren();
    ????}


    最后讓我們運行一下,得到了一個繪制有矩形的Editor:

    http://album.sina.com.cn/pic/5414465b0200041a



    2.初步討論EditPolicy

    在剛才我們實現的編輯其中,已經將Table模型的圖形顯示了出來,但是僅僅只是有一個矩形畫在畫布上,當我們點擊它的時候沒有任何反應,好像完全只是一張靜態的圖片,我們要的效果的并不是這個,而是需要一個能夠對其操作的圖形。

    第一章里我簡單地提到了在GEF中事件處理的過程,看看前面的文章可以知道,我們想要能夠對我們顯示的TableFigure圖形進行編輯,需要的是一個能夠處理相關Request的EditPolicy。

    EditPolicy的類型有很多,大致分為圖形相關和圖形無關兩大類,我在這個例子中使用到了這幾個圖形相關的EditPolicy:LayoutEditPolicy ,NonResizeableEditPolicy。

    LayoutEditPolicy 一般是作為父EditPart所具有的EditPolicy,就是說,如果我們的Figure需要對它的子EditPart進行一些圖形方面管理的話,使用這個EditPolicy比較合適。它能夠處理一些容器類EditPart的應該具備的操作:增加一個EditPart,刪除一個EditPart,移動子EditPart對應圖形等。

    并且它還能夠為它的子EditPart設置對應的EditPolicy,這樣一來就統一了子EditPart的一些行為。一會我講具體說一下這個問題。

    NonResizeableEditPolicy,顧名思義,它是一個不處理尺寸變化的EditPolicy,但是它能夠處理EditPart對應Figure位置變化,由于我們的數據表的大小需要根據它所擁有列來決定,外界不應該對它的尺寸進行修改,所以我在這里選用了它。

    怎么使用EditPolicy呢?EditPolicy是被"安裝"到EditPart上的,在EditPart中,有一個接口方法:createEditPolicies,我們要在這里面進行安裝。安裝EditPolicy使用installEditPolicy方法。

    回過頭再看看我們所要用的這兩個EditPolicy,他們兩個都應該安裝到哪個EditPart上呢。很顯然,LayoutEditPolicy應該安裝到父EditPart,也就是SchemaEditPart,這樣一來,SchemaEditPart就能對TableEditPart進行管理了; NonResizeableEditPolicy就應該屬于TableEditPart,我們需要用它來改變TableEditPart對應Figure 的位置。

    當然,LayoutEditPolicy和NonResizeableEditPolicy不能實例化后直接安裝到 EditPart上,因為我們還需要復寫他們的一些方法,稍后我們會提到。我們先創建兩個類,分別繼承LayoutEditPolicy, NonResizeableEditPolicy:

    public ? class ?SchemaLayoutEditPolicy?extends?LayoutEditPolicy?{

    ????
    protected ?EditPolicy?createChildEditPolicy(EditPart?child)?{
    ????????????? ?
    return ? null ;
    ????}
    ????
    protected ?Command?getCreateCommand(CreateRequest?request)?{
    ????????????? ?
    return ? null ;
    ????}

    ????
    protected ?Command?getDeleteDependantCommand(Request?request)?{
    ????????????????
    return ? null ;
    ????}

    ???
    protected ?Command?getMoveChildrenCommand(Request?request)?{
    ????????????? ?
    return ? null ;
    ????}

    }

    ?

    public ? class ?TableNonResizableEditPolicy?extends?NonResizableEditPolicy?{

    }


    很明顯,這輛個類只是繼承了基類,并沒有復寫或實現基類的方法。
    姑且這樣,我們先把SchemaLayoutEditPolicy安裝到SchemaEditPart上:

    ???? protected ? void ?createEditPolicies()?{
    ????????
    this .installEditPolicy(EditPolicy.LAYOUT_ROLE, new ?SchemaLayoutEditPolicy());
    ????}

    installEditPolicy 的第一個參數其實并沒有什么用,這個參數是一個String類型,隨便寫個字符串也不會影響到我們EditPolicy的安裝以及它的工作的(也有人說,如果第一個參數重復的話,EditPolicy會被覆蓋掉。我沒有研究過,各位朋友可以試一下)。

    好了,SchemaEditPart所需要的EditPolicy已經搞定,剩下TableEditPart了。大家可能會認為,安裝它的EditPolicy也和 SchemaEditPart一樣,復寫createEditPolicies方法,然后installEditPolicy即可。是的,這樣沒有問題,但是由于我們的SchemaLayoutEditPolicy中有這么一個接口方法:createChildEditPolicy,這就是我在前面所說的,為了統一管理,給子EditPart安裝所對應的EditPolicy。雖然這樣做和直接安裝的效果差不多(應該是一樣,但是也有可能有一些差別),但是我認為還是把子EditPolicy的安裝交給父EditPolicy吧:

    ???? protected ?EditPolicy?createChildEditPolicy(EditPart?child)?{
    ????????
    if (child?instanceof?TableEditPart)? return ? new ?TableNonResizableEditPolicy();
    ????????
    return ? new ?NonResizableEditPolicy();
    ????}

    好了,讓我們運行一下。呵呵,是不是可以點擊我們的“數據表”了。但是這樣還是不能移動我們的數據表。

    3. 修改我們的類 ;Command 的使用


    第一章我已經講過了,我們的模型有時需要添加一些和模型本身無關但和圖形有關的屬性。因為這樣一來我們就能夠記錄我們的圖形發生的位置變化,再通過模型的改變去通知EditPart刷新我們的圖形。
    我們先為Table增加一個屬性:location

    ???? protected ?Point?location? = ? new ?Point( 0 , 0 );
    ????
    /* *
    ?????*?@return?返回?location.
    ?????
    */
    ????
    public ?Point?getLocation()?{
    ????????
    return ?location;
    ????}
    ????
    /* *
    ?????*?@param?location?設置?location?
    ?????
    */
    ????
    public ? void ?setLocation(Point?location)?{
    ????????Point?old?
    = ? this .location;
    ????????
    this .location? = ?location;
    ????}


    這個屬性代表了圖形目前所在的位置坐標。

    有朋友要問:這里只是有了屬性,那當屬性改變的時候怎么去通知呢?我記得我也在第一章講了,一般的做法是為我們的模型增加一個屬性更改的事件發生源:PropertyChangeSupport

    我們把事件發生源寫到基類DBBase中,并增加幾個方法去發送事件以及添加刪除監聽器:

    ???? public ? static ?final?String?PRO_FIGURE? = ? " __figure__property " ;
    ????
    ????
    private ?PropertyChangeSupport?support? = ? new ?PropertyChangeSupport( this );

    ?
    public ? void ?addPropertyChangeListener(PropertyChangeListener?l){
    ????????support.addPropertyChangeListener(l);
    ????}
    ????
    ????
    public ? void ?removePropertyChangeListener(PropertyChangeListener?l){
    ????????support.removePropertyChangeListener(l);
    ????}
    ????
    ????
    public ? void ?fireFigurePropertyChange(Object?old,Object?now){
    ????????support.firePropertyChange(PRO_FIGURE,old,now);
    ????}


    好了,我們的事件源做好了,下面該想想讓誰去監聽了。

    毫無疑問,我們的監聽器應該是DBBaseEditPart,因為它才有能力去刷新Figure,所以我們需要更改DBBasEditPart代碼,如下:

    public ? class ?DBEditPartBase?extends?AbstractGraphicalEditPart?implements?PropertyChangeListener{
    ????
    public ? void ?activate()?{
    ????????
    if (getModel()? != ? null ? && ?getModel()?instanceof?DBBase){
    ????????????((DBBase)getModel()).addPropertyChangeListener(
    this );
    ????????}
    ????????super.activate();
    ????}
    ?????
    public ? void ?deactivate()?{
    ????????
    if (getModel()? != ? null ? && ?getModel()?instanceof?DBBase){
    ????????????((DBBase)getModel()).removePropertyChangeListener(
    this );
    ????????}
    ????????super.deactivate();
    ????}
    ????
    public ? void ?propertyChange(PropertyChangeEvent?evt)?{
    ???????String?pName?
    = ?evt.getPropertyName();
    ???????
    if (pName.equals(DBBase.PRO_FIGURE)){
    ???????????
    this .refreshVisuals();
    ???????}
    ????}
    }


    大家注意下propertyChange方法,當我們在獲得事件類型為PRO_FIGURE后,就會直接去調用refreshVisuals去刷新我們的Figure。
    但是refreshVisuals其實是空方法,它什么都沒有做!

    所以我們必須在TableEditPart中要復寫它:

    ??? protected ? void ?refreshVisuals()?{
    ????????super.refreshVisuals();
    ????????
    // ?得到當前Figure的位置和大小
    ????????Rectangle?rect? = ? this .getFigure().getBounds();
    ????????
    ????????
    // ?獲得更改后的位置
    ????????Point?p? = ?((Table)?getModel()).getLocation();
    ????????
    ????????
    // ?我們只更改Table的位置
    ????????((GraphicalEditPart)? this .getParent()).setLayoutConstraint( this ,? this
    ????????????????.getFigure(),
    new ?Rectangle(p,?rect.getSize()));
    ????}

    最后一句代碼是什么含義呢?這是讓TableEditPart去找到它的父EditPart,也就是SchemaEditPart,再讓它去“約束” TableEditPart圖形的位置和大小,當然了,我們這里沒有改變大小,只是通過Table模型的Location屬性去更改它的位置而已。當調用了setLayoutConstraint方法后,我們的圖形就會自動進行重繪。

    接下來,讓Table模型中更改location屬性時將更改事件發送出來,以便EditPart能夠截獲并處理:

    ????public?void?setLocation(Point?location)?{
    ????????Point?old?
    =?this.location;
    ????????
    this.location?=?location;
    ????????
    this.fireFigurePropertyChange(old,this.location);
    ????}


    我們已經做了很多調整,改了不少代碼了,這會運行看看吧!

    對不起,我們的TableFigure還是不會移動!
    這是由于我們忘記了在TableNonResizeableEditPolicy中做文章。

    剛才已經說過了,TableNonResizeableEditPolicy能夠處理對圖形移動的,但是它只是通知我們圖形移動了,要找我們索取一個 Command去執行這種變化。所以我們還需要寫一個Command類,讓這個Command去執行對模型位置的更改(關于Command的介紹請回過頭看第一章):

    public?class?TableMoveCommand?extends?Command?{

    ????
    private?ChangeBoundsRequest?request;
    ????
    ????
    private?Table?model;

    ????
    public?void?execute()?{
    ??????Point?old?
    =?getModel().getLocation();
    ??????
    int?x?=?request.getMoveDelta().x;
    ??????
    int?y?=?request.getMoveDelta().y;
    ??????
    ??????getModel().setLocation(
    new?Point(old.x+x,old.y+y));
    ????}
    }

    然后我們在TableNonResizeableEditPolicy中復寫getMoveCommand方法:

    ?protected?Command?getMoveCommand(ChangeBoundsRequest?request)?{

    ????????TableMoveCommand?command?
    =?new?TableMoveCommand();
    ????????command.setModel((Table)getHost().getModel());
    ????????command.setRequest(request);
    ????????
    return?command;
    ????}

    好了!這會再運行看看,是不是能移動了?

    4.結束語

    我們今天把上次例子代碼進行了一些修改,得到了一個能夠隨意改變位置的矩形,其中主要簡單地講述了一些EditPolicy如何使用。
    本人文筆比較爛,說事情總說不清,如果有不清楚的地方請留言,我會進行修改,盡量讓大家都能看懂。
    以后的章節,我們會繼續討論EditPolicy以及Figure布局等問題。

    評論

    # re: 能夠拖動的矩形  回復  更多評論   

    2007-01-12 16:57 by 過客[匿名]
    編輯器中,通過實現PaletteRoot工具,可以將自己定義的模型拖入到編輯器中,該模型以圖形化的形式在編輯器中顯示

    那如何將視圖中TreeViewer的節點(每個節點都有相應的模型對應)拖入到編輯器中呢?

    # re: 能夠拖動的矩形  回復  更多評論   

    2007-03-13 15:58 by 匿名
    根本允許起來后看不到矩形啊

    # re: 能夠拖動的矩形  回復  更多評論   

    2007-03-13 17:16 by Dart
    先確認,你用的Eclipse和GEF是什么版本的,這篇文章寫得比較老了,Eclipse版本應該是3.0.1,GEF版本也應該是對應當時Eclipse版本的.
    代碼應該不會有問題,因為在這篇文章還沒有丟失之前很多人都已經用過了

    # re: 能夠拖動的矩形  回復  更多評論   

    2007-03-13 17:33 by 匿名
    在3.2上面能運行起來嘛,第五篇的代碼可以運行,但第二章的運行了沒有看不到矩形.

    # re: 能夠拖動的矩形  回復  更多評論   

    2007-03-14 13:01 by Dart
    3.2可能跑不起來,我沒試過

    # re: 能夠拖動的矩形  回復  更多評論   

    2007-04-06 12:54 by xx
    看不到矩形是因為沒有設置矩形大小,默認的大小為0,0,看不到而已
    主站蜘蛛池模板: 久久精品国产亚洲综合色| 亚洲日韩精品无码专区网址 | 国产亚洲美日韩AV中文字幕无码成人 | 亚洲a∨国产av综合av下载| 成全视频免费高清| 国产精品亚洲专区在线观看| 一个人在线观看视频免费| 7777久久亚洲中文字幕| 日本特黄特黄刺激大片免费| 羞羞视频免费网站入口| 亚洲国产人成精品| 在线观看免费无码视频| 亚洲邪恶天堂影院在线观看| 69国产精品视频免费| 亚洲色大成网站WWW国产| 波多野结衣视频在线免费观看| 免费无码国产V片在线观看| 亚洲精品自产拍在线观看| 999久久久免费精品播放| 日韩亚洲产在线观看| 国产一区二区三区在线免费观看| 一级毛片不卡免费看老司机| 国产亚洲精品岁国产微拍精品| 亚洲电影免费在线观看| 国产亚洲精品成人AA片| 国产乱子伦精品免费无码专区 | 黄页网址大全免费观看12网站| 亚洲毛片av日韩av无码| 99久热只有精品视频免费看| 亚洲一区二区三区成人网站| 国产黄色一级毛片亚洲黄片大全 | 日韩欧美亚洲中文乱码| 久久精品国产亚洲Aⅴ蜜臀色欲| 91热久久免费精品99| 亚洲av色香蕉一区二区三区蜜桃| 亚洲最大激情中文字幕| www.黄色免费网站| 美景之屋4在线未删减免费 | 四虎在线免费视频| 无码的免费不卡毛片视频| 亚洲精品永久www忘忧草|