javajframejpanelgraphics2djawt

How to draw in two different JFrames


My goal is to implement a space filling curve in one frame, and in the other the number of each pixel in the frame. In the future, I will need to draw some coordinates in the third frame. My question now is how do I draw the curve in one frame and the pixels in the other. I only get them in the same frame.

Here is the code:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class HilbertCurve extends JPanel {

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            HilbertCurve exemplo1 = new HilbertCurve();
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(exemplo1);
            frame.pack();
            frame.setLocation(100,100);
            frame.setVisible(true);

            JFrame frame1 = new JFrame();
            frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame1.add(exemplo1);
            frame1.pack();
            frame1.setLocation(800, 100);
            frame1.setVisible(true);
        }
    });
}
private SimpleGraphics sg = null;
private int dist0 = 512;
private int dist = dist0;

public HilbertCurve() {
    sg = new SimpleGraphics();
}

@Override
public Dimension getPreferredSize() {
    return new Dimension(520,520);
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    int level = 4;
    dist = dist0;
    for (int i = level; i > 0; i--) {
        dist /= 2;
    }
    sg.goToXY(dist / 2, dist / 2);
    Graphics2D g2d = (Graphics2D) g.create();
    hilbertU(g2d, level);
    g2d.dispose();

}


private void hilbertU(Graphics2D g, int level) {
    if (level > 0) {
        hilbertD(g, level - 1);
        sg.lineRel(g, 0, dist);
        hilbertU(g, level - 1);
        sg.lineRel(g, dist, 0);
        hilbertU(g, level - 1);
        sg.lineRel(g, 0, -dist);
        hilbertC(g, level - 1);
    }
}

private void hilbertD(Graphics2D g, int level) {
    if (level > 0) {
        hilbertU(g, level - 1);
        sg.lineRel(g, dist, 0);
        hilbertD(g, level - 1);
        sg.lineRel(g, 0, dist);
        hilbertD(g, level - 1);
        sg.lineRel(g, -dist, 0);
        hilbertA(g, level - 1);
    }
}

private void hilbertC(Graphics2D g, int level) {
    if (level > 0) {
        hilbertA(g, level - 1);
        sg.lineRel(g, -dist, 0);
        hilbertC(g, level - 1);
        sg.lineRel(g, 0, -dist);
        hilbertC(g, level - 1);
        sg.lineRel(g, dist, 0);
        hilbertU(g, level - 1);
    }
}

private void hilbertA(Graphics2D g, int level) {
    if (level > 0) {
        hilbertC(g, level - 1);
        sg.lineRel(g, 0, -dist);
        hilbertA(g, level - 1);
        sg.lineRel(g, -dist, 0);
        hilbertA(g, level - 1);
        sg.lineRel(g, 0, dist);
        hilbertD(g, level - 1);
    }
}

}

And the SimpleGraphics.java class

import java.awt.Graphics2D;

class SimpleGraphics {
    int a = 1;

    private int x = 0, y = 0;

    public SimpleGraphics() {
    }

    public void goToXY(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void lineRel(Graphics2D g, int deltaX, int deltaY) {
        g.drawLine(x, y, x + deltaX, y + deltaY);
        g.drawString(Integer.toString(a++), x+deltaX, y+deltaY);
        x += deltaX;
        y += deltaY;
    }
}

The output is:Output

The out put I want is: enter image description here


Solution

  • Basically speaking, you want to decouple the data from the view. The way in which the data "might" be rendered should be irrelevant to the data.

    This concept is commonly know as "Model-View-Controller".

    To start with, you want to create a model of your "Hilbert Curve", which would be a bunch of points, each point representing the next point in the curve, for example...

    public class HilbertCurveModel {
    
        private List<Point> points;
        private int distribution;
    
        private int xDelta, yDelta;
    
        public HilbertCurveModel(int level, int size) {
            points = new ArrayList<>(25);
            distribution = size;
            for (int i = level; i > 0; i--) {
                distribution /= 2;
            }
            hilbertU(level);
        }
    
        public int getDistribution() {
            return distribution;
        }
    
        public List<Point> getPoints() {
            List<Point> copy = new ArrayList<>(points.size());
            for (Point p : points) {
                copy.add(new Point(p));
            }
            return copy;
        }
    
        protected void addLine(int x, int y) {
            points.add(new Point(x + xDelta, y + yDelta));
            xDelta += x;
            yDelta += y;
        }
    
        private void hilbertU(int level) {
            if (level > 0) {
                hilbertD(level - 1);
                addLine(0, distribution);
                hilbertU(level - 1);
                addLine(distribution, 0);
                hilbertU(level - 1);
                addLine(0, -distribution);
                hilbertC(level - 1);
            }
        }
    
        private void hilbertD(int level) {
            if (level > 0) {
                hilbertU(level - 1);
                addLine(distribution, 0);
                hilbertD(level - 1);
                addLine(0, distribution);
                hilbertD(level - 1);
                addLine(-distribution, 0);
                hilbertA(level - 1);
            }
        }
    
