JAVA 그래픽 Draw2d Intro

2015.07.29 21:49

졸리운_곰 조회 수:338

 

Draw2d Intro

Draw2d Intro

practical introduction to eclipse draw2d project.

eclipse, draw2d, graphics, java, 2d, 2d graphics

  1. Draw2d Intro
    1. Draw2D Description
    2. Draw2 installation
  2. Draw2d Project
    1. Sample Draw2d Java Application
    2. Drawing Draw2d simple figures
    3. Connection
  3. Draw2D Advanced
    1. Draw2D Events
    2. Draw2D Class Figure
    3. Draw2D Connection Decoration
  4. Source Code
  5. References and Further readings

Draw2D Description

Draw2D is a layout and rendering toolkit built on top of SWT. It may be used standalone (outside Eclipse) or in combination with the GEF or Zest component.

Draw2D is a ligheweight toolkit, for displayng graphical components on SWT canvas. Lightweight means that each graphical component, called figure is a simple java object and has no corresponding resource in the Operating System.

Draw2 installation

To use Draw2D you need to install the GEF framework into Eclipse.
From menu, select Help > Install new Software.
in the wizard select the update site1; type gef sdk into the search box, select Eclipse GEF SDK, and complete the installation, that requires a restart.

1 in my case Update Site is Juno- http://download.eclipse.org/releases/juno.

b01.install-new-software-GEF-SDK_M.png

 

Draw2d Project

The full Eclipse RCP framework is not needed to use Draw2D, so you can create a simple Java Application, in eclipse, and include: org.eclipse.draw2d, org.eclipse.swt and org.eclipse.swt.win32.win32.x86 jars, taken from ECLIPSE_HOME/plugins folder.

b02.draw2d-libraries-added-to-the-build-path.png

 

Note The minor number depends on the Eclipse version running

Alternatively you can create an elcipse plug-in project; and add the dependency to org.eclipse.draw2d

b03.draw2d-dependencies-eclipse-plugin_M.png

 

Sample Draw2d Java Application

With SWT and Draw2d libraries added to your build path you can build a very simple application window, containing theskeleton for ant Draw2D development.

We build a class with three methods:

  • main(..) the static application entry point
  • open() the method that instantiate the graphical window
  • buildDiagram(..) the method that draw the graphical content

Look at the code

/** class for testing SWT with Draw2d */
public class MainView {
   
  /** Application entry point */
  public static void main(String[] args) {
    new MainView().open();
  }
   
  /** Open a Shell call a method for drawing */
  public void open(){
    Shell shell = new Shell(new Display());
    shell.setSize(400, 250);
    shell.setText("My Main View");
    shell.setLayout( new GridLayout() );
     
    // build diagram
    Canvas canvas = buildDiagram( shell );
    canvas.setLayoutData(new GridData(GridData.FILL_BOTH));
     
    Display display = shell.getDisplay();
    // open and wait until closing
    shell.open();
    while( !shell.isDisposed() )
      while( !display.readAndDispatch() )
        display.sleep();
  }
   
  /** Instantiate the root figure, where we draw figures*/
  private Canvas buildDiagram( Composite parent ){
     
    // instantiate root figure
    Figure root = new Figure();
    root.setFont(parent.getFont());
    root.setLayoutManager( new XYLayout() );
     
    // insantiate a canvas on which to draw
    Canvas canvas = new Canvas(parent, SWT.DOUBLE_BUFFERED);
    canvas.setBackground(ColorConstants.white);
    LightweightSystem lws = new LightweightSystem(canvas);
    lws.setContents(root);
     
    //
    return canvas;
  }
 
}

As you can see buildDiagram(..) draws nothing, for the moment. If you launch the main(..) you will see an empty window, build on top of SWT which contains an invisible Draw2D root figure

b04.my-main-view-00.png

 

Drawing Draw2d simple figures

Now is time to put graphics on the window. My scope is to draw some blocks on on top of the SWT window.

To start I need a method that Build a Figure, containing a label.

/** specific method to draw a block figure */
public Figure myBlockFigure(String name){
  RectangleFigure f = new RectangleFigure();
  f.setBackgroundColor(ColorConstants.lightGreen);
  f.setLayoutManager( new ToolbarLayout() );
  f.setPreferredSize( 100, 100 );
  f.add( new Label( name ) );
  return f;
}

The code instantiate a RectangleFigure, with a lightGreen background, that contains a Label..

Now, to draw the Figure on our window, we add an hook: a _method call at the end of buildDiagram(..)

private Canvas buildDiagram( Composite parent ){
  // .. previous code remains above
  // this code for drawing
  draw( root );
  //
  return canvas;
}

