大夢(mèng)想家

          5年開(kāi)發(fā)工程師,2年實(shí)施經(jīng)理,X年售前顧問(wèn),......
          數(shù)據(jù)加載中……
          SWT/JFace一些經(jīng)典技術(shù)與算法

          1。圖形拖動(dòng)

          圖形的拖動(dòng)就是圖形選中的圖形跟著鼠標(biāo)的移動(dòng)而不斷的相應(yīng)改變位置,這是在圖形界面中是經(jīng)常見(jiàn)的一個(gè)操作,但是在SWT/JFace中來(lái)實(shí)現(xiàn)卻不是意見(jiàn)容易的事。在這里底板是一個(gè)Canvas,圖形也是建立在一個(gè)Canvas上,當(dāng)然位置的改變是建立在鼠標(biāo)移動(dòng)的監(jiān)聽(tīng)下.

          1、首先建立幾個(gè)變量:

          Int oldx = -1;// 拖動(dòng)前的x

          Int oldy = -1;//拖動(dòng)前的y

          Int xoffset = 0; //拖動(dòng)后的偏移量x

          Int yoffset =0 ;// 拖動(dòng)后的偏移量y;

          Int x,y;// 拖動(dòng)后圖形應(yīng)該在的位置

          2、 在第一次拖動(dòng)時(shí),取得oldx和oldy

          if(oldX==-1&&oldY==-1){

          oldX=e.x;

          oldY=e.y;

          }

          3、 獲得偏移量

          xoffset=e.x-oldX;

          yoffset=e.y-oldY;

          4、得到新的圖形位置

          x=ca.getBounds().x+xoffset;

          y=ca.getBounds().y+yoffset;

          5、 重新設(shè)置圖形的位置

          ca.setBounds(x,y,ca.getSize.x,ca.getSize.y)

             這樣就實(shí)現(xiàn)了圖形的拖動(dòng),不僅算法簡(jiǎn)潔,而且效果也很好。當(dāng)然為了更好的效果,還可以加上邊界控制,以保證圖形不超出邊界

          2。圖形連線與畫(huà)線

          2.1 圖形的連線

          整個(gè)SWT中只有一個(gè)類GC與之有關(guān),就是在一個(gè)畫(huà)板上畫(huà)線,這樣簡(jiǎn)單的線根本無(wú)法滿足復(fù)雜連線的要求,要實(shí)現(xiàn)比較復(fù)雜的圖形間的連線,我們使用了eclipse的另一個(gè)插件——draw2D,在draw2D的圖形中比較容易實(shí)現(xiàn)連線,但是draw2D中連線的圖形都是IFigure類的圖形,否則就無(wú)法實(shí)現(xiàn)draw2D內(nèi)的連線,然而我們的圖形使用SWT設(shè)計(jì)的,因此出現(xiàn)了兩者的兼容問(wèn)題。因此我們自行設(shè)計(jì)了綜合使用兩者來(lái)實(shí)現(xiàn)圖形連線的方案,就是圖形是用SWT設(shè)計(jì)的,而線是用draw2D來(lái)設(shè)計(jì)的。這樣設(shè)計(jì)表面看起來(lái)能夠達(dá)到draw2D的兩線的完美效果,而又不改變我們需要是用的SWT設(shè)計(jì)的圖形。

          1、 連線的簡(jiǎn)化流程

          獲得起始圖形,計(jì)算出連線的起點(diǎn)

          獲得指向圖形,計(jì)算出連線的終點(diǎn)

          根據(jù)起點(diǎn)和終點(diǎn)來(lái)建立連線

          2、 解決Canvas與Panel之間的兼容問(wèn)題

          因?yàn)槲覀兊慕⒃谝粋€(gè)畫(huà)布(Canvas)上的,而連線則要建立在一個(gè)(Panel)上。因此我們要將兩者聯(lián)系起來(lái),才能實(shí)現(xiàn)圖形間的連線。這里需要用到輕量級(jí)系統(tǒng)(LightweightSystem)

          lws=new LightweightSystem(editPlace);

          圖形所在的面板

          然后就可以新建Panel,并將他設(shè)為輕量級(jí)系統(tǒng)的內(nèi)容

          panel=new Figure();

          lws.setContents(panel);

          這樣我們就可以在panel上添加我們的連線了

          2.2 在面板上畫(huà)曲線

          1、 這個(gè)曲線也同樣要建立在Panel之上,因此也要像上面一樣建立Panle,這里不再重復(fù)

          2、要?jiǎng)?chuàng)建曲線則要用到PolylineConnection(),我們先創(chuàng)建一個(gè)PolylineConnection的對(duì)象pc.

          3、 如果要顯示箭頭,則可以給pc添加修飾,

          p2.setTargetDecoration(new PolygonDecoration());

          4、接下來(lái)就是設(shè)置pc上的關(guān)鍵點(diǎn),包括起點(diǎn),終點(diǎn),拐點(diǎn)。確定這些點(diǎn)后,從起點(diǎn)到終點(diǎn)依次排列即可

          p2.setPoints(new PointList(new int[]{p1, p2,p3,…}));

          5、 這樣就可以建立了曲線,不過(guò)線上的個(gè)關(guān)鍵點(diǎn)的確定是一個(gè)難點(diǎn),根據(jù)不同的情況會(huì)有不同的確定方法,這里不能一一列出了

          3。圖像常用處理與Canvas

          3.1 如何在Canvas上添加圖像

          要在一個(gè)畫(huà)布Canvas上添加,需要注冊(cè)畫(huà)布的畫(huà)圖事件,代碼如下:

          canvas.addPainListener(new PaintListener(){

          public void paintControl(PaintEvent e){

          e.gc.drawImage(image,10,10);

          }

          }

          3.2 圖像的創(chuàng)建

          1. Image(display, “eclipse.gif”)

          2. Image (display , “eclipse.gif”,SWT.IMAGE_FRAY)

          3. ImageData data = new ImageData(“eclipse.gif);

          Image image = new Image(display, data)

          3.3 圖像的放大或縮小

             通過(guò)ImageData的scaledTo可意見(jiàn)圖像放大或縮小,在這里是新建另一個(gè)圖像,而不是直接改變?cè)瓉?lái)的圖像。

          ImageData data = image.getImageData();

          ImageDate newData = data.scaledTo(newWidth,newHeight);

          Image newImage = new Image(display, newData);

          3.4 圖像的保存

          因?yàn)橐粋€(gè)動(dòng)態(tài)的圖片可能有多個(gè)圖片組成,所以用數(shù)組

          4文件的過(guò)濾

          這里所說(shuō)的文件的過(guò)濾不是上面說(shuō)的文件對(duì)話框中的文件的過(guò)濾,在這里我們?cè)O(shè)置了一個(gè)樹(shù),讓它來(lái)顯示工程下已有的文件,在這里我們只希望看到(.grh)的文件,因此需要給它設(shè)置過(guò)濾器。先來(lái)看看我們?cè)趺磳?shí)現(xiàn)顯示文件的;

          在這里使用的是TreeViewer,TreeViewer的構(gòu)建步驟如下:

          1、 創(chuàng)建新對(duì)象,例如TreeViewer tv=new TreeViewer(fileComposite,SWT.NONE);

          2、 設(shè)置內(nèi)容管理器,如tv.setContentProvider( new FileTreeContentProvider());

          3、設(shè)置標(biāo)簽提供器,如tv.setLabelProvider(new FileTreeLabelProvider());

          4、設(shè)定TreeViewer的輸入數(shù)據(jù),如tv.setInput(new File("e:\"));

          其中FileTreeContentProvide,F(xiàn)ileTreeLabelProvider分別是implements了ItreeContentProvider和ILabelProvider兩個(gè)接口的。

          FileTreeContentProvide中有幾個(gè)重要的方法。

          ① getElements();"public Object[] getElements(Object inputElement)",當(dāng)程序開(kāi)始構(gòu)建樹(shù)時(shí),首先調(diào)用它返回一個(gè)數(shù)組,此數(shù)組對(duì)象表示樹(shù)的根節(jié)點(diǎn),

          ② hasChildren();"public boolean hasChildren(Object element)",當(dāng)TreeViewer顯示一個(gè)節(jié)點(diǎn)(element)后會(huì)調(diào)用該函數(shù)判斷當(dāng)前節(jié)點(diǎn)是否有子節(jié)點(diǎn),若有則顯示“+”;

          ③ getChildren();"public Object[] getChildren(Object parentElement)",當(dāng)用戶選擇節(jié)點(diǎn)打開(kāi)子節(jié)點(diǎn)時(shí),會(huì)調(diào)用此函數(shù)返回下一層子節(jié)點(diǎn),parentElement參數(shù)為選擇的節(jié)點(diǎn);

          ④ getparent();"public Object getParent(Object element)"

          還有幾個(gè)方法就不在此敘述,

          在程序里不需要顯示根目錄的位置,只要顯示在工程目錄下有用的文件,在getElements()方法中,我們返回getChildren()中的值,這樣,我們就可以不得到輸入的路徑這個(gè)根節(jié)點(diǎn),而把該路徑下的符合條件的文件作為根節(jié)點(diǎn);

          public Object[] getElements(Object element) {

          return getChildren(element);

          }

          在getChildren方法中,我們通過(guò)一個(gè)數(shù)組列出給定路徑下的文件,然后通過(guò)一個(gè)ArrayList來(lái)存儲(chǔ)符合條件的文件對(duì)象:

          Object[] kids = ((File) element).listFiles();

          ArrayList<Object> outs = new ArrayList<Object>();

          當(dāng)kids不是空的時(shí)候,我們就看kids中的文件后綴是不是符合我們的要求,如果是,就添加到outs中

          for(int i = 0;i<kids.length;i++){

          if(((File)kids[i]).getName().endsWith(".wsdl")||

          ((File)kids[i]).getName().endsWith(".bpel")||

          ((File)kids[i]).getName().endsWith(".grh")){

          int j = 0;

          outs.add(j,kids[i]);

          j++;

          }

          }

          現(xiàn)在我們已經(jīng)得到了我們需要得到的所有的對(duì)象,因?yàn)檫@個(gè)函數(shù)的返回值是個(gè)數(shù)組,再把outs中的元素復(fù)制到一個(gè)數(shù)組中即可;

          f(outs.size()!=0){

          Object[] out = new Object[outs.size()];

          for(int i= 0;i<outs.size();i++){

          out[i] = outs.get(i);

          }

          return out;

          }

          5。關(guān)于序列化保存

          1) 關(guān)于保存

          序列化的問(wèn)題是由保存引起的,要保存一個(gè)對(duì)象就必須為相關(guān)的類實(shí)現(xiàn)序列化,這本沒(méi)有什么問(wèn)題,只需要把相關(guān)的類繼承并實(shí)現(xiàn)Serializable接口就可以了,但是,在工程里用到了一些類。例如org.eclipse.swt.widgets.graphics.Image這個(gè)類,它是一個(gè)final類,不可以被繼承,但是他是節(jié)點(diǎn)的一部分,必須要顯示出來(lái);我們可以把它作為一個(gè)參數(shù)傳到節(jié)點(diǎn)的setNodeLocation函數(shù)中,它是初始化節(jié)點(diǎn)時(shí)負(fù)責(zé)顯示的函數(shù)。每創(chuàng)建一個(gè)新的節(jié)點(diǎn)時(shí)就需要先創(chuàng)建一個(gè)Image實(shí)例。

          2) 關(guān)于恢復(fù)

          保存成功了還需要恢復(fù)圖像,恢復(fù)圖像是個(gè)比較復(fù)雜的過(guò)程,我們要保證圖像的位置和數(shù)據(jù)等許多東西保持不變;首先找到開(kāi)始節(jié)點(diǎn),從開(kāi)始節(jié)點(diǎn)開(kāi)始逐個(gè)恢復(fù),如沒(méi)有開(kāi)始節(jié)點(diǎn),那么這個(gè)圖是不完整的,就沒(méi)有辦法完整的恢復(fù)它;恢復(fù)時(shí),不能用原來(lái)的對(duì)象,因?yàn)樵械膶?duì)象都已經(jīng)被dispose();了,并且不可以用到任何有關(guān)顯示的方法,否則就會(huì)出現(xiàn)促發(fā)異常;所以要得到節(jié)點(diǎn)的大小和位置就要另想辦法;

          為了得到node原來(lái)的位置,在node中設(shè)置了一個(gè)point變量來(lái)記載node的位置,并在node的位置更改后更改point的值,這樣就可以得到node原來(lái)的位置;同理,我們可以得到保存時(shí)node的大小了;

          我們可以從保存的圖中找到與開(kāi)始節(jié)點(diǎn)相關(guān)聯(lián)的下一個(gè)節(jié)點(diǎn),回復(fù)這個(gè)節(jié)點(diǎn)后再找下一個(gè)節(jié)點(diǎn),這樣可以通過(guò)一個(gè)循環(huán)一直找到結(jié)束節(jié)點(diǎn),并把這些節(jié)點(diǎn)加到一個(gè)新建的graph中,然后把相關(guān)的信息都通過(guò)已有的set和get方法添加的節(jié)點(diǎn)中去,這樣,整個(gè)圖的所有的節(jié)點(diǎn)都恢復(fù)出了;

          因?yàn)槊總€(gè)節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)有不同的可能,用一個(gè)if else組合來(lái)判斷到底是哪一個(gè)節(jié)點(diǎn),然后不同的節(jié)點(diǎn)有不同的代碼;簡(jiǎn)單的節(jié)點(diǎn)如taskNode的恢復(fù)比較簡(jiǎn)單,基本的過(guò)程和創(chuàng)建一個(gè)新的節(jié)點(diǎn)相同,只是注意把原節(jié)點(diǎn)的信息傳遞給新的節(jié)點(diǎn)即可。
             具體的過(guò)程可以簡(jiǎn)化為

          獲得要復(fù)制的節(jié)點(diǎn)的引用

          點(diǎn)擊粘貼,新建一個(gè)與要復(fù)制節(jié)點(diǎn)類型相同的節(jié)點(diǎn)

          把要復(fù)制節(jié)點(diǎn)的信息傳遞到新的節(jié)點(diǎn)中去

          判斷節(jié)點(diǎn)是不是容器節(jié)點(diǎn),是繼續(xù),不是結(jié)束

          新建容器節(jié)點(diǎn)中的子節(jié)點(diǎn),給子節(jié)點(diǎn)傳遞信息

          以下是粘貼后初始化一個(gè)工作節(jié)點(diǎn)的例子;

          wfNode = new TaskNode(node.getName(), gra, web);

          wfNode.setId(node.getId());

          wfNode.setNodeInView(c, workspace.getPanel(), attr,workspace,web); BaseWFNodeText.setCanvasText(wfNode);

          wfNode.setNodeLocation(node.getPoint().x, node.getPoint().y, image1);

          gra.addNode(wfNode);

          若下一個(gè)節(jié)點(diǎn)是復(fù)雜節(jié)點(diǎn),首先恢復(fù)復(fù)雜節(jié)點(diǎn)本身,然后判斷該節(jié)點(diǎn)是否有子節(jié)點(diǎn),若存在子節(jié)點(diǎn),則依次恢復(fù)其子節(jié)點(diǎn),通過(guò)一個(gè)foreach循環(huán)就可以把所有的子節(jié)點(diǎn)恢復(fù);注意的是每個(gè)父節(jié)點(diǎn)的子節(jié)點(diǎn)形式可能不同,而且他們需要傳遞的信息也不完全相同。部分代碼如下

          wfNode.getCanvas().setSize(node.getSize());

          //設(shè)置節(jié)點(diǎn)的大小

          wfNode.setSize(node.getSize().x, node.getSize().y);

          //記錄節(jié)點(diǎn)的大小

          gra.addNode(wfNode);

          節(jié)點(diǎn)的信息如下

          wfNode.setBpelOperation(node.getBpelOperation());

          wfNode.setSuppressJionFaliare(node.getSuppressJionFaliare());

          wfNode.setJionCondition(node.isJionCondition());

          wfNode.setOporation(node.getOporation());

          wfNode.setLink(node.getLink());

          //以上為所有節(jié)點(diǎn)都有的屬性

          wfNode.setCondition(node.getCondition());

          //FlowNode和WhileNode有的屬性

          wfNode.setCaseCondiction(node.getCaseCondiction());

          //FlowNodeµÄ×Ó½ÚµãÓеÄÊôÐÔ

          childNode.setFromPart(element.getFromPart());

          childNode.setFromVar(element.getFromVar());

          childNode.setToPart(element.getToPart());

          childNode.setToVar(element.getToVar());

          //以上四個(gè)是copy有的節(jié)點(diǎn)

          6。圖形的復(fù)制與粘貼

          1) 為各個(gè)節(jié)點(diǎn)以及底層面板創(chuàng)建菜單項(xiàng),包括復(fù)制,粘貼,刪除;在工具欄以及菜單欄創(chuàng)建相應(yīng)的項(xiàng);

          2) 關(guān)于復(fù)制

          復(fù)制的方法比較簡(jiǎn)單,就是把一個(gè)新的變量指向要復(fù)制的對(duì)象,然后把這個(gè)變量通過(guò)get方法,讓外界可以獲得它;

          public void copy(BaseWFNode node){

          midNode = node;

          }

          3) 關(guān)于粘貼

          粘貼的過(guò)程是創(chuàng)建一個(gè)新的節(jié)點(diǎn),他所攜帶的信息和復(fù)制的節(jié)點(diǎn)相同

          1、 獲得要粘貼節(jié)點(diǎn)的引用;判斷是否為空,是就繼續(xù),否則就什么也不做;

          2、 構(gòu)建一個(gè)新的節(jié)點(diǎn),確定節(jié)點(diǎn)的id,位置等于聲稱代碼無(wú)關(guān)的信息;

          3、 判斷節(jié)點(diǎn)具體是哪一種節(jié)點(diǎn),并把原節(jié)點(diǎn)的信息賦給新的節(jié)點(diǎn);

          4、 Gragh中添加這個(gè)節(jié)點(diǎn);

          5、 根據(jù)第三步,若這個(gè)節(jié)點(diǎn)是某個(gè)復(fù)雜節(jié)點(diǎn),就把它的子節(jié)點(diǎn)也構(gòu)建出來(lái),并賦予相應(yīng)的信息;實(shí)現(xiàn)的過(guò)程和恢復(fù)圖形類似;

          4) 工具欄復(fù)制的實(shí)現(xiàn)

          1、 這里添加監(jiān)聽(tīng)的時(shí)候用了一個(gè)標(biāo)記,當(dāng)雙擊一個(gè)節(jié)點(diǎn)的時(shí)候,就記錄這個(gè)標(biāo)記為1,然后讓一個(gè)中間的變量指向這個(gè)節(jié)點(diǎn),

          public void mouseDoubleClick(MouseEvent e){

          WSCAttribute.showWind(work, node);

          deleteFlag = 1;//當(dāng)點(diǎn)擊其他地方時(shí)設(shè)為0;

          preDelNode = node;

          }

          2、點(diǎn)擊復(fù)制的時(shí)候判斷標(biāo)記是否為1,判斷PreDelNode是不是空,不是就根據(jù)上面說(shuō)的復(fù)制來(lái)執(zhí)行;刪除節(jié)點(diǎn)也是用這個(gè)思想;

          3、 點(diǎn)擊粘貼,判斷中間節(jié)點(diǎn)是否時(shí)空,不是就在底層面板的起始處將節(jié)點(diǎn)復(fù)制下來(lái);否則就什么也不做;



          客戶虐我千百遍,我待客戶如初戀!

          posted on 2007-12-25 14:21 阿南 閱讀(1262) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 老河口市| 青岛市| 彭水| 开阳县| 蒙阴县| 灌云县| 邛崃市| 固始县| 禄丰县| 曲沃县| 弥勒县| 怀远县| 光山县| 龙山县| 富阳市| 临汾市| 健康| 遵义县| 邛崃市| 长顺县| 芦山县| 镇原县| 公安县| 万荣县| 达拉特旗| 察隅县| 六安市| 策勒县| 杭锦后旗| 乌拉特前旗| 阿克陶县| 衡阳市| 通道| 上犹县| 青川县| 青浦区| 苍山县| 宁陵县| 赫章县| 三原县| 营口市|