如何正确对齐此文本?

发布于 2024-11-13 05:58:19 字数 6350 浏览 1 评论 0原文

我今天写了这个极地时钟,我几乎完成了,除了我想在类似于 this。有谁知道该怎么做?我尝试使用 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 < vars.length; i++)
        vars[i] = 0;

    // Game loop.
    while (true) {
        long now = System.nanoTime();
        acc += now - lastTime;
        tick++;
        if (acc >= 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 < vars.length; i++) {
            if (tvars[i] - vars[i] > 1) {
                vars[i] += (tvars[i] - vars[i]) / 15;
            } else if(tvars[i] - vars[i] < -1) {
                vars[i] -= (vars[i] - tvars[i]) / 15;
            } else {
                vars[i] = tvars[i];
            }
        }

        names[0] = second + " Second" + (second > 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]);
    }
}

}

I wrote this polar clock today and i am almost finished exept i want to align my text inside the line similar to this. Does anyone know how to do this? Ive tried to use FontRenderContext and font metrics but i cant seem to get it to work. Here is the whole source code so you can compile it and see for yourselves.

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 < vars.length; i++)
        vars[i] = 0;

    // Game loop.
    while (true) {
        long now = System.nanoTime();
        acc += now - lastTime;
        tick++;
        if (acc >= 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 < vars.length; i++) {
            if (tvars[i] - vars[i] > 1) {
                vars[i] += (tvars[i] - vars[i]) / 15;
            } else if(tvars[i] - vars[i] < -1) {
                vars[i] -= (vars[i] - tvars[i]) / 15;
            } else {
                vars[i] = tvars[i];
            }
        }

        names[0] = second + " Second" + (second > 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]);
    }
}

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北方的韩爷 2024-11-20 05:58:19

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

附录:您需要通过 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);
            }
        });
    }
}

Here's a simple example of rotating text.

Addendum: You'll want to adjust the the text's radial starting point by stringWidth(name[n]). Your program appears to be rotating individual characters in a effort to follow the arc, while the example appears to be drawing the text in a straight line tangent to the arc. The latter approach may prove simpler. For example, this variation centers the labels across the arc's 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);
}

enter image description here

For convenience the code above does rotate() to and fro; for comparison, here's the original example showing repeated concatenations of rotate():

enter image description here

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);
            }
        });
    }
}
怪我入戏太深 2024-11-20 05:58:19

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

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

You have to be able to draw text along the curves. There are several ways to do it, but the simplest one is to use Stroke API. You can find an example at http://www.jhlabs.com/java/java2d/strokes/

The other way is using affine transforms. The example is at http://www.java2s.com/Code/Java/2D-Graphics-GUI/Drawtextalongacurve.htm

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文