如何正确对齐此文本?

2024-01-07

我今天写了这个极地时钟,我几乎完成了,除了我想在行内对齐我的文本,类似于this http://blog.pixelbreaker.com/polarclock。有谁知道如何做到这一点?我尝试使用 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]);
    }
}

}

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

附录:您需要调整文本的径向起点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);
            }
        });
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何正确对齐此文本? 的相关文章

  • 当路径的点超出视野时,Android Canvas 不会绘制路径

    我在绘制路径时遇到了 Android Canvas 的一些问题 我的情况是 我有一个相对布局工作 如地图视图 不使用 google api 或类似的东西 我必须在该视图上绘制一条路径 canvas drawPath polyPath bor
  • 将SQL数据引入jquery availabletag

    我正在尝试制作自动完成文本框 但如何将 SQL 数据包含到 jquery 可用标记并循环它 我无法根据以下代码执行该功能 任何帮助 将不胜感激 谢谢 这是我的预期输出 预期结果演示 http jsfiddle net VvETA 71 jq
  • 文本在指定长度后分割,但不要使用 grails 打断单词

    我有一个长字符串 需要将其解析为长度不超过 50 个字符的字符串数组 对我来说 棘手的部分是确保正则表达式找到 50 个字符之前的最后一个空格 以便在字符串之间进行彻底的分隔 因为我不希望单词被切断 public List
  • 删除优先级队列的尾部元素

    如何删除优先级队列的尾部元素 我正在尝试使用优先级队列实现波束搜索 一旦优先级队列已满 我想删除最后一个元素 优先级最低的元素 Thanks 没有简单的方法 将元素从原始元素复制到新元素 最后一个除外 PriorityQueue remov
  • 为自定义驱动程序创建 GraphicsDevice

    我正在开发一个在嵌入式系统中使用 Java 的项目 我有用于屏幕和触摸输入的驱动程序 以及用于文本输入的虚拟键盘 我的屏幕驱动程序有一个Graphics2D您可以绘制的对象和repaint Rectangle 更新方法 类似地 触摸驱动器能
  • Spring数据中的本机查询连接

    我有课 Entity public class User Id Long id String name ManyToMany List
  • 是否可以从 servlet 内部以编程方式设置请求上下文路径?

    这是一个特殊情况 我陷入了处理 企业 网络应用程序的困境 企业应用程序正在调用request getContext 并将其与另一个字符串进行比较 我发现我可以使用 getServletContext getContextPath 获取 se
  • Eclipse - 安装新的 JRE (Java SE 8 1.8.0)

    我正在尝试安装 Java 8 到目前为止我所做的 安装最新版本的 Eclipse 下载并安装 Java SE 运行时环境 8http www oracle com technetwork java javase downloads jre8
  • Java、Spring:使用 Mockito 测试 DAO 的 DataAccessException

    我正在尝试增加测试覆盖率 所以我想知道 您将如何测试 DAO 中抛出的 DataAccessExceptions 例如在一个简单的 findAll 方法中 该方法仅返回数据源中的所有数据 就我而言 我使用 Spring JdbcTempla
  • Spring Data JPA:查询如何返回非实体对象或对象列表?

    我在我的项目中使用 Spring Data JPA 我正在演奏数百万张唱片 我有一个要求 我必须获取各种表的数据并构建一个对象 然后将其绘制在 UI 上 现在如何实现我的 Spring 数据存储库 我读到它可以通过命名本机查询来实现 如果指
  • 如何从日期中删除毫秒、秒、分钟和小时[重复]

    这个问题在这里已经有答案了 我遇到了一个问题 我想比较两个日期 然而 我只想比较年 月 日 这就是我能想到的 private Date trim Date date Calendar calendar Calendar getInstanc
  • 我们如何测试包私有类?

    我正在看书Effective Java in Item 13 Minimize the accessibility of classes and members 它提到 为了方便测试 您可能想让类 接口或成员更易于访问 这在某种程度上是好的
  • 寻找局部最小值

    下面的代码正确地找到了数组的局部最大值 但未能找到局部最小值 我已经进行了网络搜索 以找到找到最小值的最佳方法 并且根据这些搜索 我认为我正在使用下面的正确方法 但是 在几天的时间里多次检查每一行之后 下面的代码中有一些我仍然没有看到的错误
  • 如何停止执行的 Jar 文件

    这感觉像是一个愚蠢的问题 但我似乎无法弄清楚 当我在 Windows 上运行 jar 文件时 它不会出现在任务管理器进程中 我怎样才能终止它 我已经尝试过 TASKKILL 但它对我也不起作用 On Linux ps ef grep jav
  • 旋转 GPUImageTiltShiftFilter - GPUImage

    我想要一个非水平 GPUImageTiltShiftFilter 旋转 我想将其旋转到任意旋转角度 我还希望过滤器速度快 可以通过带有 UIRotationGestureRecongizer 的 UI 进行旋转 我该怎么做呢 啊 想通了 不
  • Java - 从 XML 文件读取注释

    我必须从 XML 文件中提取注释 我找不到使用 JDOM 或其他东西来让它们使用的方法 目前我使用 Regex 和 FileReader 但我不认为这是正确的方法 您可以使用 JDOM 之类的东西从 XML 文件中获取注释吗 或者它仅限于元
  • 无需登录即可直接从 Alfresco 访问文件/内容

    我的场景是这样的 我有一个使用 ALFRESCO CMS 来显示文件或图像的 Web 应用程序 我正在做的是在 Java servlet 中使用用户名和密码登录 alfresco 并且我可以获得该登录的票证 但我无法使用该票证直接从浏览器访
  • 使用 Java https 上传到 Imgur v3 错误

    我目前正在尝试使用他们当前的 API v3 上传到 imgur 但是我不断收到错误 错误 javax net ssl SSLException 证书中的主机名不匹配 api imgur com imgur com OR imgur com
  • ArrayList.clear() 和 ArrayList.removeAll() 有什么区别?

    假如说arraylist定义为ArrayList
  • 将对象从手机共享到 Android Wear

    我创建了一个应用程序 在此应用程序中 您拥有包含 2 个字符串 姓名和年龄 和一个位图 头像 的对象 所有内容都保存到 sqlite 数据库中 现在我希望可以在我的智能手表上访问这些对象 所以我想实现的是你可以去启动 启动应用程序并向左和向