Then we add the code to Draw two figures on the root Figure. Basically we draw twice the save figure, with different labels, in different points.

/** This method draws figures on the root */
private void draw(Figure root ) {
  Figure first= myBlockFigure("First");
  root.add(first,
    new Rectangle( new Point(10, 10), 
      first.getPreferredSize() ) );
   
  Figure second= myBlockFigure("Second");
  root.add(second,
    new Rectangle( new Point(200, 100), 
      second.getPreferredSize() ) );
}

Launching again the Application we can see two blocks inside our window.

b05.my-main-view-01-two-blocks.png

 

Connection

Now we connect the two figures, by using a specialized IFigure called Connection. Simply, this figure draws a line between two points of a canvas, connecting two figures. There are different types of connections, but now we need a simple PolylineConnection connecting figures with ChopboxAnchors.
To make a connection we add a myConnection(..) method to our class

/** return a connection figure with chopbox between two figures */
public Connection myConnection(IFigure fig1, IFigure fig2){
  PolylineConnection conn = new PolylineConnection();
  conn.setSourceAnchor( new ChopboxAnchor( fig1 ) );
  conn.setTargetAnchor( new ChopboxAnchor( fig2 ) );
  return conn;
}

To complete the test we need to add the connection to our root figure; so we add a line of code at the end of our draw(..) method

private void draw(Figure root, XYLayout layout) {
  // .. previous code here 
  root.add( myConnection( first, second ) );
}

Now, we can test the application by launching again the main(..). The result id visible in the figure below

b06.my-main-view-02-two-blocks-connected.png

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

 

At this point we have seen basics of Draw2D: Canvas, Figures and Connection.

 

Draw2D Advanced

Now we proceed with examples on advanced topics of Draw2D, with Events and Complex Figures.

Draw2D Events

We would like to move figure on the canvas, reacting to user’s drag. For this we need a Draw2D event listener, that intercepts user events: Mouse Click, Mouse Move and Mouse Release.

To to this, we need a class implementing MouseListener and MouseMotionListener interfaces.

/** This Listener implements drag and drop for Draw2D Figure */
public class MyListener
  implements MouseListener, MouseMotionListener{
   
  Figure figure;
  Point location;
   
  /** constructor save reference to figure, then add listeners */
  public MyListener(Figure figure) {
    this.figure = figure;
    figure.addMouseListener(this);
    figure.addMouseMotionListener(this);
  }
   
  @Override
  public void mousePressed(MouseEvent me) {
    location = me.getLocation();
    me.consume();
  }
   
  @Override
  public void mouseDragged(MouseEvent me) {
    Point newLocation = me.getLocation();
    if( location==null || newLocation == null)
      return;
    // calculate offset wrt last location
    Dimension offset = newLocation.getDifference( location );
    if( offset.width==0 && offset.height==0 )
      return;
    // exchange location
    location = newLocation;
     
    // old Bounds are dirty
    figure.getUpdateManager()
      .addDirtyRegion(figure.getParent(), figure.getBounds());
     
    // translate figure 
    figure.translate( offset.width, offset.height );
     
    // new Bounds are dirty
    figure.getUpdateManager()
      .addDirtyRegion( figure.getParent(), figure.getBounds() );
     
    // new Bounds: set parent constraint
    figure.getParent().getLayoutManager()
      .setConstraint(figure, figure.getBounds() );
    //
    me.consume();
  }
   
  @Override
  public void mouseReleased(MouseEvent me) {
    if( location==null )
      return;
    location = null;
    me.consume();
  }
 
  @Override
  public void mouseEntered(MouseEvent me) {}
 
  @Override
  public void mouseExited(MouseEvent me) {}
 
  @Override
  public void mouseHover(MouseEvent me) {}
 
  @Override
  public void mouseMoved(MouseEvent me) {}
 
  @Override
  public void mouseDoubleClicked(MouseEvent me) {}
 
}

Looking at the code we note

  • MyListener(.) constructor save a reference to the figure, then adds listeners
  • mousePressed(.) method store the location at the first click on the Figure, then consume the event.
  • mouseDragged(.) method calculate the difference from last movement, translate the figure, and make the repaint happens, by marking dirty the old regon, the new region and notifyng the parent layout manager.
  • mouseReleased(.) method set to null the location and consumes the event.

Finally we need to hook the listener to figure creation. It’s really simple, we need only to put one line on the myBlockFigure(.) method, so that each built figure has its own mouse listener.

public Figure myBlockFigure(String name){
  // .. previous code here
  new MyListener( f );
  return f;
}