        private void hilbertC(int level) {
            if (level > 0) {
                hilbertA(level - 1);
                addLine(-distribution, 0);
                hilbertC(level - 1);
                addLine(0, -distribution);
                hilbertC(level - 1);
                addLine(distribution, 0);
                hilbertU(level - 1);
            }
        }
    
        private void hilbertA(int level) {
            if (level > 0) {
                hilbertC(level - 1);
                addLine(0, -distribution);
                hilbertA(level - 1);
                addLine(-distribution, 0);
                hilbertA(level - 1);
                addLine(0, distribution);
                hilbertD(level - 1);
            }
        }
    
    }
    

    Once you have the model, you can share it between views, so that they can render it in what ever way they see fit, for example...

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.geom.Line2D;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.DefaultListModel;
    import javax.swing.JFrame;
    import javax.swing.JList;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.SwingUtilities;
    
    public class Test {
    
        public class HilbertCurveModel {
    
            private List<Point> points;
            private int distribution;
    
            private int xDelta, yDelta;
    
            public HilbertCurveModel(int level, int size) {
                points = new ArrayList<>(25);
                distribution = size;
                for (int i = level; i > 0; i--) {
                    distribution /= 2;
                }
                hilbertU(level);
            }
    
            public int getDistribution() {
                return distribution;
            }
    
            public List<Point> getPoints() {
                List<Point> copy = new ArrayList<>(points.size());
                for (Point p : points) {
                    copy.add(new Point(p));
                }
                return copy;
            }
    
            protected void addLine(int x, int y) {
                points.add(new Point(x + xDelta, y + yDelta));
                xDelta += x;
                yDelta += y;
            }
    
            private void hilbertU(int level) {
                if (level > 0) {
                    hilbertD(level - 1);
                    addLine(0, distribution);
                    hilbertU(level - 1);
                    addLine(distribution, 0);
                    hilbertU(level - 1);
                    addLine(0, -distribution);
                    hilbertC(level - 1);
                }
            }
    
            private void hilbertD(int level) {
                if (level > 0) {
                    hilbertU(level - 1);
                    addLine(distribution, 0);
                    hilbertD(level - 1);
                    addLine(0, distribution);
                    hilbertD(level - 1);
                    addLine(-distribution, 0);
                    hilbertA(level - 1);
                }
            }
    
            private void hilbertC(int level) {
                if (level > 0) {
                    hilbertA(level - 1);
                    addLine(-distribution, 0);
                    hilbertC(level - 1);
                    addLine(0, -distribution);
                    hilbertC(level - 1);
                    addLine(distribution, 0);
                    hilbertU(level - 1);
                }
            }
    
            private void hilbertA(int level) {
                if (level > 0) {
                    hilbertC(level - 1);
                    addLine(0, -distribution);
                    hilbertA(level - 1);
                    addLine(-distribution, 0);
                    hilbertA(level - 1);
                    addLine(0, distribution);
                    hilbertD(level - 1);
                }
            }
    
        }
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    HilbertCurveModel model = new HilbertCurveModel(4, 512);
    
                    HilbertCurve exemplo1 = new HilbertCurve(model);
                    JFrame frame = new JFrame();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(exemplo1);
                    frame.pack();
                    frame.setLocation(100, 100);
                    frame.setVisible(true);
    
                    // This is the second window ;)
    
                    int xPos = model.getDistribution() / 2;
                    int yPos = model.getDistribution() / 2;
    
                    DefaultListModel listModel = new DefaultListModel();
                    listModel.addElement(new Point(xPos, yPos));
                    for (Point p : model.getPoints()) {
                        listModel.addElement(p);
                    }
    
