3

I tried to plot a circle using the java awt, what I get in output is just few small which are separated by much distance apart and doesn't look like a circle as a whole. Code is given below :

class DrawFrame extends JFrame {
    int хс, yc, r, x, y;
    float p;
    DrawFrame(int rr, int c1, int c2) {
        setSize(1000, 1000);
        setTitle("circle drawing algo");
        r = rr;
        xc = c1;
        yc = c2;
    }
    public void paint(Graphics g) {
        Circl(g);
    }
    public void Circl(Graphics g) {
        x = xc - r;
        while (x <= (xc + r)) {
            for (y = yc - r; y <= (yc + r); y++) {
                p = x * x + y * y - r * r;
                if (p == 0.0)
                    g.drawOval(x, y, 2, 2);
            }
            x++;
        }
    }
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • Have you tried increasing the size of the oval? Right now you're drawing them 3 pixels by 3 pixels. https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html#drawOval(int,%20int,%20int,%20int) – Harvtronix Feb 01 '19 at 03:15
  • As as aside, are you aware of [`Graphics.drawOval(int,int,int,int)`](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Graphics.html#drawOval(int,int,int,int))? – Andrew Thompson Feb 01 '19 at 04:39
  • You need to make the JFrame visible ` setVisible(true);` Also see [Java naming conventions](https://www.geeksforgeeks.org/java-naming-conventions/) – c0der Feb 01 '19 at 05:01
  • That’s not how custom painting works – MadProgrammer Feb 01 '19 at 05:09

4 Answers4

2

You should start by having a read of Performing Custom Painting and Painting in AWT and Swing to get a better understanding of how the painting system works and how you should work with it.

You shouldn't override the paint method of top level components, apart from not been double buffered, they are actually compound components. This means that they have a number of additional components laid out on top of them which provide the overall functionality of the window.

JRootPane and it's many layers

This means that it's possible for what you've painted to the surface of the frame to be ignored, as the content on top of it paints over it.

You're also ignoring the complexity of the painting process, unless you're prepared to take over the responsibility of the paint method yourself, you should always call its super method.

A better place to start is with a JPanel (which is simpler) and override its paintComponent method

Example

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane(100, 100, 100));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        int xc, yc, r;

        public TestPane(int rr, int c1, int c2) {
            r = rr;
            xc = c1;
            yc = c2;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(r * 2, r * 2);
        }

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

        public void circle(Graphics g) {
            // Credit to LAD for the algorithm updates
            int x = xc - r;
            while (x <= (xc + r)) {
                for (int y = yc - r; y <= (yc + r); y++) {
                    float p = (x - xc) * (x - xc) + (y - yc) * (y - yc) - (r * r);
                    if (p <= 0.0f)
                    {
                        g.drawOval(x, y, 2, 2);
                    }
                }
                x++;
            }


        }
    }

}

Credit to LAD for the algorithm updates

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

The first thing to change is to make JFrame visible by adding setVisible(true); to its constructor.
It is recommended to use names that have a clear meaning to make the code more readable. Make the fields scope as limited as possible, in this case make them private:

private int сenterX, centerY, radius; 

(x,y and p are method variables and do not need to be fields )
Avoid using magic numbers. Use constants instead:

private static final int W = 1000, H = 1000, DOT_SIZE =2 ;

Putting it together, using correct Java naming conventions and fixing the algorithm:

import java.awt.Graphics; //add imports to make tour code mcve
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

class DrawFrame extends JFrame {

    private final int сenterX, centerY, radius;
    private static final int W = 1000, H = 1000, DOT_SIZE =2 ;

    DrawFrame(int radius, int centerX, int centerY) {
        setSize(W, H);
        setTitle("circle drawing algo");
        this.radius = radius;
        сenterX = centerX;
        this.centerY = centerY;
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//make program stop when closing frame
        setVisible(true); //make frame visible
    }

    @Override
    public void paint(Graphics g) {
       super.paint(g); 
       circl(g);
    }

    public void circl(Graphics g) {
        int x, y;
        x = сenterX - radius;
        while (x <= сenterX + radius) {
           //calculate x 
           y = (int)Math.sqrt(radius*radius - (сenterX -x)*(сenterX -x ));
           g.drawOval(x, centerY-y, 2, 2); // 2 y values for every x 
           g.drawOval(x, centerY+y, 2, 2);
           x++;
       }
    }

