将字符串的 ArrayList 与(自定义)Box 对齐不会在正确的位置
Aligning an ArrayList of Strings into a (custom)Box won't get in proper position
我在将一组字符串与 Java 中的框底部对齐时遇到了一点问题。
NOTE: the Box
class I'm using is not a default > javax.Swing box! It's a simple costum box with a x, y position, and with a width and height!
我目前拥有什么?
- 一个
Message
class可以单独对齐我的Allign
class.
- 一个
MessageList
对象,包含 Message
个对象的 ArrayList,这些对象可以与 Allign
class. 对齐
- 一个
Box
包含框的位置和尺寸的对象。 Allign
class 使用此框对齐对象。
Allign
class可以对齐不同类型的Object,用一个Box
对象对齐。
我的代码应该如何工作:
(页面下方的代码片段)
Message
对象可以使用不同的 Font
设置。 Allign
class 可以对齐这些 Message
s 对象。 Message
class 包含一个名为 obtainFontDimension()
的方法,它在首选 Font
设置中获取对象字符串的边界。当我们想要对 Message
对象应用对齐时,我创建了一个包含 x、y 位置以及宽度和高度的 Box
对象。通过调用 Allign.applyAllignment(params)
,将应用计算来对齐 Box
中的 Message
对象,并且 Message
的 dx、dy(绘制 x、y 位置)将是设置。
到这里为止一切正常。
现在我创建一个 MessageList
对象并向其添加一些 (Message
对象。对此应用对齐时,它将 运行 通过 Message
对象它包含,并将在它们上调用 obtainFontDimensions()
。将对这些字符串的高度求和,并得出字符串的总高度(int listHeight
)。获取每个 [ 的绘制位置=12=] 对象,我们在我们想要对齐的 Box
的 y 位置。首先我们删除 Box
的 y 位置的 listHeight
:
现在我们得到了第一个字符串的偏移量。当应用底部对齐时,它只是将 Box
的高度添加到偏移量中。最后,通过将当前 Message
对象高度添加到偏移量来为下一个 Message
对象设置偏移量。下一次迭代的时间,直到 ArrayList 已完全计算。这应该导致以下结果:
出了什么问题?
当对 MessageList
对象应用对齐时,一些字符串完美地相互接触(参见图像上的圆圈 B),而一些字符串与其他像素保持更远的距离(参见图像上的圆圈 A1、A2)。紧接着,底部还有一个意想不到的填充(见图片上的圆圈 C)。
到目前为止我尝试了什么?
- 首先我一直在检查字符串的高度,这似乎都是正确的。所以 `obtainFontDimensions()` 方法似乎工作正常。
- 在纸上画出概念,并尝试重新计算程序,这应该让我得到正确的字符串位置。例如:
- `Box`: x=80, y=80, width=100, height=100
- `MessageList` 有 3 个 `Messages`,高度分别为 0=10、1=10、2=20。这些字符串的总高度为 40 像素。
- 在真正对齐之前,第一个String的位置变为box.y-listHeight,即40.
- 当实际对齐到底部时,偏移量变为 40+100=140.
- 将计算第二个字符串的偏移量:140+20(当前消息的高度)=160.
- 这对第三根弦重复,即 160+10 = 170。
- 这意味着,最终字符串的底线在 170+10 = 180 上,等于 `Box` 底部的底部。
- 你的建议...?
代码片段
(仅重要部分)
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);
}
}
我可以推荐这样的实用程序 class 吗?
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
感谢 David Perez 和 VGR 的投入!
我已经切换回字体指标,抓取字符串边界的高度。但是,这仅使用基线到最高上升点的高度。为了获得适当的底部间距(如顶部),我还添加了下降整数。
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的总高度。总高度是字符串的高度包括下降高度。
然后我需要为我添加的每个垂直对齐可能性获取偏移高度。 (顶部、中间、底部)
之后,我们通过在每次迭代时将高度和下降添加到偏移量来对齐彼此下方的每个消息,这次禁用垂直对齐,否则它将水平重新对齐每个消息作为单个消息对象而不是作为一个组的消息,但它确实允许它垂直对齐。
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);
}
最终结果:
再次感谢!
我在将一组字符串与 Java 中的框底部对齐时遇到了一点问题。
NOTE: the
Box
class I'm using is not a default > javax.Swing box! It's a simple costum box with a x, y position, and with a width and height!
我目前拥有什么?
- 一个
Message
class可以单独对齐我的Allign
class. - 一个
MessageList
对象,包含Message
个对象的 ArrayList,这些对象可以与Allign
class. 对齐
- 一个
Box
包含框的位置和尺寸的对象。Allign
class 使用此框对齐对象。 Allign
class可以对齐不同类型的Object,用一个Box
对象对齐。
我的代码应该如何工作:
(页面下方的代码片段)
Message
对象可以使用不同的 Font
设置。 Allign
class 可以对齐这些 Message
s 对象。 Message
class 包含一个名为 obtainFontDimension()
的方法,它在首选 Font
设置中获取对象字符串的边界。当我们想要对 Message
对象应用对齐时,我创建了一个包含 x、y 位置以及宽度和高度的 Box
对象。通过调用 Allign.applyAllignment(params)
,将应用计算来对齐 Box
中的 Message
对象,并且 Message
的 dx、dy(绘制 x、y 位置)将是设置。
到这里为止一切正常。
现在我创建一个 MessageList
对象并向其添加一些 (Message
对象。对此应用对齐时,它将 运行 通过 Message
对象它包含,并将在它们上调用 obtainFontDimensions()
。将对这些字符串的高度求和,并得出字符串的总高度(int listHeight
)。获取每个 [ 的绘制位置=12=] 对象,我们在我们想要对齐的 Box
的 y 位置。首先我们删除 Box
的 y 位置的 listHeight
:
现在我们得到了第一个字符串的偏移量。当应用底部对齐时,它只是将 Box
的高度添加到偏移量中。最后,通过将当前 Message
对象高度添加到偏移量来为下一个 Message
对象设置偏移量。下一次迭代的时间,直到 ArrayList 已完全计算。这应该导致以下结果:
出了什么问题?
当对 MessageList
对象应用对齐时,一些字符串完美地相互接触(参见图像上的圆圈 B),而一些字符串与其他像素保持更远的距离(参见图像上的圆圈 A1、A2)。紧接着,底部还有一个意想不到的填充(见图片上的圆圈 C)。
到目前为止我尝试了什么?
- 首先我一直在检查字符串的高度,这似乎都是正确的。所以 `obtainFontDimensions()` 方法似乎工作正常。
- 在纸上画出概念,并尝试重新计算程序,这应该让我得到正确的字符串位置。例如:
- - `Box`: x=80, y=80, width=100, height=100
- `MessageList` 有 3 个 `Messages`,高度分别为 0=10、1=10、2=20。这些字符串的总高度为 40 像素。
- 在真正对齐之前,第一个String的位置变为box.y-listHeight,即40.
- 当实际对齐到底部时,偏移量变为 40+100=140.
- 将计算第二个字符串的偏移量:140+20(当前消息的高度)=160.
- 这对第三根弦重复,即 160+10 = 170。 - 这意味着,最终字符串的底线在 170+10 = 180 上,等于 `Box` 底部的底部。 - 你的建议...?
代码片段
(仅重要部分)
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);
}
}
我可以推荐这样的实用程序 class 吗?
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
感谢 David Perez 和 VGR 的投入!
我已经切换回字体指标,抓取字符串边界的高度。但是,这仅使用基线到最高上升点的高度。为了获得适当的底部间距(如顶部),我还添加了下降整数。
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的总高度。总高度是字符串的高度包括下降高度。
然后我需要为我添加的每个垂直对齐可能性获取偏移高度。 (顶部、中间、底部)
之后,我们通过在每次迭代时将高度和下降添加到偏移量来对齐彼此下方的每个消息,这次禁用垂直对齐,否则它将水平重新对齐每个消息作为单个消息对象而不是作为一个组的消息,但它确实允许它垂直对齐。
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);
}
最终结果:
再次感谢!