如何正确对齐此文本?

我今天写了这个极地时钟,我几乎完成了我想要将我的文字对齐在类似于此的行内。 有谁知道如何做到这一点? 我曾尝试使用FontRenderContext和字体指标,但我似乎无法让它工作。 这是完整的源代码,因此您可以编译它并自己查看。

import java.applet.Applet; import java.awt.AWTEvent; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.Arc2D; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.util.Calendar; import java.util.TimeZone; public class Clock extends Applet implements Runnable { int[][] colorsInt = {{20,20,20},{100,100,50},{50,100,100},{10,170,50},{79,29,245},{24,69,234},{253,24,103}}; Color[] colors; int size; int radius; boolean anitalias = false; static final float HPI = (float)(Math.PI / 180f); public void start() { enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); new Thread(this).start(); } public void run() { setSize(500, 500); // For AppletViewer, remove later. // Set up the graphics stuff, double-buffering. BufferedImage screen = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB); Graphics2D g = (Graphics2D)screen.getGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); WritableRaster wr = screen.getRaster(); Graphics appletGraphics = getGraphics(); // Some variables to use for the fps. long fpstn = 1000000000 / 600; int tick = 0, fps = 0, acc = 0; long lastTime = System.nanoTime(); // Vars Calendar c; size = 500; radius = size / 2; Arc2D.Float arch; float scale, radians; long miliSecond; int second, minute, hour, month, year, dayOfWeek, dayOfMonth, dayOfYear, daysInMonth, daysInYear; float[] tvars = new float[6]; float[] vars = new float[6]; String[] names = new String[6]; FontMetrics fm = g.getFontMetrics(); Font font = g.getFont(); FontRenderContext frc = g.getFontRenderContext(); GlyphVector gv = font.createGlyphVector(frc, "Hello world"); int length = gv.getNumGlyphs(); // Init initColors(); for (int i = 0; i = 1000000000L) { acc -= 1000000000L; fps = tick; tick = 0; } // Update c = Calendar.getInstance(); miliSecond = c.get(Calendar.MILLISECOND); second = c.get(Calendar.SECOND); minute = c.get(Calendar.MINUTE); hour = c.get(Calendar.HOUR_OF_DAY); dayOfMonth = c.get(Calendar.DAY_OF_MONTH); dayOfYear = c.get(Calendar.DAY_OF_YEAR); dayOfWeek = c.get(Calendar.DAY_OF_WEEK); month = c.get(Calendar.MONTH); daysInMonth = c.getActualMaximum(Calendar.DAY_OF_MONTH); daysInYear = c.getActualMaximum(Calendar.DAY_OF_YEAR); tvars[0] = (second * 1000 + miliSecond) / 60000f * 360f; tvars[1] = (minute * 60f + second) / 3600f * 360f; tvars[2] = (hour * 60f + minute) / 1440f * 360f; tvars[3] = ((dayOfWeek - 2) * 24f + hour) / 168f * 360f; tvars[4] = ((dayOfMonth - 1) * 24f + hour) / (daysInMonth * 24f) * 360f; tvars[5] = dayOfYear / (float)daysInYear * 360f; for (int i = 0; i  1) { vars[i] += (tvars[i] - vars[i]) / 15; } else if(tvars[i] - vars[i]  1 ? "s" : ""); lastTime = now; // Render g.setColor(colors[0]); g.fillRect(0, 0, size, size); for (int i = 0; i < vars.length; i++) { scale = i / (float)vars.length * radius * 1.7f; g.setColor(colors[0]); g.fillOval((int)(scale / 2), (int)(scale / 2), (int)(size - scale), (int)(size - scale)); g.setColor(colors[i + 1]); scale += 15; arch = new Arc2D.Float(scale / 2, scale / 2, size - scale, size - scale, 450 - vars[i], vars[i], Arc2D.PIE); g.fill(arch); g.setColor(Color.WHITE); radians = (vars[i]) * HPI;// vars[i] - 90 scale = ((float)(vars.length - i) / (float)vars.length * (float)radius / 2f * 1.7f) + 15f; g.translate(radius, radius); System.out.println(i + ": " + ((1 - scale / radius) * 2)); for (int j = 0; j < names[0].length(); j++) { char ch = names[0].charAt(j); radians = ((vars[i] - (names[0].length() - j) * 2) * (1 + (1 - scale / radius) * 2)) * HPI; g.rotate(radians); g.drawString(ch + "", 0, -scale); g.rotate(-radians); } g.translate(-radius, -radius); /*float x = (float)Math.cos(radians) * scale; float y = (float)Math.sin(radians) * (vars.length - i) / vars.length * radius / 2 * 1.7f; g.drawRect((int)x + size / 2, (int)y + size / 2, 10, 10);*/ } scale = vars.length / (float)vars.length * radius * 1.7f; g.setColor(colors[0]); g.fillOval((int)(scale / 2), (int)(scale / 2), (int)(size - scale), (int)(size - scale)); g.setColor(Color.WHITE); g.drawString("FPS " + String.valueOf(fps), 20, 30); // Draw the entire results on the screen. appletGraphics.drawImage(screen, 0, 0, null); do { Thread.yield(); } while (System.nanoTime() - lastTime < 0); if (!isActive()) { return; } } } public void initColors() { colors = new Color[colorsInt.length]; for (int i = 0; i < colors.length; i++) { colors[i] = new Color(colorsInt[i][0], colorsInt[i][1], colorsInt[i][2]); } } } 

这是旋转文本的简单示例。

附录:您需要通过stringWidth(name[n])调整文本的径向起点。 您的程序似乎正在旋转单个字符以努力跟随圆弧,而示例似乎是在与圆弧相切的直线上绘制文本。 后一种方法可能更简单。 例如,此变体将标签集中在弧的getStartPoint()

 for (int i = 0; i < vars.length; i++) { ... String s = names[0]; int w = fm.stringWidth(s); int h = fm.getHeight() + fm.getMaxDescent(); Point2D p = arch.getStartPoint(); int x = (int) p.getX(); int y = (int) p.getY(); radians = (vars[i]) * HPI; g.rotate(radians, x, y); g.drawString(s, x - w / 2, y + h); g.rotate(-radians, x, y); } 

在此处输入图像描述

为方便起见,上面的代码来回rotate() ; 为了比较,这是显示rotate()重复连接的原始示例:

在此处输入图像描述

 import java.awt.*; import java.awt.geom.AffineTransform; import javax.swing.*; /** @see http://stackoverflow.com/questions/6238037 */ public class RotateText extends JPanel { private static final Font f = new Font("Serif", Font.BOLD, 32); private static final String s = "Hello World!"; private static final Color[] colors = { Color.red, Color.green, Color.blue, Color.cyan }; private Graphics2D g2d; private AffineTransform at; public RotateText() { setPreferredSize(new Dimension(400, 400)); } @Override public void paintComponent(Graphics g) { g2d = (Graphics2D) g; g2d.setFont(f); g2d.setColor(Color.black); g2d.fillRect(0, 0, getWidth(), getHeight()); at = g2d.getTransform(); int w = this.getWidth(); int h = this.getHeight(); int w2 = g2d.getFontMetrics().stringWidth(s) / 2; int h2 = 2 * g2d.getFontMetrics().getHeight() / 3; render(0, w / 2 - w2, h - h2); render(1, h2, h / 2 - w2); render(2, w / 2 + w2, h2); render(3, w - h2, h / 2 + w2); g2d.setTransform(at); g2d.setColor(Color.yellow); g2d.fillRect(w / 3, h / 3, w / 3, h / 3); } private void render(int n, int x, int y) { g2d.setColor(colors[n]); g2d.setTransform(at); g2d.rotate(n * Math.PI / 2, x, y); g2d.drawString(s, x, y); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { //@Override public void run() { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(new RotateText(), BorderLayout.CENTER); f.pack(); f.setVisible(true); } }); } } 

您必须能够沿曲线绘制文本。 有几种方法可以做到,但最简单的方法是使用Stroke API 。 您可以在http://www.jhlabs.com/java/java2d/strokes/找到示例。

另一种方式是使用仿射变换。 该示例位于http://www.java2s.com/Code/Java/2D-Graphics-GUI/Drawtextalongacurve.htm