I was playing around with JUNG2 and wanted to implement a small GUI that allows me to display and change a Graph. Following the examples from the JUNG library worked fine, but they don't separate Model, View and Controller. So I started to build GUI with a clean separation.
My first version of a GUI is supposed, to simply show an initial graph. The view is an observer of the model and gets notifications, whenever the graph changes, which happens exactly one time, at the initialization step of the graph. However, the graph isn't displayed in the center of the screen, (as it was in the non-MVC example), but I can see a small part of it in the upper-left corner.
Now, this leads to the general question: How do I tell the jung-visualization components, that the model changed? And for later: How do I use ready-to-use components, like the Jung-Mouse in a MVC-Architecture? JUNG seems to have mixed model, view and controller and I'm not sure, how and where to use them properly.
EDIT: The Jung Tutorial shows how to manage changes by using the mouse, but it doesn't show, how to change the view based on changes in the model (through other options, e.g. a button "add node" or something else)
Here is my first try so far:
The View
public class MOCView implements GraphChangeObserver {
private final ControllerInterface controller;
private final MOCModelInterface model;
private Layout<Node, Edge> layout;
private BasicVisualizationServer<Node, Edge> visualization;
private JFrame frame;
public MOCView(final ControllerInterface controller,
final MOCModelInterface model) {
this.controller = controller;
this.model = model;
model.registerObserver(this);
}
public void createView() {
this.layout = new CircleLayout<Node, Edge>(this.model.getGraph());
this.layout.setSize(new Dimension(300, 300));
this.visualization = new BasicVisualizationServer<Node, Edge>(
this.layout);
this.visualization.setPreferredSize(new Dimension(350, 350));
this.frame = new JFrame("MOC View");
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frame.getContentPane().add(this.visualization);
this.frame.pack();
this.frame.setVisible(true);
}
@Override
public void updateGraph() {
this.visualization.repaint();
}
}
The Model
public class MOCModel implements MOCModelInterface {
private final Graph<Node, Edge> graph = new DirectedSparseGraph<Node, Edge>();
private final ArrayList<GraphChangeObserver> graphChangeObservers = new ArrayList<GraphChangeObserver>();
@Override
public void initialize() {
this.generateInitialGraph();
}
@Override
public Graph<Node, Edge> getGraph() {
return this.graph;
}
@Override
public void registerObserver(final GraphChangeObserver o) {
this.graphChangeObservers.add(o);
}
@Override
public void removeObserver(final GraphChangeObserver o) {
this.graphChangeObservers.remove(o);
}
private void generateInitialGraph() {
final Node nodeA = new Node("Node A");
this.graph.addVertex(nodeA);
final Node nodeB = new Node("Node B");
this.graph.addVertex(nodeB);
final Node nodeC = new Node("Node C");
this.graph.addVertex(nodeC);
final Node nodeD = new Node("Node D");
this.graph.addVertex(nodeD);
final Node nodeE = new Node("Node E");
this.graph.addVertex(nodeE);
this.graph.addEdge(new Edge("Edge 1"), nodeA, nodeB);
this.graph.addEdge(new Edge("Edge 2"), nodeA, nodeC);
this.graph.addEdge(new Edge("Edge 3"), nodeB, nodeC);
this.graph.addEdge(new Edge("Edge 4"), nodeC, nodeD);
this.graph.addEdge(new Edge("Edge 5"), nodeD, nodeE);
this.graph.addEdge(new Edge("Edge 6"), nodeA, nodeE);
this.graph.addEdge(new Edge("Edge 7"), nodeE, nodeA);
this.graph.addEdge(new Edge("Edge 8"), nodeD, nodeB);
notifyGraphChangeObservers();
}
private void notifyGraphChangeObservers() {
for (final GraphChangeObserver gco : this.graphChangeObservers) {
gco.updateGraph();
}
}
}
The Controller
public class MOCController implements ControllerInterface {
private final MOCModelInterface model;
private final MOCView view;
public MOCController(final MOCModelInterface model) {
this.model = model;
this.view = new MOCView(this, model);
this.view.createView();
this.model.initialize();
}
}
The Main Class
public class MOCStart {
/**
* @param args
*/
public static void main(final String[] args) {
final MOCModelInterface model = new MOCModel();
new MOCController(model);
}
}
The best way to learn how JUNG2 works is to look at its samples from SVN repository using Maven
svn checkout http://jung.googlecode.com/svn/trunk/ jung-read-only
via m2e Maven Eclipse pluginFrom here, check the package edu.uci.ics.jung.samples for various JUNG2 code samples involving graph mouse: e.g.
GraphEditorDemo.java
Note: Apply the SVN patches below to correct a few bugs