Reputation: 11
I'm experiencing a rendering/painting issue with a simple drawing of a line in Swing when it is applied to a component which contains an already existing graph created using Graphstream.
Issue is when the mouse is dragged and painting method called, the underlying graph is updated and the whole frame flickers and line is not drawn smoothly.
Is there a way to freeze the rendering of the underlying graph?
I have tried several approaches but all seem to produce the same result. Below the latest example I tried setting a forelayout renderer on the view.
I believe it is a simple issue related to an incorrect approach to drawing on the canvas without properly managing the concurrency or update of the repaint/render of this foreground layer.
Also, as seen below, I remove all listeners from the graph before adding my own custom one (otherwise when dragging the mouse, a bounding box/selection rectangle is drawn by the graphstream library, or a node is dragged). Is there a better way also here to deactivate the drawing and mouse interaction done by graphstream.
import org.graphstream.graph.Graph;
import org.graphstream.graph.implementations.DefaultGraph;
import org.graphstream.ui.graphicGraph.GraphicGraph;
import org.graphstream.ui.swing_viewer.DefaultView;
import org.graphstream.ui.swing_viewer.SwingViewer;
import org.graphstream.ui.view.LayerRenderer;
import org.graphstream.ui.view.Viewer;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class LinesDrawingOnGraphExample extends JFrame {
static Point pointStart = null;
static Point pointEnd = null;
static LayerRenderer lineRenderer;
static DefaultView view;
public static void main(String args[]) throws Exception {
JFrame f = new JFrame("Draw a Red Line on graph");
f.setSize(300, 300);
f.setLocation(300, 300);
f.setResizable(false);
//build graph
Graph graph = new DefaultGraph("g");
graph.addNode("A");
graph.addNode("B");
graph.addNode("C");
graph.addNode("D");
graph.addNode("E");
graph.addNode("F");
graph.addNode("G");
graph.addNode("H");
graph.addNode("I");
graph.addEdge("AB", "A", "B");
graph.addEdge("BC", "B", "C");
graph.addEdge("CA", "C", "A");
//set viewer
Viewer viewer = new SwingViewer(graph, Viewer.ThreadingModel.GRAPH_IN_GUI_THREAD);
view = (DefaultView) viewer.addDefaultView(false);
viewer.enableAutoLayout();
viewer.replayGraph(graph);
//backup existing default graph listeners
MouseListener[] ml = ((DefaultView) viewer.getDefaultView()).getMouseListeners();
MouseMotionListener[] ml2 = ((DefaultView) viewer.getDefaultView()).getMouseMotionListeners();
//remove them (remove the bounding box which is drawn on mouse drag)
for (MouseListener mouseListener : ml) {
view.removeMouseListener(mouseListener);
}
for (MouseMotionListener mouseListener : ml2) {
view.removeMouseMotionListener(mouseListener);
}
//add new mouse listeners for drawing
MouseAdapter newListener = new DrawListener();
view.addMouseListener(newListener);
view.addMouseMotionListener(newListener);
//use graph forelayout for drawing the line
lineRenderer = new LayerRenderer<Graphics2D>() {
@Override
public void render(Graphics2D g, GraphicGraph graphicGraph, double v, int i, int i1, double v1, double v2, double v3, double v4) {
if (pointStart != null && pointEnd != null) {
g.setColor(Color.RED);
g.drawLine(pointStart.x, pointStart.y, pointEnd.x, pointEnd.y);
}
}
};
view.setForeLayoutRenderer(lineRenderer);
JPanel p = new JPanel(new BorderLayout());
p.add(view, BorderLayout.CENTER);
f.add(p);
f.setVisible(true);
}
private static class DrawListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
pointStart = e.getPoint();
}
public void mouseReleased(MouseEvent e) {
pointStart = null;
}
public void mouseDragged(MouseEvent e) {
pointEnd = e.getPoint();
view.render((Graphics2D) view.getGraphics());
}
}
}
Upvotes: 1
Views: 49