Java Drawing DrawTop

Language

JP  US  UK

 

Creating shape

 H. Jyounishi, Tokyo Japan
 

Frame (Index), No frame                 version:0.3(latest)  

Class on this page: CreateShapeLS, DiscreteAngledLine

1. Overview
1.1 Summary of the control flow

The type of a shape to be created is specified by clicking the button on the tool bar, then the type is transferred to the CreateShapeLS object via ExecCommand (command dispatcher) object. The CreateShapeLS receives the mouse motion by the methods defined by the MouseListener and MouseMotionListener interfaces, and it sends the mouse motion to the ShapeElement subclass to create the specified shape.

See=> Control flow of creating a shape


Auto shape buttons on the toolbar

1.2 Operation
=> User's guide Creating a shape

(1) Basic shape (Rectangle, RoundRectangle, Ellipse and so on)

Click the button on the tool bar and drag with the mouse over the canvas, then a basic shape will be created to fit the dragged rectangle. If you click on the canvas, instead of dragging, then a small basic shape will be created around the clicked point.


Figure 1. Creating a basic shape

(2) Line (and arrow line)
Click the line or arrow line button on the tool bar and drag with the mouse over the canvas, then a line will be created. The two end points of the line are corresponding to drag start point and end point. If you click on the canvas, instead of dragging, then a short diagonal line will be created at the clicked point.


Figure 2. Creating lines

(3) Polyline (or Polygonal line) and cubic curve
A polyline and a piecewise cubic curve are created in a similar way. Both shapes are defined by the sequence of points.

①Click on the button on the tool bar and click on the canvas to specify the start point.
②Move the mouse on the canvas, then the line segment connecting the clicked point and the current mouse position will be displayed (See the figure in mouseMoved method). If the mouse position seems good, click the mouse to specify the next point.
③Repeat ②.
④To finish creating and specify the last point, click the right button of the mouse or double-click.

: Figure3 shows polylines and cubic curves created in this way. These shapes haven't good shape, however we can modify the shapes easily by "modify shape" command described later (See=> Modifying Shape).
: To create a closed polyline (polygon) or closed cubic curve, the last point must be placed close to the start point. When the last point is close enough to the start point, "closed" message appears on the canvas.

Figure3. Creating polylines and cubic curves


(4) Component Library
To create a library shape on the canvas, click on a shape in the Component library dialog and drag with the mouse over the canvas diagonally, then the library shape will be created.
See=> User's guide Component Library

---------------------------------------------
: Ctrl key and Shift key
---------------------------------------------
∙ If a basic shape is created by dragging the mouse with holding down the Shift or Ctrl key, then the basic shape will be forced to be square.
∙ If a line or a polyline is created with holding down the Shift or Ctrl key, then the line will be forced to be horizontal, 45/135 degree or vertical.



Figure4. The shapes created holding down the Shift or Ctrl key

---------------------------------------------------
: " Connector enable" option
---------------------------------------------------


If this option is true (default setting is true) and the mouse is moved to a shape's boundary after clicking a auto shape button, then the connection mark will be displayed on the boundary (Figure(a)). While the connection mark is displayed, press the mouse button and drag the mouse toward other shape's boundary, then you can see the other connection mark on the boundary. If you release the mouse button at this time, then you can get a line connected to the both shape (Figure(b)). This operation can be done in the same way for a polyline (Figure(c)).
You can confirm the connection between the two shapes by pressing the mouse button on a selected shape (Figure(d)). The red marks in Figure(d) show the connection points on the selected shape when it is being moved or resized.


Figure_(a)

Figure_(b)

Figure_(c)

Figure (d)
Figure 5. The "connector enable" option and connection marks


2. CreateShapeLS (LS: listener) return=>page top
2.1 Control flow of creating a shape

The following description is limitted to create a closed basic shape like a rectangle, a round rectangle or an ellipse, however the control flow itself is similar for creating other kind of a shape.

Step

Description

Step1. Start

∙ Click the button on the tool bar that represents the shape to be created.

Step2. Creating a command sequence

∙ The button action (ButtonOfToggleAction) is invoked.
∙ The button action generates a command sequence (command id, command issuing object and parameter) and calls the exec method of the ExecCommand.
Step3. Command
dispatch
∙ The exec method of the ExecCommand dispatches the command according to its command id. And the exec method creates a new CreateShapeLS object and calls its creatingStart method.
Step 4. Registering mouseLisners ∙ The creatingStart method registers the CreateShapeLS object to the ListenerPanel as a MouseListener and MouseMotionListener object.
Remove the SelectionLS object from the ListenerPanel temporarily by the end method of the SelectionLS to avoid malfunction.

