我试图视觉上居中一个任意的用户提供的字符串在JPanel上。我在SO上读了几十个其他类似的问题和答案,但没有找到任何直接解决我遇到的问题的答案。
在下面的代码示例中,getWidth()和getHeight()指的是我放置文本字符串的JPanel的宽度和高度。我找到了那个文本布局。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),传递给draString()的y参数指定了绘制文本的基线,而不是下界。因此,在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上的位置太高,无法居中显示。
就在那时我发现了文本布局。getDescent()(以及我为其他类找到的所有其他getDescent()方法)返回字体的最大下降,而不是特定字符串的最大下降。因此,我的大写字符串被提升,以解释该字符串中甚至没有出现的派生词。
我该怎么办?如果我不调整drawString()的y参数来考虑下行,那么在JPanel上带有下行的小写字符串在视觉上就太低了。如果我调整drawString()的y参数以考虑下行字符,那么在JPanel上不包含任何带有下行字符的字符串在视觉上会过高。我似乎无法确定基线在给定字符串的文本边框中的位置。因此,我无法准确地确定要传递给drawString()的y是什么。
谢谢你的帮助和建议。
我认为这个答案是正确的方法,但是我在过去有过自定义字体和获得它们的界限的问题。在一个项目中,我不得不求助于实际获取字体的轮廓并使用这些边界。这种方法可能更消耗内存,但它似乎是获得字体边界的可靠方法。
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Font font = new Font("Arial", Font.BOLD, 48);
String text = "Along time ago, in a galaxy, far, far away";
Shape outline = font.createGlyphVector(g.getFontMetrics().getFontRenderContext(), text).getOutline();
// the shape returned is located at the left side of the baseline, this means we need to re-align it to the top left corner. We also want to set it the the center of the screen while we are there
AffineTransform transform = AffineTransform.getTranslateInstance(
-outline.getBounds().getX() + getWidth()/2 - outline.getBounds().width / 2,
-outline.getBounds().getY() + getHeight()/2 - outline.getBounds().height / 2);
outline = transform.createTransformedShape(outline);
g2d.fill(outline);
}
正如我之前所说的,尝试使用字体度量,但如果所有其他方法都失败,请尝试此方法。
当我在使用TextLayout
时,您可以使用图形
上下文的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();
}
}
}
了解更多信息,请参阅使用文本API...
更新
如前所述,您可以使用字形向量
。。。
分别计算每个单词(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();
}
}
}
问题内容: 我试图在视觉上将用户提供的任意字符串放在JPanel上。我在这里已经阅读了许多其他类似的问题和答案,但是还没有找到任何直接解决我所遇到的问题的方法。 在下面的代码示例中,getWidth()和getHeight()指的是我要放置文本字符串的JPanel的宽度和高度。我发现TextLayout.getBounds()很好地告诉了我包围文本的边界矩形的大小。因此,我认为通过计算文本边界矩形
问题内容: 在Java forString类中,有一个称为matchs的方法,该方法如何使用正则表达式检查我的字符串是否只有数字。我尝试了以下示例,但它们均使我返回了false。 问题答案: 尝试 要么 按照Java 正则表达式 ,其 含义是“一次或多次”,并且其含义是“数字”。 注意:“双反斜杠”是一个 转义序列, 用于获取单个反斜杠-因此,在Java字符串中会提供实际结果: 参考文献: Jav
问题内容: 在Python中,如何检查字符串是否仅包含某些字符? 我需要检查仅包含a..z,0..9和的字符串。(句号),没有其他字符。 我可以遍历每个字符并检查字符是a..z还是0..9或。但这会很慢。 我现在不清楚如何使用正则表达式进行操作。 这个对吗?您可以提出更简单的正则表达式还是更有效的方法? 问题答案: 决赛(?) 答案,包装在函数中,带有注释的交互式会话: 注意:在此答案中还有一个比
问题内容: 我在Java中有一个具有值的字符串变量: 我希望我的最终字符串包含值: 我怎样才能做到这一点?我是Java编程语言的新手。 谢谢, 问题答案: 您可以使用:
问题内容: 我需要定义一个数组,其中包含所有以下特殊字符。 我正在用这个 它接受除“和\以外的所有字符 请帮助如何定义这两个。 问题答案: 并且是String类中的特殊字符 是String的开始或结尾 用于创建如新线的某些字符 标签或你的情况逃脱特殊字符,如和 因此,要使它们成为文字,您必须使用和 另一个想法是使用而不是,这样您就不必转义,并且您的字符可以写为或(因为要求转义- 应该写为- 在这里
问题内容: 我有一串琴弦,其中一些琴弦。我只想删除最后四个字符。 换句话说,我有 我希望它成为 Python处理此问题的方法是什么? 问题答案: