Krypton
Krypton

Reputation: 1

Java create dynamic but simple graphic using Graphics

I have to create a graphic in Java using the methods of class Graphics. I already coded the Panel and Frame class, so I just have to code the graphic using Graphics.

I´ll add a picture of what I have to create, so maybe somebody can help me with this :/

Here´s a picture of the graphic to create

It should be dynamic, so if the user changes the Frame window size, the graphic should also.

Please help me with this, I´ve already tried so much

Upvotes: 0

Views: 458

Answers (1)

Gilbert Le Blanc
Gilbert Le Blanc

Reputation: 51495

I was going to answer this question as an illustration of how to use decomposition to solve a problem. But the requirement of the graphic being dynamic took this application from the realm of homework assignment to an illustration of component resizing.

The OP didn't mention what GUI software he was using to create the graphic window. I used Java Swing because I'm familiar with Swing.

Here's the GUI I created. I'll post the runnable code at the end of the answer so you can run it yourself and see the component resizing.

Graphics Example

When faced with a task like this one, you break the problem down into smaller and smaller steps, until you can write code for each step. That's what I did.

As I said in my comment, the graphic is made up of 6 levels of 4 circles. The circles are connected with lines touching their circumference. So, using the model / view / controller pattern, I created a model.

The first thing I defined was a Circle class. My circle class contains an integer radius and a java.awt.Point center. Point is a class that holds an X and Y value.

My Circle class has a draw method to draw the circle using the Graphics drawOval method. I put the draw method in the Circle class to keep the other drawing methods simple. When generating complex graphics, or animated games, have each object draw itself.

The Circle class has four methods to determine the top, right, bottom, and left points on the circumference. These methods will be used when we draw the lines connecting the circles.

Here's the complete Circle class.

public class Circle {

    private int radius;

    private Point center;

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public Point getCenter() {
        return center;
    }

    public void setCenter(Point center) {
        this.center = center;
    }

    public Point getTopPoint() {
        int x = getCenter().x;
        int y = getCenter().y - getRadius();
        return new Point(x, y);
    }

    public Point getRightPoint() {
        int x = getCenter().x + getRadius();
        int y = getCenter().y;
        return new Point(x, y);
    }

    public Point getBottomPoint() {
        int x = getCenter().x;
        int y = getCenter().y + getRadius();
        return new Point(x, y);
    }

    public Point getLeftPoint() {
        int x = getCenter().x - getRadius();
        int y = getCenter().y;
        return new Point(x, y);
    }

    public void draw(Graphics g) {
        int diameter = getRadius() + getRadius();
        int x = getCenter().x - getRadius();
        int y = getCenter().y - getRadius();
        g.drawOval(x, y, diameter, diameter);
    }

}

Next, I created a class to hold four circles.

My CircleLevel class has a draw method that draws the four circles and connecting lines. There's not much to explain here.

public class CircleLevel {

    private int radius;
    private int drawingWidth;

    private Circle topLeftCircle;
    private Circle topRightCircle;
    private Circle bottomLeftCircle;
    private Circle bottomRightCircle;

    public CircleLevel(int drawingWidth) {
        this.drawingWidth = drawingWidth;

        this.topLeftCircle = new Circle();
        this.topRightCircle = new Circle();
        this.bottomLeftCircle = new Circle();
        this.bottomRightCircle = new Circle();
    }

    public int getRadius() {
        return radius;
    }

    public int getDrawingWidth() {
        return drawingWidth;
    }

    public void setDrawingWidth(int drawingWidth) {
        this.drawingWidth = drawingWidth;
    }

    public void createCircles(int radius) {
        this.radius = radius;
        int center = drawingWidth / 2;

        Point point = new Point(center - radius, center - radius);
        topLeftCircle.setCenter(point);
        topLeftCircle.setRadius(radius);

        point = new Point(center + radius, center - radius);
        topRightCircle.setCenter(point);
        topRightCircle.setRadius(radius);

        point = new Point(center - radius, center + radius);
        bottomLeftCircle.setCenter(point);
        bottomLeftCircle.setRadius(radius);

        point = new Point(center + radius, center + radius);
        bottomRightCircle.setCenter(point);
        bottomRightCircle.setRadius(radius);
    }

