Hello, everyone!
While studying graph algorithms I created a class that helps visualise what your algorithm is doing. That’s helpful for debugging and helps learn the way the algorithm works.

You can plug any graph algorithm, the important part is to notify the JPanel whenever you want to repaint.
Here is the code:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.algos; | |
| import java.awt.*; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.List; | |
| import javax.swing.*; | |
| public class GraphPanel extends JPanel { | |
| private static final long serialVersionUID = 7148504528835036003L; | |
| private List<GraphNode> graph = new ArrayList<>(); | |
| public static class GraphNode { | |
| public static final double radius = 30; | |
| public Point point; | |
| public int index; | |
| public List<GraphNode> children; | |
| public boolean currentlyVisited = false; | |
| public GraphNode(int index, Point point) { | |
| this.point = point; | |
| this.index = index; | |
| children = new ArrayList<>(); | |
| } | |
| public void draw(Graphics g) { | |
| if (this.currentlyVisited) { | |
| g.setColor(Color.GREEN); | |
| g.fillOval(this.point.x, this.point.y, (int)radius * 2, (int)radius * 2); | |
| } else { | |
| g.setColor(Color.BLACK); | |
| g.drawOval(this.point.x, this.point.y, (int)radius * 2, (int)radius * 2); | |
| } | |
| g.setColor(Color.BLACK); | |
| g.drawChars(new char[]{Character.forDigit(this.index, 10)}, 0, 1, this.point.x, this.point.y); | |
| } | |
| } | |
| @Override | |
| public void paintComponent(Graphics g) { | |
| super.paintComponent(g); | |
| for (GraphNode gf : graph) { | |
| gf.draw(g); | |
| for (GraphNode child : gf.children) { | |
| g.drawLine(gf.point.x + (int) GraphNode.radius, gf.point.y + (int) GraphNode.radius, child.point.x + (int) GraphNode.radius, child.point.y + (int) GraphNode.radius); | |
| } | |
| } | |
| } | |
| public void addNodes(GraphNode… nodes) { | |
| this.graph.addAll(Arrays.asList(nodes)); | |
| } | |
| } |
And here is how you might use it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.algos; | |
| import com.algos.GraphPanel.GraphNode; | |
| import java.awt.BorderLayout; | |
| import java.awt.Color; | |
| import java.awt.Point; | |
| import java.util.ArrayDeque; | |
| import java.util.Queue; | |
| import javax.swing.SwingUtilities; | |
| import javax.swing.JFrame; | |
| import javax.swing.JPanel; | |
| /** | |
| * A panel maintaining a picture of a Do Not Enter sign. | |
| */ | |
| public class GraphsGraphics { | |
| private static boolean[] visited = new boolean[100]; | |
| private static Queue<GraphNode> queue = new ArrayDeque<>(); | |
| public static void DFS(GraphNode currentNode, GraphNode searchedNode, JPanel panel) { | |
| System.out.println("Currently we are visiting node " + currentNode.index); | |
| currentNode.currentlyVisited = true; | |
| panel.updateUI(); | |
| try { | |
| Thread.sleep(2000); | |
| } catch (InterruptedException e) { | |
| } | |
| currentNode.currentlyVisited = false; | |
| panel.updateUI(); | |
| if (currentNode.index == searchedNode.index) { | |
| System.out.println("Node found: " + searchedNode.index); | |
| return; | |
| } | |
| if (visited[currentNode.index]) { | |
| return; | |
| } | |
| visited[currentNode.index] = true; | |
| for (GraphNode child : currentNode.children) { | |
| DFS(child, searchedNode, panel); | |
| } | |
| } | |
| public static void BFS(GraphNode currentNode, GraphNode searchedNode, JPanel panel) { | |
| currentNode.currentlyVisited = true; | |
| panel.updateUI(); | |
| try { | |
| Thread.sleep(2000); | |
| } catch (InterruptedException e) { | |
| } | |
| currentNode.currentlyVisited = false; | |
| panel.updateUI(); | |
| if (currentNode.index == searchedNode.index) { | |
| System.out.println("Node found: " + searchedNode.index); | |
| return; | |
| } | |
| if (visited[currentNode.index]) { | |
| return; | |
| } | |
| System.out.println("Currently visiting node " + currentNode.index); | |
| visited[currentNode.index] = true; | |
| for (GraphNode child : currentNode.children) { | |
| queue.add(child); | |
| } | |
| if (!queue.isEmpty()) { | |
| BFS(queue.poll(), searchedNode, panel); | |
| } | |
| } | |
| /** | |
| * A little driver in case you want a stand-alone application. | |
| */ | |
| public static void main(String[] args) { | |
| GraphNode rootNode = new GraphNode(0, new Point(300, 20)); | |
| GraphNode node1 = new GraphNode(1, new Point(200, 100)); | |
| GraphNode node2 = new GraphNode(2, new Point(400, 100)); | |
| GraphNode node3 = new GraphNode(3, new Point(500, 200)); | |
| GraphNode node4 = new GraphNode(4, new Point(100, 200)); | |
| GraphNode node5 = new GraphNode(5, new Point(40, 300)); | |
| GraphNode node6 = new GraphNode(6, new Point(200, 300)); | |
| rootNode.children.add(node1); | |
| rootNode.children.add(node2); | |
| node1.children.add(node4); | |
| node2.children.add(node3); | |
| node4.children.add(node5); | |
| node4.children.add(node6); | |
| GraphPanel panel = new GraphPanel(); | |
| panel.addNodes(rootNode, node1, node2, node3, node4, node5, node6); | |
| SwingUtilities.invokeLater(() -> { | |
| panel.setBackground(Color.GRAY.darker()); | |
| JFrame frame = new JFrame("A simple graphics program"); | |
| frame.setSize(800, 600); | |
| frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
| frame.getContentPane().add(panel, BorderLayout.CENTER); | |
| frame.setVisible(true); | |
| }); | |
| BFS(rootNode, node6, panel); | |
| } | |
| } |
Happy learning!