- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我试图在 JPanel 上以视觉方式将任意用户提供的字符串居中。我已经在 SO 上阅读了许多其他类似的问题和答案,但没有找到任何直接解决我遇到的问题的内容。
在下面的代码示例中,getWidth() 和 getHeight() 指的是我放置文本字符串的 JPanel 的宽度和高度。我发现 TextLayout.getBounds() 可以很好地告诉我包围文本的边界矩形的大小。因此,我认为通过计算文本边界矩形左下角的 JPanel 上的 x 和 y 位置,将文本矩形居中放置在 JPanel 矩形中会相对简单:
FontRenderContext context = g2d.getFontRenderContext();
messageTextFont = new Font("Arial", Font.BOLD, fontSize);
TextLayout txt = new TextLayout(messageText, messageTextFont, context);
Rectangle2D bounds = txt.getBounds();
xString = (int)((getWidth() - (int)bounds.getWidth()) / 2 );
yString = (int)((getHeight()/2) + (int)(bounds.getHeight()/2));
g2d.setFont(messageTextFont);
g2d.setColor(rxColor);
g2d.drawString(messageText, xString, yString);
这对于全部为大写的字符串非常有效。但是,当我开始测试包含带下标的小写字母(如 g、p、y)的字符串时,文本不再居中。小写字母的下部(延伸到字体基线以下的部分)在 JPanel 上绘制得太低,以至于文本看起来居中。
那时我发现(感谢 SO)传递给 drawString() 的 y 参数指定绘制文本的 baseline,而不是下限。因此,再次在 SO 的帮助下,我意识到我需要根据字符串中下部的长度调整文本的位置:
....
TextLayout txt = new TextLayout(messageText, messageTextFont, context);
Rectangle2D bounds = txt.getBounds();
int descent = (int)txt.getDescent();
xString = (int)((getWidth() - (int)bounds.getWidth()) / 2 );
yString = (int)((getHeight()/2) + (int)(bounds.getHeight()/2) - descent);
....
我用大量小写字母(如 g、p 和 y)的字符串对此进行了测试,效果很好!呜呼!可是等等。啊。现在,当我尝试仅使用大写字母时,JPanel 上的文本太高而无法居中显示。
那时我发现 TextLayout.getDescent()(以及我为其他类找到的所有其他 getDescent() 方法)返回 FONT 的最大下降不是特定的字符串。因此,我的大写字符串被提升以说明甚至没有出现在该字符串中的下行字母。
我该怎么办?如果我不调整 drawString() 的 y 参数来考虑下部,那么带有下部的小写字符串在 JPanel 上看起来太低了。如果我确实调整了 drawString() 的 y 参数以说明下部,那么在 JPanel 上,不包含任何带有下部的字符的字符串在视觉上太高了。我似乎没有任何方法可以确定基线在 GIVEN 字符串的文本边界矩形中的位置。因此,我无法弄清楚到底要将什么 y 传递给 drawString()。
感谢任何帮助或建议。
最佳答案
虽然我在处理 TextLayout
,但您可以只使用 Graphics
上下文的 FontMetrics
,例如...
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 java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LayoutText {
public static void main(String[] args) {
new LayoutText();
}
public LayoutText() {
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;
public TestPane() {
text = "Along time ago, in a galaxy, far, far away";
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
Font font = new Font("Arial", Font.BOLD, 48);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int x = ((getWidth() - fm.stringWidth(text)) / 2);
int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2d.setColor(Color.BLACK);
g2d.drawString(text, x, y);
g2d.dispose();
}
}
}
好吧,经过一些大惊小怪......
基本上,文本渲染发生在基线处,这使得边界的 y
位置通常出现在该点上方,使其看起来像是在 y
位置
为了克服这个问题,我们需要将字体的上升减去字体的下降添加到
y
位置...
例如……
FontRenderContext context = g2d.getFontRenderContext();
Font font = new Font("Arial", Font.BOLD, 48);
TextLayout txt = new TextLayout(text, font, context);
Rectangle2D bounds = txt.getBounds();
int x = (int) ((getWidth() - (int) bounds.getWidth()) / 2);
int y = (int) ((getHeight() - (bounds.getHeight() - txt.getDescent())) / 2);
y += txt.getAscent() - txt.getDescent();
...这就是我喜欢手动渲染文本的原因...
可运行的例子...
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 java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LayoutText {
public static void main(String[] args) {
new LayoutText();
}
public LayoutText() {
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;
public TestPane() {
text = "Along time ago, in a galaxy, far, far away";
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
FontRenderContext context = g2d.getFontRenderContext();
Font font = new Font("Arial", Font.BOLD, 48);
TextLayout txt = new TextLayout(text, font, context);
Rectangle2D bounds = txt.getBounds();
int x = (int) ((getWidth() - (int) bounds.getWidth()) / 2);
int y = (int) ((getHeight() - (bounds.getHeight() - txt.getDescent())) / 2);
y += txt.getAscent() - txt.getDescent();
g2d.setFont(font);
g2d.setColor(Color.BLACK);
g2d.drawString(text, x, y);
g2d.setColor(Color.BLUE);
g2d.translate(x, y);
g2d.draw(bounds);
g2d.dispose();
}
}
}
看看Working with Text APIs更多信息...
已更新
如前所述,您可以使用 GlyphVector
...
每个单词(Cat
和Dog
)都单独计算以展示差异
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LayoutText {
public static void main(String[] args) {
new LayoutText();
}
public LayoutText() {
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;
public TestPane() {
text = "A long time ago, in a galaxy, far, far away";
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
Font font = new Font("Arial", Font.BOLD, 48);
g2d.setFont(font);
FontRenderContext frc = g2d.getFontRenderContext();
GlyphVector gv = font.createGlyphVector(frc, "Cat");
Rectangle2D box = gv.getVisualBounds();
int x = 0;
int y = (int)(((getHeight() - box.getHeight()) / 2d) + (-box.getY()));
g2d.drawString("Cat", x, y);
x += box.getWidth();
gv = font.createGlyphVector(frc, "Dog");
box = gv.getVisualBounds();
y = (int)(((getHeight() - box.getHeight()) / 2d) + (-box.getY()));
g2d.drawString("Dog", x, y);
g2d.dispose();
}
}
}
关于Java - 如何在矩形中以视觉方式将特定字符串(不仅仅是字体)居中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23729944/
我是一名优秀的程序员,十分优秀!