I solved this problem by adding two tables that each memorize the X and Y coordinate for the node instance being generated at the presentation layer and at model layer.
At runtime, node images continue to change its position and these events are all updated.
When I click on a node image on Panel instance, it gives the id of the node instance.
The reason why two tables are required is that only when the id returned by calling the X, Y position of the node image refers to the same node object is the evidence that the event is for the node object represented by the clicked node image. Now I realize I could have used multi-key table.
import java.util.ArrayList;
import java.util.List;
// * Represents node at presentation layer and its model
public class NodeObject
{
// * node id
private int id;
// * coordinate on Panel
public double x;
public double y;
// * coordinate change
private double dx;
private double dy;
// * isFixed
public boolean fixed;
// * node name
public String nodeName;
// * connected node object id list ( redundant when edge is used )
public List<Integer> connectedNodeIdList;
// * connected edge object id list
private List<Integer> connectedEdgeIdList;
// * constructor
public NodeObject()
{}
// * constructor
public NodeObject( int _id )
{
// * initialization
this.id = _id;
// * default
this.nodeName = "default";
// * connected node id list
this.connectedNodeIdList = new ArrayList<Integer>();
}
// * Constructor ( when node name is given )
public NodeObject( int _id, String _nodeName )
{
// * node id
this.id = _id;
// * node name
this.nodeName = _nodeName;
// * connected node id list
this.connectedNodeIdList = new ArrayList<Integer>();
// * connected edge id list
this.connectedEdgeIdList = new ArrayList<Integer>();
}
// * set node name
public void setNodeName( String nName )
{
this.nodeName = nName;
}
// * get node id
public int getNodeId()
{
return this.id;
}
// * get node name
public String getNodeName()
{
return this.nodeName;
}
// * get node name and id in String
public String getNodeNameWithID()
{
String id = Integer.toString( this.getNodeId() );
return ( this.nodeName + "-" +id );
}
// * store connected node
public boolean addSingleNode( int nid )
{
if ( this.connectedNodeIdList.contains( nid ) == true )
{
return true; // this node is already connected
}
else
{
// * register
this.connectedNodeIdList.add( nid );
// * this is the first time this node is connected
return false;
}
}
// * unregister a node
public boolean removeConnectedSingleNode( int nid )
{
// * it was registered before
if ( this.connectedNodeIdList.contains( nid ) == true )
{
this.connectedNodeIdList.remove( nid );
return true; // it had been registered and now unregistered ( only at model layer )
}
else
{
return false; // it has not been registered before.
}
}
// * add edge id
public boolean addSingleEdge( int eid )
{
if ( this.connectedEdgeIdList.contains( eid ) == true )
{
return true; // already registered edge
}
else
{
// * registered
this.connectedEdgeIdList.add( eid );
// * this is the first time this edge was connected
return false;
}
}
// * remove edge
public boolean removeConnectedSingleEdge( int eid )
{
// * registered before
if ( this.connectedEdgeIdList.contains( eid ) == true )
{
this.connectedEdgeIdList.remove( eid );
return true; // now removed ( model level )
}
else
{
return false; // it has not been registered before
}
}
// * return edge id list
public List<Integer> getEdgeIdList()
{
return this.connectedEdgeIdList;
}
//////// for visualization on Panel instance ///////
// * X coordinate setting
public void setNodePositionX( Double xPos )
{
this.x = xPos;
}
// * Y coordinate setting
public void setNodePositionY( Double yPos )
{
this.y = yPos;
}
// * change of node position
public void changeNodePosition( Double changeX, Double changeY )
{
this.x = this.x + changeX;
this.y = this.y + changeY;
}
// * position difference
public void changeNodePositionDifference( Double changeDX, Double changeDY )
{
this.dx = this.dx + changeDX;
this.dy = this.dy + changeDY;
}
// * update node position difference
public void updateNodePositionDifference( Double changeDX, Double changeDY )
{
this.dx = changeDX;
this.dy = changeDY;
}
// * get X pos
public double getNodePositionX()
{
return this.x;
}
// * get Y pos
public double getNodePositionY()
{
return this.y;
}
// * get dx
public double getNodePositionDX()
{
return this.dx;
}
// * get dy
public double getNodePositionDY()
{
return this.dy;
}
}
And the Graph class goes like below
public class Graph extends Panel implements Runnable, MouseListener, MouseMotionListener, ItemListener
{
// * number of nodes
public int nnodes;
// * node generator
public NodeGenerator ndGenerator;
// * memorize the node coordinate
public Map<Integer, Integer> xCoordinateTbl; // key : coordinate / value : node id
public Map<Integer, Integer> yCoordinateTbl;
// * node tbl
public Map<Integer, NodeObject> nodeTbl;
Once mouse click event occurs, it is handled like below
public void actionPerformed(ActionEvent event)
{
// * get node id of the node object being referred to at the presentation layer
Integer nid = getNodeId( e.getPoint().x, e.getPoint().y );
// * remove node on the presentation layer and of the model at the same time
removeSingleNode( nid );
}