: SelectionLS object is a mouse listener for selecting shapes. If the SelectionLS object is active during creating a shape, it may do unnecessary operations, therefore it must be stopped before creating a shape.
Step 5. Creating a shape element ∙ The creatingStart method creates a new object of the ShapeElement subclass according to the command id and set it to the new ShapeContainer object.
∙ Adds the new ShapeContainer object to the ContainerList by the ContainerManager. Hereafter, the updated shape will be displayed on the canvas by calling the repaint method of the DrawPanel.

See => DrawPanel overview
See => The relation of the ShapeElement with the ShapeContainer =>ShapeContainer Figure 1
Step 6. Creating a shape data ∙ When a mouse event (mouse dragging in this case) occurs, then CreateShapeLS object receives the mouse motion by its mousePressed and mouseDragged method and begins sending the dragged rectangle to the ShapeElement subclass.
∙ During the mouse dragging, the mouseDragged method repeatedly sends the dragged rectangle to the create method of the ShapeElement subclass to update the shape data, and it also call the repaint method of the DrawPanel to draw the updated shape on the canvas.
Step 7. Post process ∙ When the mouse button is released, the creating process must be terminated. To do this, the mouseReleased method of the CreateShapeLS calls the creatingEnd method.
∙ The creatingEnd method removes the CreateShapeLS object from ListenerPanel and registers the SelectionLS object to ListenerPanel by the start method of the SelectionLS to restart the selecting process.
The creatingEndmethod also executes the undo setting before it ends.
∙ Generates the command for returning to ExecCommand at the end of this method to report that the creating process finished normally.


2.2 CreateShapeLS API return=>page top
public class CreateShapeLS implements MouseListener, MouseMotionListener

Field

Description

shapeContainer ShapeContainer shapeContainer
The new ShapeContainer object that stores the shape to be created.
The creatingStart method creates a new object of the ShapeContainer and sets it to this field.
shapeElement ShapeElement shapeElement
The ShapeElement object to be created.
commandId int commandId
The command id which is passed from the ExecCommand (see Control flow of creating a shape Step2, 3). The command id also represents the type of a new object of the ShapeElement subclass to be created.
: The command Ids are defined in Command class.
isLineFamily boolean isLineFamily
True if commandId is creating a line/arrowed line/double arrowed line command.
isPolylineFamily boolean isPolylineFamily
True if commandId is creating a polyline/cubic curve command.

isRectangleFamily

boolean isRectangleFamily
True if commandId is creating a basic shape command. Here the basic shape is a rectangle, round rectangle, ellipse/circle or text box.

isComponentFamily

boolean isComponentFamily
True if commandId is creating a library component command.
See =>User's Guide Component Library
Note : isLineFamily, isPolylineFamily, isRectangleFamily, isComponentFamily
These fields are used to make "if then else" statements comprehensible.

startPoint

Point2D startPoint:
The dragging start point. This point can be modified, if the ctrl>0 (Figure 4) or "connector enable" option is true (Figure 5).

endPoint

Point2D endPoint:
The dragging current point or end point. This point can be modified, if the ctrl>0 (Figure 4) or "connector enable" option is true (Figure 5).

oldPoint

Point2D oldPoint:The dragging point when the mouseDragged method was called previously.
Saves the endPoint to this field at the end of the mouseDragged method.

pressedPoint

Point2D pressedPoint

The point when the mouse button is pressed. This point can't be changed.

draggedPoint

Point2D draggedPoint

The point when the mouse is dragged. This point is updated whenever the mouseDragged method is called. This point can't be changed for other reason.

clicked

boolean clicked

The mousePressed method sets false and the mouseClicked method sets true.

rightButtonPressed

boolean rightButtonPressed

True if the mouse right button was pressed.
=> Detection of the double-click or right button click

ctrl

int ctrl
This field is set in the mousePressed, mouseDragged and mouseClicked methods as follows:
ctrl=0: the mouse left button was pressed.
ctrl=1: the mouse button was pressed with holding down the Shift key.
ctrl=2: the mouse button was pressed with holding down the Ctrl key.
ctrl=3: the mouse button was pressed with holding down the Alt key.

See =>Detection of the double-click or right button click
committedNodePoints

Point2D[] committedNodePoints

The array of the committed segment junction points for a polyline and piece-wise cubic curve.

tentativeNodePoints

Point2D[] tentativeNodePoints

The array of the tentative segment junction points for a polyline and piece-wise cubic curve. The last point in the array is tentative and it is changed to a committed point when the mouse is clicked.


