java – Swing中带有小字体的String的边界
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java – Swing中带有小字体的String的边界,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8115字,纯文字阅读大概需要12分钟。
内容图文
![java – Swing中带有小字体的String的边界](/upload/InfoBanner/zyjiaocheng/787/5945590cb48e42a78cca249ab856a3f7.jpg)
关于计算应该绘制到Swing组件中的字符串的大小(宽度或高度)有很多(很多)问题.并且有许多提议的解决方案.但是,我注意到大多数这些解决方案对于小字体都不能正常工作.
以下是MCVE,其中显示了一些方法:
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.function.BiFunction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TextBoundsTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Font baseFont = new Font("Sans Serif", Font.PLAIN, 10);
Font smallFont0 = baseFont.deriveFont(0.5f);
Font smallFont1 = baseFont.deriveFont(0.4f);
f.getContentPane().setLayout(new GridLayout(5,2));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont0,
TextBoundsTest::computeBoundsWithFontMetrics,
"FontMetrics"));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont1,
TextBoundsTest::computeBoundsWithFontMetrics,
"FontMetrics"));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont0,
TextBoundsTest::computeBoundsWithFontAndFontRenderContext,
"Font+FontRenderContext"));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont1,
TextBoundsTest::computeBoundsWithFontAndFontRenderContext,
"Font+FontRenderContext"));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont0,
TextBoundsTest::computeBoundsWithGlyphVectorLogicalBounds,
"GlyphVectorLogicalBounds"));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont1,
TextBoundsTest::computeBoundsWithGlyphVectorLogicalBounds,
"GlyphVectorLogicalBounds"));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont0,
TextBoundsTest::computeBoundsWithGlyphVectorVisualBounds,
"GlyphVectorVisualBounds"));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont1,
TextBoundsTest::computeBoundsWithGlyphVectorVisualBounds,
"GlyphVectorVisualBounds"));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont0,
TextBoundsTest::computeBoundsWithTextLayout,
"TextLayout"));
f.getContentPane().add(
new TextBoundsTestPanel(smallFont1,
TextBoundsTest::computeBoundsWithTextLayout,
"TextLayout"));
f.setSize(600,800);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static Rectangle2D computeBoundsWithFontMetrics(
String string, Graphics2D g)
{
FontMetrics fontMetrics = g.getFontMetrics();
Rectangle2D bounds = fontMetrics.getStringBounds(string, g);
return bounds;
}
private static Rectangle2D computeBoundsWithFontAndFontRenderContext(
String string, Graphics2D g)
{
FontRenderContext fontRenderContext =
new FontRenderContext(g.getTransform(),true, true);
Font font = g.getFont();
Rectangle2D bounds = font.getStringBounds(string, fontRenderContext);
return bounds;
}
private static Rectangle2D computeBoundsWithGlyphVectorLogicalBounds(
String string, Graphics2D g)
{
FontRenderContext fontRenderContext = g.getFontRenderContext();
Font font = g.getFont();
GlyphVector glyphVector = font.createGlyphVector(
fontRenderContext, string);
return glyphVector.getLogicalBounds();
}
private static Rectangle2D computeBoundsWithGlyphVectorVisualBounds(
String string, Graphics2D g)
{
FontRenderContext fontRenderContext = g.getFontRenderContext();
Font font = g.getFont();
GlyphVector glyphVector = font.createGlyphVector(
fontRenderContext, string);
return glyphVector.getVisualBounds();
}
private static Rectangle2D computeBoundsWithTextLayout(
String string, Graphics2D g)
{
FontRenderContext fontRenderContext = g.getFontRenderContext();
Font font = g.getFont();
TextLayout textLayout = new TextLayout(string, font, fontRenderContext);
return textLayout.getBounds();
}
}
class TextBoundsTestPanel extends JPanel
{
private final Font textFont;
private final BiFunction<String, Graphics2D, Rectangle2D> boundsComputer;
private final String boundsComputerName;
TextBoundsTestPanel(Font textFont,
BiFunction<String, Graphics2D, Rectangle2D> boundsComputer,
String boundsComputerName)
{
this.textFont = textFont;
this.boundsComputer = boundsComputer;
this.boundsComputerName = boundsComputerName;
}
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
g.drawString("Font size: "+textFont.getSize2D(), 10, 20);
g.drawString("Bounds : "+boundsComputerName, 10, 40);
AffineTransform oldAt = g.getTransform();
AffineTransform at = AffineTransform.getScaleInstance(50, 50);
g.transform(at);
g.translate(1, 2);
g.setFont(textFont);
String string = "Test";
g.drawString(string, 0, 0);
Rectangle2D bounds = boundsComputer.apply(string, g);
Shape boundsShape = at.createTransformedShape(bounds);
g.setTransform(oldAt);
g.setColor(Color.RED);
g.translate(50, 100);
g.draw(boundsShape);
}
}
此截屏显示了此程序的结果:
可以看出,对于大小为0.5的字体,简单方法很有效,但是对于大小为0.4的字体,突然挽救并返回高度为0.0的边界.
(旁注:我想知道这是否只是一个错误 – 虽然它可能是由一些内部的舍入错误引起的,因为它恰好发生在0.5和0.49的字体大小之间……)
适用于这些较小字体的唯一解决方案是使用GlyphVector或TextLayout进行计算.但是这两种方法都非常昂贵,因为它们需要创建字符串的形状和许多辅助对象.此外,它们仅返回视觉边界(即实际形状的边界),而不返回文本的逻辑边界.
是否有任何有效的解决方案来计算小字体中字符串的逻辑边界?
解决方法:
您可以先将字体规范化.然后测量,然后通过字体的true size2D缩放矩形的尺寸.
private static Rectangle2D computeBoundsUsingNormalizedFont(
String string, Graphics2D g) {
Font normalizedFont = g.getFont().deriveFont(1f);
Rectangle2D bounds = normalizedFont.getStringBounds(string, g.getFontRenderContext());
float scale = g.getFont().getSize2D();
return new Rectangle2D.Double(bounds.getX() * scale,
bounds.getY() * scale,
bounds.getWidth() * scale,
bounds.getHeight() * scale);
}
那么显然你可以缓存规范化的字体并在计算器类中隐藏这个工作,如下所示:
TextBoundsCalculator textBoundsCalculator = TextBoundsCalculator.forFont(smallFontX);
Rectangle2D bounds = textBoundsCalculator.boundsFor(string, g);
TextBoundsCalculator的位置:
import java.awt.*;
import java.awt.geom.Rectangle2D;
public final class TextBoundsCalculator {
private interface MeasureStrategy {
Rectangle2D boundsFor(String string, Graphics2D g);
}
private MeasureStrategy measureStrategy;
private TextBoundsCalculator(MeasureStrategy measureStrategy) {
this.measureStrategy = measureStrategy;
}
public static TextBoundsCalculator forFont(Font font) {
if (font.getSize() == 0)
return new TextBoundsCalculator(new ScaleMeasureStrategy(font));
// The bug appears to be only when font.getSize()==0.
// So there's no need to normalize, measure and scale with fonts
// where this is not the case
return new TextBoundsCalculator(new NormalMeasureStrategy(font));
}
public Rectangle2D boundsFor(String string, Graphics2D g) {
return measureStrategy.boundsFor(string, g);
}
private static class ScaleMeasureStrategy implements MeasureStrategy {
private final float scale;
private final Font normalizedFont;
public ScaleMeasureStrategy(Font font) {
scale = font.getSize2D();
normalizedFont = font.deriveFont(1f);
}
public Rectangle2D boundsFor(String string, Graphics2D g) {
Rectangle2D bounds = NormalMeasureStrategy.boundsForFont(normalizedFont, string, g);
return scaleRectangle2D(bounds, scale);
}
}
private static class NormalMeasureStrategy implements MeasureStrategy {
private final Font font;
public NormalMeasureStrategy(Font font) {
this.font = font;
}
public Rectangle2D boundsFor(String string, Graphics2D g) {
return boundsForFont(font, string, g);
}
private static Rectangle2D boundsForFont(Font font, String string, Graphics2D g) {
return font.getStringBounds(string, g.getFontRenderContext());
}
}
private static Rectangle2D scaleRectangle2D(Rectangle2D rectangle2D, float scale) {
return new Rectangle2D.Double(
rectangle2D.getX() * scale,
rectangle2D.getY() * scale,
rectangle2D.getWidth() * scale,
rectangle2D.getHeight() * scale);
}
}
内容总结
以上是互联网集市为您收集整理的java – Swing中带有小字体的String的边界全部内容,希望文章能够帮你解决java – Swing中带有小字体的String的边界所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。