    public void draw(Graphics g) {
        topLeftCircle.draw(g);
        topRightCircle.draw(g);
        bottomLeftCircle.draw(g);
        bottomRightCircle.draw(g);

        drawLines(g);
    }

    private void drawLines(Graphics g) {
        Point start = topLeftCircle.getTopPoint();
        Point end = topRightCircle.getTopPoint();
        g.drawLine(start.x, start.y, end.x, end.y);

        start = topRightCircle.getRightPoint();
        end = bottomRightCircle.getRightPoint();
        g.drawLine(start.x, start.y, end.x, end.y);

        start = bottomRightCircle.getBottomPoint();
        end = bottomLeftCircle.getBottomPoint();
        g.drawLine(start.x, start.y, end.x, end.y);

        start = bottomLeftCircle.getLeftPoint();
        end = topLeftCircle.getLeftPoint();
        g.drawLine(start.x, start.y, end.x, end.y);
    }
}

The view and controller code are more complicated. I created a FrameResize class by extending java.awt.event.ComponentAdapter. I created a drawing panel by extending JPanel.

Because I create the GUI first, and then draw the graphics, I had to put boolean flags in the FrameResize and the drawing panel classes so that I could create the model first, then have the view draw the graphics.

Anyway, if you've read this far, here's the runnable code. It's not minimal.

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class GraphicsExample implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new GraphicsExample());
    }

    private static final boolean DEBUG = false;

    private int drawingWidth;

    private CircleLevel[] circleLevels;

    private Dimension frameSize;

    private DrawingPanel drawingPanel;

    private JFrame frame; 

    public GraphicsExample() {
        this.drawingWidth = 400;
    }

    @Override
    public void run() {
        frame = new JFrame("Graphics Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        FrameResize frameResize = new FrameResize();
        frame.addComponentListener(frameResize);

        drawingPanel = new DrawingPanel(drawingWidth);
        frame.add(drawingPanel);

        frame.pack();
        frame.setLocationRelativeTo(null);

        drawingPanel.setCreated(true);
        circleLevels = drawGraphics();
        drawingPanel.repaint();

        frameSize = frame.getSize();
        if (DEBUG) System.out.println(frameSize);

        frame.setVisible(true);
        frameResize.setCreated(true);
    }

    private CircleLevel[] drawGraphics() {
        int levels = 6;
        CircleLevel[] circleLevels = new CircleLevel[levels];

        int margin = 6;
        int width = drawingWidth - margin - margin;
        int decrement = drawingWidth / 8;

        for (int i = 0; i < levels; i++) {
            int radius = width / 4;
            CircleLevel circleLevel = new CircleLevel(drawingWidth);
            circleLevel.createCircles(radius);
            circleLevels[i] = circleLevel;
            width -= decrement;
        }

        return circleLevels;
    }

    public class FrameResize extends ComponentAdapter {

        private boolean isCreated;

        public FrameResize() {
            this.isCreated = false;
        }

        public void setCreated(boolean isCreated) {
            this.isCreated = isCreated;
        }

        @Override
         public void componentResized(ComponentEvent event) {
            if (isCreated) {
                Dimension size = event.getComponent().getSize();
                if (size.width == frameSize.width && 
                        size.height == frameSize.height) {
                    return;
                }

                if (DEBUG) System.out.println(size);
                frame.setVisible(false);
                frameSize = size;

                drawingWidth = calculateDrawingSize();
                drawingPanel.setResized(drawingWidth);
                drawingPanel.revalidate();
                circleLevels = drawGraphics();
                drawingPanel.repaint();
                frame.setVisible(true);
            }
        }

        private int calculateDrawingSize() {
            // You'll have to adjust these borders for
            // different operating systems.  I'm using
            // Windows 10 defaults.
            int borderWidth = 16;
            int borderHeight = 39;
            int width = frameSize.width - borderWidth;
            int height = frameSize.height - borderHeight;
            int drawingWidth = Math.min(width, height);
            // Making sure the drawing width is divisible
            // by 8 makes subsequent calculations even.
            return drawingWidth / 8 * 8;
        }

    }

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        private boolean isResized;
        private boolean isCreated;

        private int width;

        public DrawingPanel(int width) {
            this.setBackground(Color.WHITE);
            this.setPreferredSize(new Dimension(width, width));
            this.width = width;
            this.isResized = false;
            this.isCreated = false;
        }

        public void setCreated(boolean isCreated) {
            this.isCreated = isCreated;
        }

        public void setResized(int width) {
            this.setPreferredSize(new Dimension(width, width));
            this.width = width;
            this.isResized = true;
        }

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

            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                    RenderingHints.VALUE_ANTIALIAS_ON);

            if (isResized) {
                g2d.setColor(Color.WHITE);
                g2d.fillRect(0, 0, width, width);
                isResized =  false;
            }

            if (isCreated) {
                g2d.setColor(Color.BLACK);
                g2d.setStroke(new BasicStroke(2f));
                for (CircleLevel circleLevel : circleLevels) {
                    circleLevel.draw(g);
                }
            }
        }

    }

    public class CircleLevel {

        private int radius;
        private int drawingWidth;

        private Circle topLeftCircle;
        private Circle topRightCircle;
        private Circle bottomLeftCircle;
        private Circle bottomRightCircle;

        public CircleLevel(int drawingWidth) {
            this.drawingWidth = drawingWidth;

            this.topLeftCircle = new Circle();
            this.topRightCircle = new Circle();
            this.bottomLeftCircle = new Circle();
            this.bottomRightCircle = new Circle();
        }

        public int getRadius() {
            return radius;
        }

        public int getDrawingWidth() {
            return drawingWidth;
        }

        public void setDrawingWidth(int drawingWidth) {
            this.drawingWidth = drawingWidth;
        }

        public void createCircles(int radius) {
            this.radius = radius;
            int center = drawingWidth / 2;

            Point point = new Point(center - radius, center - radius);
            topLeftCircle.setCenter(point);
            topLeftCircle.setRadius(radius);

            point = new Point(center + radius, center - radius);
            topRightCircle.setCenter(point);
            topRightCircle.setRadius(radius);

            point = new Point(center - radius, center + radius);
            bottomLeftCircle.setCenter(point);
            bottomLeftCircle.setRadius(radius);

            point = new Point(center + radius, center + radius);
            bottomRightCircle.setCenter(point);
            bottomRightCircle.setRadius(radius);
        }

        public void draw(Graphics g) {
            topLeftCircle.draw(g);
            topRightCircle.draw(g);
            bottomLeftCircle.draw(g);
            bottomRightCircle.draw(g);

            drawLines(g);
        }

        private void drawLines(Graphics g) {
            Point start = topLeftCircle.getTopPoint();
            Point end = topRightCircle.getTopPoint();
            g.drawLine(start.x, start.y, end.x, end.y);

            start = topRightCircle.getRightPoint();
            end = bottomRightCircle.getRightPoint();
            g.drawLine(start.x, start.y, end.x, end.y);

            start = bottomRightCircle.getBottomPoint();
            end = bottomLeftCircle.getBottomPoint();
            g.drawLine(start.x, start.y, end.x, end.y);

            start = bottomLeftCircle.getLeftPoint();
            end = topLeftCircle.getLeftPoint();
            g.drawLine(start.x, start.y, end.x, end.y);
        }
    }

    public class Circle {

        private int radius;

        private Point center;

        public int getRadius() {
            return radius;
        }

        public void setRadius(int radius) {
            this.radius = radius;
        }

        public Point getCenter() {
            return center;
        }

        public void setCenter(Point center) {
            this.center = center;
        }

        public Point getTopPoint() {
            int x = getCenter().x;
            int y = getCenter().y - getRadius();
            return new Point(x, y);
        }

        public Point getRightPoint() {
            int x = getCenter().x + getRadius();
            int y = getCenter().y;
            return new Point(x, y);
        }

        public Point getBottomPoint() {
            int x = getCenter().x;
            int y = getCenter().y + getRadius();
            return new Point(x, y);
        }

        public Point getLeftPoint() {
            int x = getCenter().x - getRadius();
            int y = getCenter().y;
            return new Point(x, y);
        }

        public void draw(Graphics g) {
            int diameter = getRadius() + getRadius();
            int x = getCenter().x - getRadius();
            int y = getCenter().y - getRadius();
            g.drawOval(x, y, diameter, diameter);
        }

    }

}

Upvotes: 2

Related Questions