                    JFrame frame1 = new JFrame();
                    frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame1.add(new JScrollPane(new JList(listModel)));
                    frame1.pack();
                    frame1.setLocation(800, 100);
                    frame1.setVisible(true);
                }
            });
        }
    
        public class HilbertCurve extends JPanel {
    
            private HilbertCurveModel model;
            private int xPos, yPos;
    
            public HilbertCurve(HilbertCurveModel model) {
                this.model = model;
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(520, 520);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                int xPos = model.getDistribution() / 2;
                int yPos = model.getDistribution() / 2;
    
                List<Point> points = model.points;
                if (points.size() == 0) {
                    return;
                }
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.translate(xPos, yPos);
                g2d.setColor(Color.BLACK);
                Point from = new Point(0, 0);
                for (Point point : points) {
                    Point to = new Point(point);
                    System.out.println(from + "x" + to);
                    Line2D line = new Line2D.Double(from, to);
                    g2d.draw(line);
                    from = to;
                }
                g2d.dispose();
            }
        }
    }
    

    This will basically create two windows, one will render the curve and the other will display a list of points

    Updated

    The problem about my code is that I have the g.drawLine(x, y, x + deltaX, y + deltaY); g.drawString(Integer.toString(a++), x+deltaX, y+deltaY); in the lineRel method, and I don't know how to draw differently in another frame. Every time I call the paint method, it draws the same thing

    Okay, this example goes to the nth degree. Personally, I'd have created a renderer which contained a couple of flags which could be used to turn features on or off, but this demonstrates inheritance and how you might be able to use to use it to expand the functionality of a class.

    Curvy

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.geom.Line2D;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class Test {
    
        public class HilbertCurveModel {
    
            private List<Point> points;
            private int distribution;
    
            private int xDelta, yDelta;
    
            public HilbertCurveModel(int level, int size) {
                points = new ArrayList<>(25);
                distribution = size;
                for (int i = level; i > 0; i--) {
                    distribution /= 2;
                }
                hilbertU(level);
            }
    
            public int getDistribution() {
                return distribution;
            }
    
            public List<Point> getPoints() {
                List<Point> copy = new ArrayList<>(points.size());
                for (Point p : points) {
                    copy.add(new Point(p));
                }
                return copy;
            }
    
            protected void addLine(int x, int y) {
                points.add(new Point(x + xDelta, y + yDelta));
                xDelta += x;
                yDelta += y;
            }
    
            private void hilbertU(int level) {
                if (level > 0) {
                    hilbertD(level - 1);
                    addLine(0, distribution);
                    hilbertU(level - 1);
                    addLine(distribution, 0);
                    hilbertU(level - 1);
                    addLine(0, -distribution);
                    hilbertC(level - 1);
                }
            }
    
            private void hilbertD(int level) {
                if (level > 0) {
                    hilbertU(level - 1);
                    addLine(distribution, 0);
                    hilbertD(level - 1);
                    addLine(0, distribution);
                    hilbertD(level - 1);
                    addLine(-distribution, 0);
                    hilbertA(level - 1);
                }
            }
    
            private void hilbertC(int level) {
                if (level > 0) {
                    hilbertA(level - 1);
                    addLine(-distribution, 0);
                    hilbertC(level - 1);
                    addLine(0, -distribution);
                    hilbertC(level - 1);
                    addLine(distribution, 0);
                    hilbertU(level - 1);
                }
            }
    
            private void hilbertA(int level) {
                if (level > 0) {
                    hilbertC(level - 1);
                    addLine(0, -distribution);
                    hilbertA(level - 1);
                    addLine(-distribution, 0);
                    hilbertA(level - 1);
                    addLine(0, distribution);
                    hilbertD(level - 1);
                }
            }
    
        }
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    HilbertCurveModel model = new HilbertCurveModel(4, 512);
    
                    JFrame frame = new JFrame();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new HilbertCurveLineRenderer(model));
                    frame.pack();
                    frame.setLocation(100, 100);
                    frame.setVisible(true);
    
                    JFrame frame2 = new JFrame();
                    frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame2.add(new HilbertCurveLineAndPointRenderer(model));
                    frame2.pack();
                    frame2.setLocation(100 + frame.getWidth(), 100);
                    frame2.setVisible(true);
                }
            });
        }
    
        public abstract class AbstractHilbertCurve extends JPanel {
    
            private HilbertCurveModel model;
    
            public AbstractHilbertCurve(HilbertCurveModel model) {
                this.model = model;
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(520, 520);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                int xPos = model.getDistribution() / 2;
                int yPos = model.getDistribution() / 2;
    
                List<Point> points = model.points;
                if (points.size() == 0) {
                    return;
                }
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.translate(xPos, yPos);
                g2d.setColor(Color.BLACK);
                Point from = new Point(0, 0);
                int count = 0;
                for (Point to : points) {
                    count++;
                    // I don't trust you to play nice with my graphics context
                    Graphics2D copyG = (Graphics2D) g2d.create();
                    renderLine(copyG, from, to);
                    renderCurrentPoint(copyG, count, to);
                    from = to;
                    copyG.dispose();
                }
                g2d.dispose();
            }
    
            protected void renderLine(Graphics2D g2d, Point from, Point to) {
            }
    
            protected void renderCurrentPoint(Graphics2D g2d, int count, Point current) {
            }
        }
    
        public class HilbertCurveLineRenderer extends AbstractHilbertCurve {
    
            public HilbertCurveLineRenderer(HilbertCurveModel model) {
                super(model);
            }
    
            protected void renderLine(Graphics2D g2d, Point from, Point to) {
                Line2D line = new Line2D.Double(from, to);
                g2d.draw(line);
            }
        }
    
        public class HilbertCurveLineAndPointRenderer extends AbstractHilbertCurve {
    
            public HilbertCurveLineAndPointRenderer(HilbertCurveModel model) {
                super(model);
            }
    
            protected void renderLine(Graphics2D g2d, Point from, Point to) {
                Line2D line = new Line2D.Double(from, to);
                g2d.draw(line);
            }
    
            @Override
            protected void renderCurrentPoint(Graphics2D g2d, int count, Point current) {
                String text = Integer.toString(count);
                FontMetrics fm = g2d.getFontMetrics();
                int x = current.x - (fm.stringWidth(text) / 2); 
                g2d.drawString(text, x, current.y);
            }
    
        }
    }
    

    I would, highly, recommend you take a closer look at How to perform custom painting and Painting in Swing to gain a better understanding into how painting actually works in Swing.

    Also, an instance of a component can only reside in one container at a time. As demonstrated in the above example, you will need at least two instances of the render pane