Thornack
Thornack

Reputation: 71

Subtracting an inner radius/portion of an arc to achieve a ring style progress bar

I am trying to draw a ring/partial ring using arc's.

But I need the middle of the partial ring/ring to be transparent and show whats behind it. Since I am using an arc and spinning it, is there a way to subtract away the inner portion of each arc and leave only the end at the desired thickness which will be spun to create the ring?

This is my code so far: I have the arcs working, but I am only simulating the ring by layering over each one with a couple circles, I need to actually subtract out the area of each circle from each arc.

Not sure how to do that to achieve transparency in the center. If there is a better way to do this please let me know, this is going to be a custom progress bar.

public class JCustomProgressBar extends JComponent{

private final Dimension SIZE = new Dimension( 50, 50 );

public JCustomProgressBar() {
    super();
    this.setVisible(true);
    System.out.println("CAlled");

}

int progress = 1;

public void updateProgress (int progress){
    this.progress = progress;
}


 @Override
 public void paintComponent (Graphics g){
   super.paintComponent(g);
   System.out.println("called");
   Graphics2D g2D = (Graphics2D) g.create();
   g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

   g2D.translate(this.getWidth()/2, this.getHeight()/2);
   g2D.rotate(Math.toRadians(270));
   Arc2D.Float arc = new Arc2D.Float (Arc2D.PIE);
   Ellipse2D circle = new Ellipse2D.Float(0, 0, 80, 80);
   arc.setFrameFromCenter (new Point(0,0), new Point (90, 90));
   circle.setFrameFromCenter(new Point(0,0), new Point (80, 80));
   arc.setAngleExtent(-progress*360/100);
   g2D.setColor(new Color(120,192,0));
   g2D.draw(arc);
   g2D.fill(arc);

   g2D.setColor(this.getParent().getBackground());
   g2D.draw(circle);
   g2D.fill(circle);

   arc.setFrameFromCenter (new Point(0,0), new Point (75, 75));
   arc.setAngleExtent(-90*360/100);
   g2D.setColor(new Color(197,228,146));
   g2D.draw(arc);
   g2D.fill(arc);

   circle.setFrameFromCenter(new Point(0,0), new Point (70, 70));
   g2D.setColor(this.getParent().getBackground());
   g2D.draw(circle);
   g2D.fill(circle);

   circle.setFrameFromCenter(new Point(0,0), new Point (60, 60));
   g2D.setColor(new Color(245, 245, 245));
   g2D.draw(circle);
   g2D.fill(circle);



   g2D.setColor(Color.black);
   g2D.rotate(Math.toRadians(90));
   g2D.setFont(new Font("Verdana", Font.PLAIN, 30));
   FontMetrics fm = g2D.getFontMetrics();
   Rectangle2D r2D = fm.getStringBounds(progress + "%", g);
   int x = (0 - (int) r2D.getWidth())/2;
   int y = (0 - (int) r2D.getHeight())/2 +fm.getAscent();
   g2D.drawString(progress + "%", x, y-10);

  //Rectangle2D r2d = fm.getStringBounds(progress + "", g);
  // g2D.setFont(new Font("Verdana", Font.PLAIN, 22));
  // g2D.drawString("%", x + 40, y-10);

   g2D.setFont(new Font("Verdana", Font.PLAIN, 15));
   g2D.drawString("Progress", -35, y+5);
   g2D.dispose();

}

}

Upvotes: 1

Views: 301

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347314

There are a number of ways you "might" do this, but the simplest might be to just use BasicStroke and simply draw the arcs (and not fill anything at all)

This example deliberately sets the background color so you can see that it's transparent.

Stroked

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Arc2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

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

                JCustomProgressBar pb = new JCustomProgressBar();
                pb.setProgress(25);

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

    public class JCustomProgressBar extends JPanel {

        private final Dimension SIZE = new Dimension(200, 200);

        public JCustomProgressBar() {
            super();
            setBackground(Color.RED);
            // Uncomment this to make it transparent
            //setOpaque(false);
        }

        @Override
        public Dimension getPreferredSize() {
            return SIZE;
        }

        int progress = 1;

        public void setProgress(int progress) {
            this.progress = progress;
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2D = (Graphics2D) g.create();
            g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            g2D.translate(this.getWidth() / 2, this.getHeight() / 2);

            BasicStroke bs = new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
            Arc2D.Float arc = new Arc2D.Float(Arc2D.OPEN);
            arc.setAngleStart(90);
            arc.setFrameFromCenter(new Point(0, 0), new Point(90, 90));
            arc.setAngleExtent(-((progress / 100d) * 360));
            g2D.setStroke(bs);
            g2D.setColor(new Color(120, 192, 0));
            g2D.draw(arc);

            bs = new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
            arc.setFrameFromCenter(new Point(0, 0), new Point(75, 75));
            arc.setAngleExtent(-(((100 - progress) / 100d) * 360));
            g2D.setStroke(bs);
            g2D.setColor(new Color(197, 228, 146));
            g2D.draw(arc);

            g2D.setColor(Color.black);
            g2D.setFont(new Font("Verdana", Font.PLAIN, 30));
            FontMetrics fm = g2D.getFontMetrics();
            Rectangle2D r2D = fm.getStringBounds(progress + "%", g);
            int x = (0 - (int) r2D.getWidth()) / 2;
            int y = (0 - (int) r2D.getHeight()) / 2 + fm.getAscent();
            g2D.drawString(progress + "%", x, y - 10);

            g2D.setFont(new Font("Verdana", Font.PLAIN, 15));
            g2D.drawString("Progress", -35, y + 5);
            g2D.dispose();
        }

    }

}

You can take a look at Stroking and Filling Graphics Primitives for more details.

Before you tell me how you "don't want the ends rounded" (because I like it that way), make sure you take the time to read the BasicStroke JavaDocs

Upvotes: 2

Related Questions