Java:图形对齐字符串

时间:2014-05-20 00:42:30

标签: java fonts graphics2d fontmetrics java-canvas

我目前正在尝试创建一个滚动文本方法,其中将使用String的参数。很快,它将从左到右开始绘制,并随着时间的推移进入新的线条,因此它不会从屏幕上消失。我正在使用FontMetrics来实现我的目标。

我从我的主类中的render方法向我的RollingText.render(Graphics g, int x, int y)传递参数。在我的render方法中,我开始设置Graphics字体和颜色,并抓住所有FontMetrics,然后我开始从FontMetrics抓取不同的内容。同样,我进入for循环,将文本绘制到字符串中。

public void render(Graphics g, int x, int y) {
    // text is the field that a grab the index of the string from
    // the index is the max part of the string I'm grabbing from,
    // increments using the update() method
    String str = text.substring(0, index);
    String[] words = str.split(" ");

    Font f = new Font(g.getFont().getName(), 0, 24);
    FontMetrics fmetrics = g.getFontMetrics(f);
    g.setColor(Color.white);
    g.setFont(f);

    int line = 1;
    int charsDrawn = 0;
    int wordsDrawn = 0;
    int charWidth = fmetrics.charWidth('a');
    int fontHeight = fmetrics.getHeight();
    for (int i = 0; i < words.length; i++) {
        int wordWidth = fmetrics.stringWidth(words[i]);
        if (wordWidth* wordsDrawn + charWidth * charsDrawn > game.getWidth()) {
            line++;
            charsDrawn = 0;
            wordsDrawn = 0;
        }

        g.drawString(words[i], x * charsDrawn + charWidth, y + fontHeight * line);

        charsDrawn += words[i].length();
        wordsDrawn += 1;
    }
}

目前,在这一点上一切都会正常,但问题仍然是drawString方法中每个单词之间的空格被夸大了,如下所示:

Rolling Text Demo

该行:

g.drawString(words[i], x * charsDrawn + charWidth, y + fontHeight * line);

我目前唯一的问题是找到正确的方法来对x位置进行数学计算。目前,它根据字长而间隔很大且动态,我无法弄清楚如何让它看起来至少正常。我已经尝试了与我当前定义的整数的不同组合,依此类推。出现的问题可能是错误的间距,无法定位和闪烁,以及同时运行的文本。

最后,我的问题是,将使用什么样的算法来帮助我正确定位文本的x坐标以使其看起来正确?

1 个答案:

答案 0 :(得分:1)

我不确定为什么你会尝试根据各种不同的变量计算x / y位置,只需将FontMetrics#stringWidthFontMetrics#getHeight添加到x / y值即可在我看来更简单......

您似乎也在使用FontMetrics#stringWidth和根据“样本”宽度... wordsDrawn + charWidth计算单个字符的宽度之间切换,这使您的计算简单......令人困惑。您似乎也有优先权问题......

不应x * charsDrawn + charWidthx + (charsDrawn * charWidth)

我实际上无法让您的示例代码重现您的结果,相反,我简化了它...

TextLayout

import java.awt.BorderLayout;
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 javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class RenderText {

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

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

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

    public class TestPane extends JPanel {

        private String text;
        private int index;

        public TestPane() {
            text = "A long time ago, in a galaxy far, far, away..."
                    + "A vast sea of stars serves as the backdrop for the main title. "
                    + "War drums echo through the heavens as a rollup slowly crawls "
                    + "into infinity."
                    + "     It is a period of civil war. Rebel spaceships, "
                    + "     striking from a hidden base, have won their first "
                    + "     victory against the evil Galactic Empire."
                    + "     During the battle, Rebel spies managed to steal "
                    + "     secret plans to the Empire's ultimate weapon, the "
                    + "     Death Star, an armored space station with enough "
                    + "     power to destroy an entire planet."
                    + "     Pursued by the Empire's sinister agents, Princess "
                    + "     Leia races home aboard her starship, custodian of "
                    + "     the stolen plans that can save her people and "
                    + "     restore freedom to the galaxy...";

            index = text.length() - 1;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            render(g, 0, 0);
            g2d.dispose();
        }

        public void render(Graphics g, int x, int y) {
            // text is the field that a grab the index of the string from
            // the index is the max part of the string I'm grabbing from,
            // increments using the update() method
            String str = text.substring(0, index);
            String[] words = str.split(" ");

            Font f = new Font(g.getFont().getName(), 0, 24);
            FontMetrics fmetrics = g.getFontMetrics(f);
//            g.setColor(Color.white);
            g.setFont(f);

            int fontHeight = fmetrics.getHeight();

            int spaceWidth = fmetrics.stringWidth(" ");

            int xPos = x;
            int yPos = y;
            for (String word : words) {
                int wordWidth = fmetrics.stringWidth(word);
                if (wordWidth + xPos > getWidth()) {
                    yPos += fontHeight;
                    xPos = x;
                }
                g.drawString(word, x + xPos, yPos + fmetrics.getAscent());
                xPos += wordWidth + spaceWidth;
            }
        }
    }

}

在您提供实际runnable example that demonstrates your problem之前,这是我能做的最好的事情......