随机推荐

  • 是否可以在不登录的情况下冒充用户?

    是否可以在不提供用户名 密码的情况下模拟用户 基本上 我想得到CSIDL LOCAL APPDATA对于使用以下命令的用户 不是当前用户 ShGetFolderPath 功能 我目前拥有的只是该用户的 SID 您可以通过调用 ZwCreat
  • Nodejs - HTTP 范围支持/部分文件下载

    我正在创建一个音乐网络应用程序 用于流式传输我存储在 MongoDB GridFS 中的 MP3 我的问题 如何添加 http 范围支持 以便我可以开始流式传输音频文件 1 2 而无需等待缓冲区 我知道GridFS支持读取X字节 X字节 所
  • 为什么选择 UnityEvent 而不是本机 C# 事件?

    我的意思是 UnityEvents 比原生 C 事件慢 并且它们仍然存储对接收器的强引用 因此 我发现使用 UnityEvents 而不是原生 C 事件的唯一有效原因是它们与编辑器的集成 我是否忽略了什么 我是否忽略了什么 不 你没有忽视任
  • Java - 将二进制解析为长整数[重复]

    这个问题在这里已经有答案了 我有一个数字的二进制表示形式 想将其转换为 long 我有 Java 8 public class TestLongs public static void main String args String a L
  • Android WebView 下载不工作

    我创建了一个包含 html 表单页面的 Web 视图 在提交表单 使用 post 方法 时 它应该下载该文件 我已经实施了webview download listener这样我就可以处理下载了 Override public void o
  • 如何手动创建 UISplitView?

    我有一个应用程序将导航到 UISplitView 完全在另一个视图内 如下所示 void switchToMyDayView NSLog Show My Day Screen if self myDayController view sup
  • Dart 中用于获取数据类型大小的函数/运算符

    我想知道 Dart 中分配给不同数据类型的内存量 但我找不到函数 运算符 例如sizeofC 中的运算符来执行此操作 我已经提到了dart core为此目的图书馆 但仍然找不到任何合适的方法 那么 是否有其他方法可以获取数据类型的大小 或者
  • 使用 SymPy 求解方程组

    我正在尝试使用 SymPy 0 7 1 求解一组方程 from sympy import equations Eq S vf S vi a t Eq S d S vi t 1 2 a t 2 Eq S a S 10 Eq S d S 60
  • BASH 在变量非文件中提取字符串后的值[重复]

    这个问题在这里已经有答案了 我发现了一个无法解决的奇怪问题 我需要提取变量中的一些值 这些值位于字符串后面 本例中变量的名称是 DSLSTATE 这是其中值的示例 NewEnable 1 NewStatus Up NewDataPath F
  • 使用 matplotlib 在 qiskit 中可视化电路

    我正在学习如何使用 qiskit 并且正在使用 jupyter 笔记本 但是每次我尝试使用属性绘制来可视化电路时 我都会收到此错误 import qiskit from qiskit import from qiskit import IB
  • 如何在 Linux、Mac 和 Windows 上从 Java 启动 .NET 应用程序?

    我想从 Java 环境的上下文中启动 NET 应用程序 与 Mono 兼容 我的猜测是 我必须以某种方式确定是否安装了 mono 找到位置并使用 NET 应用程序路径作为参数启动它 但什么是可靠的方法呢 或者 还有更好的方法 也许我应该澄清
  • 按HOME后重新启动应用程序时如何返回到最新启动的活动? [复制]

    这个问题在这里已经有答案了 熟悉的场景 我有一个Main启动的活动Game按下按钮时的活动 如果用户按 HOME 然后再次启动我的应用程序 则应显示GameActivity 这是他最后一次使用该应用程序时所做的事情 然而 相反发生的事情是他
  • 为什么 div 会有这样的行为?

    有时我的 div 会出现这个问题 无法按预期运行 我想要的是让它们按照我的理解 流动 布局 但它们不是 我只是想知道为什么不 我已经使用 firebug 来检查 css 似乎没有任何不符合规范的内容 但它们并没有一个接一个地流动 我提供了两
  • 在领域驱动设计中,您可以在 UI 中使用领域实体吗?

    在许多领先的 DDD 项目中 尤其是 MVC 风格 我看到 UI 使用镜像域实体的显示对象 而不是直接使用这些域对象 这种风格显然是为了解耦和分离关注点 我个人更喜欢这种风格 但我不确定这是否是 DDD 的严格原则 或者这是否只是不同开发人
  • 我需要做直方图拉伸

    我有一个 BitmapFrames 数组 需要进行直方图拉伸 我知道这与直方图均衡不同 最终结果是什么 有点 问题是我完全不知道得到直方图后该怎么做 到目前为止 我的代码为直方图创建了一个数组 因此我知道每个值有多少个像素 但在那之后我不知
  • 让semantic_errors呈现准确的错误消息

    我有一个模型Camping which has many Images 露营至少需要一张图片 class Camping lt ActiveRecord Base attr accessible images attributes has
  • PostgreSQL:如何实现最小基数?

    正如这个问题中的回答 PostgreSQL 中的基数 https stackoverflow com questions 3135206 cardinality in postgresql 基数是使用强制执行的限制条件 http www p
  • 使用游标获取字段值

    我正在创建一个应用程序 但遇到问题Cursor 我有一个SQLiteDatabase这给我返回了一个Cursor当我尝试使用此函数获取值时 public Cursor fetchOption long rowId throws SQLExc
  • 如何将“zd”说明符与“printf()”一起使用?

    寻求有关使用的说明 zd with printf 当然 对于 C99 及更高版本 以下内容是正确的 void print size size t sz printf zu n sz C 规范seems允许printf zd n sz 取决于
  • 如何正确对齐此文本?

    我今天写了这个极地时钟 我几乎完成了 除了我想在行内对齐我的文本 类似于this http blog pixelbreaker com polarclock 有谁知道如何做到这一点 我尝试使用 FontRenderContext 和字体指标