    // add main to make your code mcve 
    public static void main(String[] args) {
        SwingUtilities.invokeLater(()-> new DrawFrame(100, 400, 400));
    }
}

The next improvement could be to refactor so the painting is done on a JPanel rather than on the JFrame itself, using Graphics.drawOval:

class DrawFrame extends JFrame {

    DrawFrame(int radius, int centerX, int centerY) {
        setTitle("circle drawing algo");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//make program stop when closing frame
        add(new DrawingPane(radius, centerX, centerY));
        pack();
        setVisible(true); //make frame visible
    }

    // add main to make your code mcve
    public static void main(String[] args) {
        SwingUtilities.invokeLater(()-> new DrawFrame(100, 400, 400));
    }
}

class DrawingPane extends JPanel{

    private final int сenterX, centerY, radius;
    private static final int W = 1000, H = 1000, DOT_SIZE =2 ;

    DrawingPane(int radius, int centerX, int centerY) {
        setPreferredSize(new Dimension(W, H));
        this.radius = radius;
        сenterX = centerX;
        this.centerY = centerY;
    }

    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawOval(сenterX, centerY, radius, radius);
    }
}
c0der
  • 18,467
  • 6
  • 33
  • 65
0

I edited your code a bit and changed the draw algorithm a little in order to completely draw the circle. Here is the refactored code:

class DrawFrame extends JFrame {
    int xc, yc, r, x, y;
    float p;
    DrawFrame(int rr, int c1, int c2) {
        setSize(1000, 1000);
        setTitle("circle drawing algo");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Handles the window being closed
        setVisible(true); // Makes the window visible
        r = rr;
        xc = c1;
        yc = c2;
    }
    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D)g;
        GradientPaint gp = new GradientPaint(0f,0f,Color.blue,0f,30f,Color.green); // Just sets a color for the paint
        g2.setPaint(gp);
        Circl(g2); 
    }
    public void Circl(Graphics g) {
        x = xc-r;
        while (x <= (xc+r)) {
            for (y = yc-r; y <= (yc+r); y++) {
                p = (x-xc)*(x-xc)+(y-yc)*(y-yc)-(r*r); // Edited this line so that it’s now the correct circle formula
                if (p <= 0.0f) // If the point is 0 or less, then the point is within the circle bounds
                    g.drawOval(x, y, 2, 2);
            }
            x++;
        }
    }
    public static void main(String[] args) {
        new DrawFrame(100, 500, 500);
    }
}

The code is a bit slow, though, as the drawOval method seems to be quite slow when called a bunch of times. So, this code is mainly suited for the algorithm aspect, as you could easily fill out an oval by calling the following once:

g.drawOval(x, y, 200, 200);
g.fillOval(x, y, 200, 200);
0xCursor
  • 2,242
  • 4
  • 15
  • 33
0

You set initial value of x as x = xc - r, y as y = yc - r. And converting Cartesian to Polar coordinate like p = x * x + y * y - r * r . Assume that if xc=500, and yc=500, r=50, "p" will never be 0. So I think you forgot to calculate xc, yc when you draw. I modified your code little bit and attached the result.

package testProject;
import java.awt.*;
import javax.swing.*;

public class DrawFrame extends JPanel {
    int xc=500, yc=500, r=150, x, y;
    int real_x, real_y;
    float p;

    public static void main(String[] args) {
        JFrame.setDefaultLookAndFeelDecorated(true);
        JFrame frame = new JFrame("circle drawing algo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBackground(Color.white);
        frame.setSize(1000, 1000);
        DrawFrame panel = new DrawFrame();
        frame.add(panel);
        frame.setVisible(true);
    }



    public void paint(Graphics g) {
        Circl(g);
    }
    public void Circl(Graphics g) {
        x = -r;
        while (x <= r) {
            y = -r;
            while (y <= r) {
                p = x * x + y * y - r * r;
                // here is the change
                if (p>=0 && p<= xc) {
                    g.drawOval(x+xc, y+yc, 3, 3);
                }
                y++;
            }
            x++;
        }
    }
}

Result