将字符串的ArrayList对齐(自定义)Box不会处于正确的位置

时间:2015-07-21 19:57:11

标签: java fonts position graphics2d

我在Java中将一组字符串对齐到一个框的底部时遇到了一些问题。

  

注意:我使用的Box课程不是默认设置> javax.Swing 框!它是一个简单的成本箱,有x,y位置,宽度和高度!

我现在有什么?

  • Message类,可以由我的Allign类单独对齐。
  • 包含MessageListMessage个对象的ArrayList的Allign对象,可以与Box类对齐。
  • 包含框的位置和尺寸的Allign对象。 Allign类使用此框来对齐对象。
  • 可以对齐不同类型对象的Box类,并使用Message对象进行对齐。

我的代码应如何运作:

(代码片段在页面下方)

Font对象可以使用不同的Allign设置。 Message类可以对齐这些Message对象。 obtainFontDimension()类包含一个名为Font的方法,该方法在首选Message设置中获取对象的字符串边界。当我们想要将对齐应用于Box对象时,我创建了一个Allign.applyAllignment(params)对象,其中包含x,y位置以及宽度和高度。通过调用Message,将应用计算来对齐Box中的Message对象和MessageList的dx,dy(绘制x,y位置) )将被设定。

直到这里工作正常。

现在我创建一个Message对象并向其添加一些(Message个对象。当对它应用对齐时,它将运行它包含的obtainFontDimensions()个对象,并将调用它们上的int listHeight。这些字符串的高度将相加,并将结果转换为字符串的总高度(Message)。要获得每个Box对象的绘图位置,我们将listHeight的y位置放在我们想要对齐的位置。首先,我们删除Box' sy位置的Box

The pre-positioning before alligning to the bottom

现在我们得到了第一个String的偏移量。在应用底部对齐时,它只会将Message的高度添加到偏移量。最后,通过将当前Message对象高度添加到te偏移量,为下一个MessageList对象设置偏移量。下一次迭代的时间,直到ArrayList完全计算完毕。这应该导致以下结果:

positioning the strings to position as it should be

出了什么问题?

将对齐应用于public class Window() { public void draw(Graphics2D g2d) { Box contentBox = new Box(100, 100, 300, 300); Message loadTitle = new Message("This is a testing TITLE", Colors.ORANGE, Fonts.LOADING_TITLE, false); Message loadDescription = new Message(loadString, Colors.RED, Fonts.LOADING_DESCRIPTION, false); Message loadTip = new Message("This is a random TIP!", Colors.RED, Fonts.LOADING_DESCRIPTION, false); Message loadRelease = new Message("Planned game release 2939!", Colors.RED, Fonts.LOADING_DESCRIPTION, false); Message loadSingle = new Message("THIS IS A SINGLE MESSAGE! 2o15", Colors.RED, Fonts.LOADING_DESCRIPTION, false); MessageList list = new MessageList(); list.add(loadTitle); list.add(loadDescription); list.add(loadTip); list.add(loadRelease); list.add(loadSingle); Allign.applyAllignment(g2d, Allignment.BOTTOM_RIGHT, list, loadBox); loadBox.testDraw(g2d); loadTitle.draw(g2d); loadDescription.draw(g2d); loadTip.draw(g2d); loadRelease.draw(g2d); loadSingle.draw(g2d); } } public class Message { private String text; private Color color; private Font font; private int dx, dy; private int width, height; private Rectancle2D vb; // temp public Message(String text, int x, int y, Color color, Font font) { // set text, color, font, x, y.. } public Rectangle2D obtainFontDimension(Graphics2D g2d) { if(font == null){ font = Fonts.DEFAULT; } g2d.setFont(font); FontRenderContext frc = g2d.getFontRenderContext(); GlyphVector gv = g2d.getFont().createGlyphVector(frc, text); Rectangle2D vb = gv.getPixelBounds(null, 0, 0); this.width = (int)vb.getWidth(); this.height = (int)vb.getHeight(); this.gv = gv; // TEMP for bound drawing return vb; } public void draw(Graphics2D g2d) { g2d.setFont(font); g2d.setColor(color); g2d.drawString(text, dx, dy); // TEMP draw bounds g2d.setColor(new Color(0, 0, 0, 100)); g2d.draw(gv.getPixelBounds(null, dx, dy)); } } public class Allign { public static enum Allignment { BOTTOM_RIGHT //, etc } public static void applyAllignment(Graphics2D g2d, Allignment allignment, Object object, Box box) { Point position = null; Point dimension = null; if(obj instanceof Message){ // Single Message object } else if(obj instanceof Message) { MessageList messageList = (MessageList) obj; int listHeight = 0; for(Message message : messageList.getList()) { listHeight += message.obtainFontDimension(g2d).getHeight(); } position = new Point(box.x, box.y-listHeight); // offset Y for(Message message : messageList.getList()) { message.setDrawPosition(allign(allignment, position, new Dimension(message.getWidth(), 0), box, true)); position.y += message.getHeight(); } } } private static Point allign(Allignment allignment, Point position, Dimension dimension, Box box, boolean verticalAllign) { switch(allignment) { case BOTTOM_RIGHT: position = allignRight(position, dimension, box); if(!verticalAllign) break; position = allignBottom(position, dimension, box); break; // Rest } } private static Point allignBottom(Point position, Dimension dimension, Box box) { return new Point(position.x, position.y+box.height-dimension.height); } } 对象时,某些字符串会完美地相互接触(请参见图像上的圆圈B),有些像素会使其他像素的距离更远(参见图像上的圆A1,A2)。接下来,底部仍有一个意外的填充(见图像上的圆圈C)。

enter image description here

到目前为止我尝试了什么?

  • 首先,我一直在检查弦乐的高度,这些似乎都是正确的。所以`obtainFontDimensions()`方法似乎工作得很好。
  • 在纸上绘制概念,并尝试重新计算程序,这应该让我获得字符串的正确位置。例如:
      - `Box`:x = 80,y = 80,width = 100,height = 100
      - 具有3个“消息”的`MessageList`,其高度为0 = 10,1 = 10,2 = 20。这些字符串的总高度为40像素 - 在实际对齐之前,第一个String的位置变为box.y-listHeight,即40 - 当实际调到底部时,偏移量变为40 + 100 = 140 - 将计算第二个字符串的偏移量:140 + 20(当前消息' s高度)= 160 - 重复第三个字符串,即160 + 10 = 170。 - 这意味着,最终字符串的底线是170 + 10 = 180,等于“Box”底部的底部。
    1. 你的建议......?

代码段

(仅限重要部分)

\b(\w+)\s+(?=\1)

2 个答案:

答案 0 :(得分:1)

我可以建议这样的实用程序类吗?

public class TextPrinter {

    public enum VerticalAlign {

        TOP,
        MIDDLE,
        BOTTOM
    }

    public enum HorizontalAlign {

        LEFT,
        CENTER,
        RIGHT
    }

    private Font font;
    private Color color;
    private int width;
    private int height;
    private VerticalAlign vAlign = VerticalAlign.TOP;
    private HorizontalAlign hAlign = HorizontalAlign.LEFT;

    public Font getFont() {
        return font;
    }

    public void setFont(Font font) {
        this.font = font;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public VerticalAlign getVerticalAlign() {
        return vAlign;
    }

    public void setVerticalAlign(VerticalAlign vAlign) {
        this.vAlign = vAlign;
    }

    public HorizontalAlign getHorizontalAlign() {
        return hAlign;
    }

    public void setHorizontalAlign(HorizontalAlign hAlign) {
        this.hAlign = hAlign;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    private int getOffSetX(int widthText){
        int result = 0;
        if (hAlign == HorizontalAlign.CENTER){
            result = (width - widthText)/2;
        } else if (hAlign == HorizontalAlign.RIGHT){
            result = width - widthText;
        }
        return result;
    }

    private int getOffSetY(int ascent, int descent){
        int result = ascent;
        if (vAlign == VerticalAlign.MIDDLE){
            result = (height + ascent - descent)/2;
        } else if (vAlign == VerticalAlign.BOTTOM){
            result = height - descent;
        }
        return result;
    }

    public void print(Graphics g, String text, int x, int y) {
        g.setColor(color);
        g.setFont(font);
        FontMetrics fm = g.getFontMetrics(font);

        int widthText = fm.stringWidth(text);
        g.drawString(text, x + getOffSetX(widthText), y + getOffSetY(fm.getAscent(), fm.getDescent()));
    }
}

我在扑克游戏中使用它: https://github.com/dperezcabrera/jpoker

enter image description here

答案 1 :(得分:0)

感谢David Perez和VGR的投入!

我已切换回Font指标,抓住了字符串边界的高度。但是,这仅使用基线的高度到最高的上升点。对于正确的底部间距(如在顶部),我添加了下降整数。

public int obtainFontDimension(Graphics2D g2d)
{
    if(font == null){ font = Fonts.DEFAULT; }
    g2d.setFont(font);

    FontMetrics fm = g2d.getFontMetrics(font);
    Rectangle2D sb = fm.getStringBounds(text, g2d);
    this.width = (int)sb.getWidth();
    this.height = (int)sb.getHeight();
    this.descent = (int)fm.getDescent(); // added
    tempShape = new Rectangle(width, height+descent); // Temp for drawing bounds

    return height;
}

在对齐开始之前,我首先计算MessageList中所有字符串的总高度。总高度是String的高度,包括降序高度。

然后我需要获得每个垂直对齐可能性的偏移高度,我已经添加了。 (TOP,MIDDLE,BOTTOM)

之后,我们通过在每次迭代时将高度和下降添加到偏移量来对每个消息进行对齐,这次禁用垂直对齐,或者它将每个消息水平地重新分配为单个Message对象而不是一组消息,但它确实允许它垂直对齐。

if (obj instanceof MessageList)
{
    MessageList messageList = (MessageList) obj;

    int listHeight = 0;
    for(Message message : messageList.getList())
    {
        message.obtainFontDimension(g2d);
        listHeight += message.getHeight()+message.getDescent();
    }

    position = new Point(box.x, box.y);
    Dimension listDimension = new Dimension(0, listHeight);
    if( allignment == Allignment.MIDDLE || allignment == Allignment.MIDDLE_LEFT
    || allignment == Allignment.ABSOLUTE_MIDDLE || allignment == Allignment.MIDDLE_RIGHT)
    {
        position = allign(Allignment.MIDDLE, position, listDimension, box, true);
    }
    else if(allignment == Allignment.BOTTOM || allignment == Allignment.BOTTOM_LEFT
    ||       allignment == Allignment.BOTTOM_CENTER ||  allignment == Allignment.BOTTOM_RIGHT)
    {
        position = allign(Allignment.BOTTOM, position, listDimension, box, true); 
    }
    else
    {
        position = allign(Allignment.TOP, position, listDimension, box, true); 
    }

    for(Message message : messageList.getList())
    {
        position.y += message.getHeight(); // prepare the offset
        message.setDrawPosition(allign(allignment, position, new Dimension(message.getWidth(), 0), box, true));
        position.y += message.getDescent(); // add descending offset for next itteration
    }
}

使用新界限绘制消息:

public void draw(Graphics2D g2d)
{
    g2d.setFont(font);
    g2d.setColor(color);
    g2d.drawString(text, dx, dy);

    // Drawing bounds for testing
    g2d.setColor(new Color(0, 0, 0, 100));
    shape.setLocation(dx, dy-height);
    g2d.draw(tempShape);
}

最终结果:
enter image description here

再次感谢!