Java : 部分填充圆圈并在其中放置百分比数字
Java : fill circle partially and put percentage number inside it
我们如何部分地(例如从底部到顶部)填充绘制的圆(或任何其他形状)?
以及如何将百分比的数字放在这个圆圈内?
这是一个预览,但适用于 Android 环境:Draw a circle partially filled dynamically
绘制轮廓,然后添加裁剪并在其上绘制填充版本,然后在其上绘制百分比字符串。
import java.text.NumberFormat;
import java.util.Objects;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.FontMetrics;
import java.awt.Dimension;
import java.awt.Shape;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class ShapeFiller
extends JPanel {
private static final long serialVersionUID = 1;
private final Shape shape;
private final Timer fillTimer;
private float percentageFilled;
private final NumberFormat percentageFormat;
private final Rectangle textBounds = new Rectangle();
private final Rectangle iconBounds = new Rectangle();
public ShapeFiller(Shape shape) {
this(shape, 250);
}
public ShapeFiller(Shape shape,
int fillDelayMillis) {
this.shape = Objects.requireNonNull(shape, "Shape cannot be null");
this.percentageFormat = NumberFormat.getPercentInstance();
this.fillTimer = new Timer(Math.max(50, fillDelayMillis),
new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
incrementPercentage();
}
});
setFont(getFont().deriveFont(getFont().getSize2D() * 4));
}
@Override
public Dimension getPreferredSize() {
Rectangle bounds = shape.getBounds();
bounds.add(0, 0);
return bounds.getSize();
}
@Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D g = (Graphics2D) graphics;
g.draw(shape);
// Fill shape
Shape originalClip = g.getClip();
Rectangle bounds = shape.getBounds();
int clipHeight = (int) (bounds.height * percentageFilled);
g.clip(new Rectangle(0, bounds.y + bounds.height - clipHeight,
getWidth(), clipHeight));
g.fill(shape);
g.setClip(originalClip);
// Draw percentage
String text = percentageFormat.format(percentageFilled);
TextLayout layout =
new TextLayout(text, g.getFont(), g.getFontRenderContext());
FontMetrics metrics = g.getFontMetrics();
iconBounds.setBounds(0, 0, 0, 0);
textBounds.setBounds(0, 0, 0, 0);
SwingUtilities.layoutCompoundLabel(this,
metrics, text, null,
SwingConstants.CENTER, SwingConstants.CENTER,
SwingConstants.CENTER, SwingConstants.CENTER,
bounds, iconBounds, textBounds, 0);
int textX = textBounds.x;
int textY = textBounds.y + metrics.getAscent();
Paint originalPaint = g.getPaint();
g.setPaint(getBackground());
layout.draw(g, textX, textY);
g.setPaint(originalPaint);
// Draw percentage outline
AffineTransform textPos =
AffineTransform.getTranslateInstance(textX, textY);
g.draw(layout.getOutline(textPos));
}
public void setPercentageDone(float percentage) {
if (Float.isNaN(percentage) || Float.isInfinite(percentage)) {
throw new IllegalArgumentException("Percentage must be finite");
}
percentageFilled = Math.max(0, Math.min(1, percentage));
repaint();
}
public void startFilling() {
percentageFilled = 0;
fillTimer.restart();
}
private void incrementPercentage() {
setPercentageDone(percentageFilled + 0.01f);
if (percentageFilled >= 1) {
fillTimer.stop();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Shape shape = new Ellipse2D.Float(50, 50, 200, 200);
ShapeFiller shapeFiller = new ShapeFiller(shape);
shapeFiller.startFilling();
JOptionPane.showMessageDialog(null, shapeFiller);
System.exit(0);
}
});
}
}
我们如何部分地(例如从底部到顶部)填充绘制的圆(或任何其他形状)?
以及如何将百分比的数字放在这个圆圈内?
这是一个预览,但适用于 Android 环境:Draw a circle partially filled dynamically
绘制轮廓,然后添加裁剪并在其上绘制填充版本,然后在其上绘制百分比字符串。
import java.text.NumberFormat;
import java.util.Objects;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.FontMetrics;
import java.awt.Dimension;
import java.awt.Shape;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class ShapeFiller
extends JPanel {
private static final long serialVersionUID = 1;
private final Shape shape;
private final Timer fillTimer;
private float percentageFilled;
private final NumberFormat percentageFormat;
private final Rectangle textBounds = new Rectangle();
private final Rectangle iconBounds = new Rectangle();
public ShapeFiller(Shape shape) {
this(shape, 250);
}
public ShapeFiller(Shape shape,
int fillDelayMillis) {
this.shape = Objects.requireNonNull(shape, "Shape cannot be null");
this.percentageFormat = NumberFormat.getPercentInstance();
this.fillTimer = new Timer(Math.max(50, fillDelayMillis),
new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
incrementPercentage();
}
});
setFont(getFont().deriveFont(getFont().getSize2D() * 4));
}
@Override
public Dimension getPreferredSize() {
Rectangle bounds = shape.getBounds();
bounds.add(0, 0);
return bounds.getSize();
}
@Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D g = (Graphics2D) graphics;
g.draw(shape);
// Fill shape
Shape originalClip = g.getClip();
Rectangle bounds = shape.getBounds();
int clipHeight = (int) (bounds.height * percentageFilled);
g.clip(new Rectangle(0, bounds.y + bounds.height - clipHeight,
getWidth(), clipHeight));
g.fill(shape);
g.setClip(originalClip);
// Draw percentage
String text = percentageFormat.format(percentageFilled);
TextLayout layout =
new TextLayout(text, g.getFont(), g.getFontRenderContext());
FontMetrics metrics = g.getFontMetrics();
iconBounds.setBounds(0, 0, 0, 0);
textBounds.setBounds(0, 0, 0, 0);
SwingUtilities.layoutCompoundLabel(this,
metrics, text, null,
SwingConstants.CENTER, SwingConstants.CENTER,
SwingConstants.CENTER, SwingConstants.CENTER,
bounds, iconBounds, textBounds, 0);
int textX = textBounds.x;
int textY = textBounds.y + metrics.getAscent();
Paint originalPaint = g.getPaint();
g.setPaint(getBackground());
layout.draw(g, textX, textY);
g.setPaint(originalPaint);
// Draw percentage outline
AffineTransform textPos =
AffineTransform.getTranslateInstance(textX, textY);
g.draw(layout.getOutline(textPos));
}
public void setPercentageDone(float percentage) {
if (Float.isNaN(percentage) || Float.isInfinite(percentage)) {
throw new IllegalArgumentException("Percentage must be finite");
}
percentageFilled = Math.max(0, Math.min(1, percentage));
repaint();
}
public void startFilling() {
percentageFilled = 0;
fillTimer.restart();
}
private void incrementPercentage() {
setPercentageDone(percentageFilled + 0.01f);
if (percentageFilled >= 1) {
fillTimer.stop();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Shape shape = new Ellipse2D.Float(50, 50, 200, 200);
ShapeFiller shapeFiller = new ShapeFiller(shape);
shapeFiller.startFilling();
JOptionPane.showMessageDialog(null, shapeFiller);
System.exit(0);
}
});
}
}