Method Description
creatingStart public void creatingStart(int commandId)
Parameter:
commandId - the type of the shape to be created.
Processing:
See =>Control flow Step4
∙ This method registers the CreateShapLS object to ListenerPanel and removes MouseListener and MouseMotionListener objects from ListenerPanel.
∙ This method creates new objects of the ShapeContainer and ShapeElement subclass according to the commandId which accommodates a shape data.
Note : The shape data is created by the create method of the ShapeElement using the data of the mouse drag or the click. The new ShapeContainer object is registered to the ContainerList by the ContainerManager. Hereafter, the updated shape will be displayed on the canvas by calling the repaint method of DrawPanel.

creatingEnd

public void creatingEnd()
This method is called by the mouseReleased method when it creates a basic shape or line. It is also called by the mouseClicked method when it creates a polyline or cubic curve.
∙ Removes the CreateShapeLS object from ListenerPanel.
∙ Executes the undo setting by the methods of ContainerManager.
See =>ContainerManager undo support
∙ Generates the command for returning to ExecCommand at the end of this method.
This command reports to ExecCommand that the creating process finished normally.

abort

public void abort()
This method is called by the ExecCommand to terminate the CreateShapeLS object when a serious error occurs.
=> Serious errors in CreatShapeLS

This method cancels the operations that the creatingStart method has performed. To be more precise, this method removes the CreateShapeLS object from the ListenerPanel, restarts the SelectionLS by calling its start methods and deletes the ShapeContainer object from ContainerList.

mousePressed

public void mousePressed(MouseEvent e)
∙ Stores the dragging start point to the startPoint and pressedPoint fields.

If the startPoint is close to a boundary of other shape, then puts the startPoint on the boundary by using the drawMouseHitPT method (Figure 5 (a)).

∙ Stores the key or the mouse button information to ctrl field.
See =>Detection of the double-click or right button click

mouseDragged

public void mouseDragged(MouseEvent e)
∙ Stores the dragging current point to the endPoint and draggedPoint fields.

If the endPoint is close to a boundary of other shape, then puts the startPoint on the boundary by using the drawMouseHitPT method of the ConnectionLS (Figure 5 (a)).

∙ Stores the key or the mouse button information to the ctrl field.

if the ctrl>0, then moves the endPoint to adequate position (Figure 4).
See=>Ctrl key and Shift key

∙ Calls the create method of the ShapeElement subclass to create the shape data and display it.

If isRectangleFamily is true or isComponentFamily is true, passes the bounding box(rectangle) to the create method as a parameter. The bounding box is a rectangle which is created by using the startPoint and endPoint and to which the creating shape fits.
If isLineFamily is true, passes the startPoint and endPoint to the create method as a parameter.

: This method does nothing, if isPolylineFamily is true. see => mouseClicked

mouseReleased

public void mouseReleased(MouseEvent e)
If the isRectangleFamily,isComponentFamily or isLineFamily is true, then calls creatingEnd method for the post processing.

mouseMoved

public void mouseMoved(MouseEvent e)

∙ Calls the drawMouseHitPT method to display a connection point.

If the current mouse position is close to a boundary of other shape, then displays the connection point on the boundary (Figure 5 (a)).

∙ If isPolylineFamily is true, calls the createNodePoint method.

In the figure below, the p0, p1, p2 and p3 are the points in the committedNodePoints, and the "mouse position" is the current (moving) mouse position. The createNodePoint method merges "mouse position" and the committedNodePoints into the tentativeNodePoints, and calls the create method of the ShapeElement subclass (PolylineElement or CubicCurveElement).

See=>Operation:Polyline (or Polygonal line) and cubic curve
Note : The direction of the last line segment of the polyline is limited to be horizontal, vertical or ±45 degree, if the ctrl field>0.

mouseClicked

public void mouseClicked(MouseEvent e)

If isPolylineFamily is true, then does the following.

Copies the tentativeNodePoints to the committedNodePoints.
If the click was a double click or the right button click, then calls the creatingEnd method.

See=>Detection of the double-click or right button click

Note : This method is used for creating a polyline or a cubic curve. However If the isRectangleFamily, isLineFamily or isComponentFamily is true, then this method creates a small shape at the clicked point according to the commandId.

mouseEntered

public void mouseEntered(MouseEvent e)
∙ Nothing is done.

mouseExited

public void mouseExited(MouseEvent e)
∙ Nothing is done.

isDifferentPoint

private boolean isDifferentPoint(Point2D p1, Point2D p2)
∙ Return true if the position of p1 is different from that of p2.

createNodePoint

private void createNodePoint(int ctrl, Point2D mousePT)

Parameters:

ctrl - Same as the ctrl.
mousePT - The mouse position.

Processing:

Copies all the points in the committedNodePoints to the tentativeNodePoints and adds a new point given by the mouseMoved method to the tentativeNodePoints, and then calls the create method of the shapeElement.


Note : Serious errors in CreatShapeLS return=>page top

Error case

Error handling

The mouse was dragged for creating a polyline or cubic curve.
The mouse click was expected.

The mouse drag may be the result of that the mouse was unexpectedly moved slightly. So if the moved distance is small, a new segment junction point will be added at end point of the mouse drag.

The mouse was clicked for creating a basic shape or a line.
The mouse drag was required.

Creates a small shape around the clicked point according to the commandId.

Clicked on a button for creating a shape and tried to move or resize another shape.

Same as the above.
Clicked on a button for creating a shape and next clicked other button. The mouse drag or click was expected.
This error can be detected by the Command dispatcher ExecComannd, not by the CreateShapeLS. So the ExecCommand calls the abort method to terminate the CreateShapeLS.

Note : The exec method of ExecComannd stores the CreateShapeLS object to the activeCreateShapeLS field of the ExecCommand before creating a shape. If the CreateShapeLS finished normally or abnormally, the creatingEnd method of the CreateShapeLS generates a command to return to the ExecCommand for reporting its normal end (see=>Control flow Step6).
Then the ExecCommand clears (stores null to) the field of activeCreateShapeLS.
This error can be found by the exec method checking the activeCreateShapeLS field before dispatching a new command. If the activeCreateShapeLS field isn't null, then the error occurred, so the exec method calls the abort method to terminate the CreateShapeLS.

Note : Detection of the double-click or right button click

Whether double-click or not can be known by the getClickCount() method of the MouseEvent object which is given as the parameter of the mouseClicked method. However, it can't give us any information about right-button-click. We have to get the right-button-click information by the MouseEvent object which is given as the parameter of the mousePressed as follows.

int ctrl=0;
if((key&InputEvent.SHIFT_DOWN_MASK)!=0) ctrl=1; //check Shift-key
if((key&InputEvent.CTRL_DOWN_MASK)!=0) ctrl=2; //check Ctrl-key
if((key&InputEvent.BUTTON2_DOWN_MASK)!=0) ctrl=3; //check mouse button2
if((key&InputEvent.BUTTON3_DOWN_MASK)!=0) ctrl=3; //check mouse button3

The ctrl field is set in the mousePressed method and is referred in the mouseClicked method.


3. Class DiscreteAngledLine return=>page top

This class is used to restrict the direction of the mouse drag, which enable to create a horizontal or vertical line easily and move a shape to the horizontal or vertical direction easily.

Field

Description

initAngle

double initAngle

The initial angle (degree) of the direction.

anglePitch

double anglePitch

The angle pitch (degree) of the direction.

startPT

Point2D startPT

The start point (anchor point).

direction

int direction

The integer representing the specified direction. If the direction isn't specified, then this field equals -1. For example, if the initAngle=0 and anglePitch=90, then direction=0,2 represents x-direction and direction=1,3 represents y-direction.

vec

Vector2D[] vec

The constructor sets the direction vectors to this field.


Method

Description

Constructor

public DiscreteAngledLine(double initAngle, double anglePitch, Point2D startPT)

Sets the parameters to the corresponding fields and sets the direction vectors to the vec.

getControlledPT
(static)

public Point2D getControlledPT(int ctrl, Point2D p)

Usually, the next static method is used. However, the next method has a weak point, that is, if the p is closed to p0, the restricted direction from p0 to p is changed easily by the small movement of p.
This method avoids this week point. This method keeps the direction from p0 to p under the condition of ctrl>0, even if the p is moved around p0 closely.

Parameters:
ctrl - if ctrl>0, then the line direction from the startPT to the p is restricted.
p - The end point.

Returns:

Returns the same point as described in the next static method.

getControlledPT
(static)

public static Point2D getControlledPT(double initAngle, double anglePitch, Point2D p0, Point2D p)

Parameters:
initAngle - The initial angle (degree).
anglePitch - The angle pitch (degree).
p0 - The start point of a line.
p - The end point of a line.

Returns:

Returns the projected point of the p on the line whose endpoint is p0 and the angle with x-axis is one of initAngle+anglePitch*n (n-0,1,2....). Here the n is selected so that the angle given by initAngle+anglePitch*n is closest to the angle from x-axis to p0-p.
Example: If initAngle=0 and anglePitch=45, then the retured points for p are as follow.



Copyright (c) 2009-2013
All other trademarks are property of their respective owners.