Now, launching the application again we see the same two blocks. By dragging them, we see blocks moving, together with connection. Try yourself to see the Drag And Drop

b07.my-main-view-03-two-blocks-moved_M.png

 

Draw2D Class Figure

Now we want to transform our simple block figure into one more complex figure, similar to a class of a class diagram. Our class needs:

  • an icon near its name
  • a compartment for fiends
  • a compartment for methods

So we change our code, by adding a new method that builds the class figure. If you give a look at the conde you can see that is similar to previous myBlockFigure(.), except for few details.

/** this method build a Class image figure */
public Figure myClassFigure(String name, String[] fields, String[] methods) {
  RectangleFigure f = new RectangleFigure();
  f.setBackgroundColor(ColorConstants.lightGray);
  f.setLayoutManager(new ToolbarLayout());
  f.setPreferredSize(150, 110);
  //
  f.add( new Label( name, getImage("resources/img/class_obj.gif") ) );
  f.add(myListLabel(fields));
  f.add(myListLabel(methods));
  //
  new MyListener(f);
  return f;
}

Note we inserted into the project a resource/img folder that contains the class_obj.gif file.

Our method calls two helper methods; one that builds an Image given a path relative to the user dir.

/** build an image starting from relative path wrt user directory */
private static Image getImage(String path) {
  File f = new File(System.getProperty("user.dir"), path );
  return new Image( Display.getCurrent(), f.getAbsolutePath() );
}

And one that build a big label with a top line and a list of elements displayed.

/** builds a label with a list of strings */
public Label myListLabel(String[] list) {
  String text = "";
  for (String s : list) {
    text += s + "\n";
  }
  Label label = new Label(text) {
    protected void paintBorder(Graphics g) {
      Rectangle r = getBounds();
      /** paints horizontal line on top of label */
      g.drawLine(r.x, r.y, r.x + r.width, r.y);
    };
    public Insets getInsets() {
      // top, left, bottom, right
      return new Insets(5, 0, 0, 0);
    }
  };
  return label;
}

Finally we change the code into the draw(.) method, so that it can draw our class figures.

/** This method draws figures on the root */
private void draw(Figure root) {
  Figure first = myClassFigure("First",
      new String[] { "- name:String" },
      new String[] { "+ First(String)",
        "+ getName():String",
        "+ setName(String)" });
  root.add(first,
      new Rectangle(new Point(10, 10), first.getPreferredSize()));
 
  Figure second = myClassFigure("Second",
      new String[]{"- email: String"},
      new String[]{"+ getEmail():String",
        "+ setEmail(String)"}
  );
  root.add(second,
      new Rectangle(new Point(200, 100), second.getPreferredSize()));
 
  root.add(myConnection(first, second));
}

Now the diagram looks like a class diagram. See the following image

b08.my-main-view-05-two-blocks-class.png

 

Draw2D Connection Decoration

At this point we need only to decorate connections.

First we add a decoration that looks like a containment, with the following code

/** cerate a poligon decoration that looks like a containment */
public PolygonDecoration myPolygonDecoration(){
  PolygonDecoration deco = new PolygonDecoration();
  PointList pl = new PointList();
  pl.addPoint( 0, 0 );
  pl.addPoint(-2, 2);
  pl.addPoint(-4, 0);
  pl.addPoint(-2,-2);
  deco.setTemplate( pl );
  return deco;
}

Then we add a label representing multiplicity, attached to target endpoint, withh following code

/** adds a multiplicity label linked to targte endpoint */
public void addMultiplicity(PolylineConnection c){
  ConnectionEndpointLocator targetEL = new ConnectionEndpointLocator(c, true);
  targetEL.setVDistance(10);
  Label multiplicity = new Label("1..*");
  c.add(multiplicity, targetEL);
}

Finally we join the code, by changing the myConnection(..) method, as follows

/** return a connection figure with chopbox between two figures */
public Connection myConnection(IFigure fig1, IFigure fig2) {
  PolylineConnection conn = new PolylineConnection();
  conn.setSourceAnchor(new ChopboxAnchor(fig1));
  conn.setTargetAnchor(new ChopboxAnchor(fig2));
  conn.setSourceDecoration( myPolygonDecoration() );
  addMultiplicity(conn);
  return conn;
}

The result looks like the following image.

b09.my-main-view-06-two-class-with-containment.png

 

Source Code

You can download the source code of the example

Notes

  • The zipped archive (3MB) contain a project together with dependencies.

References and Further readings

 

 

[출처] http://www.ingegno.it/programming/eclipse/eclipse-draw2d/

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED