Search code examples
swingresizejpanelcoordinateslayout-manager

How to draw custom components on a resizeable JPanel with a specific coordinate system?


I'm working on a graph-tree visualizing application. The program could create different layouts for visualizing trees. By tree I mean a Node object which could have a Node as a parent, and a list of nodes called children. By creating layout for a tree, I mean setting an X and a Y coordinate of each node of the tree. There are multiple layout algorithms all of them are in an implementation of a LayoutAlgorithm interface, and one of their methods takes a root node (the one node of the tree without a parent), and calculating the X and Y coordinate for each node of the tree.

To visualize these layouts, I could use a JPanel, and tell exactly in which coordinate I'd like to draw my nodes, and after, I could draw lines between them. Thats a bit problemmatic, because, I'd like to draw a node with x=0 and y=0 coordinates to the left side horizontally and to the middle vertically. To achieve that, I could simply offset the y-coordinates of each node, and draw them after, but I'd want the JPanel to be resizable. Thats also achivable by redrawing each of the nodes after a resize operation happened. But thats too much complexity, so Im wondering if there is an easier/simpler solution for that, like a custom LayoutManager for the JPanel.

I've tried several LayoutManager, but none of them are letting me put JComponents on the panel using coordinates.


Solution

  • By creating a custom JComponent class and overriding the paint method, its possible to offset the coordinates of the components and graphics to be drawn, by calling the g.translate(...) method.

    import javax.swing.*;
    import java.awt.*;
    
    public class VerticallyAlignedJPanel extends JPanel {
    
        public VerticallyAlignedJPanel() {
            super();
            setLayout(null);
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            g.translate(0, getHeight()/2);
            super.paintComponent(g);
        }
    }