Swing drawString:文本边界和换行

时间:2016-12-13 00:25:20

标签: java swing layout graphics

我需要使用Graphics#drawString

绘制文字

我正在绘制宽度和高度都变化的JPanel(通过拖动)。

我正在寻找一种生成边界的解决方案,这样我就可以自动扭曲线条并相应调整文本,而不会溢出。

我想我可以通过使用fontMetrics获取像素的长度来自己进行硬编码,但是,我希望有一个自动执行此操作的组件(drawString也不支持'\n')。

在文档以及this其他答案中,我发现了这一点:

Graphics2D g = ...;
Point2D loc = ...;
Font font = Font.getFont("Helvetica-bold-italic");
FontRenderContext frc = g.getFontRenderContext();
TextLayout layout = new TextLayout("This is a string", font, frc);
layout.draw(g, (float)loc.getX(), (float)loc.getY());

Rectangle2D bounds = layout.getBounds();
bounds.setRect(bounds.getX()+loc.getX(),
              bounds.getY()+loc.getY(),
              bounds.getWidth(),
              bounds.getHeight());
g.draw(bounds);

它绘制字符串和边界,但它们没有效果,所以这里没有运气。

我可以使用的任何课程吗?

2 个答案:

答案 0 :(得分:7)

  

我可以使用的任何课程吗?

另一种选择是使用LineBreakMeasurer

import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.text.*;
import java.util.Objects;
import javax.swing.*;
import javax.swing.border.Border;

public final class LineBreakMeasurerTest {
  private static final String TEXT = "1234567890 ABCDEFG HIJKLMN OPQRSTU VWXYZ";
  private final JLabel    lbl1 = new JLabel(TEXT);
  private final JTextArea lbl2 = new JTextArea(TEXT);
  private final JLabel    lbl3 = new WrappingLabel(TEXT);
  public JComponent makeUI() {
    Border b = BorderFactory.createLineBorder(Color.GREEN,  5);
    lbl1.setBorder(
        BorderFactory.createTitledBorder(b, "JLabel"));
    lbl2.setBorder(
        BorderFactory.createTitledBorder(b, "JTextArea"));
    lbl3.setBorder(
        BorderFactory.createTitledBorder(b, "LineBreakMeasurer"));

    lbl2.setFont(lbl1.getFont());
    lbl2.setEditable(false);
    lbl2.setLineWrap(true);
    lbl2.setWrapStyleWord(true);
    lbl2.setBackground(lbl1.getBackground());

    JPanel p = new JPanel(new GridLayout(3, 1));
    p.add(lbl1);
    p.add(lbl2);
    p.add(lbl3);
    return p;
  }

  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      UIManager.put("swing.boldMetal", Boolean.FALSE);
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new LineBreakMeasurerTest().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

class WrappingLabel extends JLabel {
  //TEST: private AffineTransform at = AffineTransform.getScaleInstance(.8, 1d);
  protected WrappingLabel(String text) {
    super(text);
  }
  @Override protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(getForeground());
    Insets i = getInsets();
    float x = i.left;
    float y = i.top;
    int w = getWidth() - i.left - i.right;

    AttributedString as = new AttributedString(getText());
    //TEST: as.addAttribute(TextAttribute.FONT, g2.getFont());
    //TEST: as.addAttribute(TextAttribute.TRANSFORM, at);
    AttributedCharacterIterator aci = as.getIterator();
    FontRenderContext frc = g2.getFontRenderContext();
    LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);

    while (lbm.getPosition() < aci.getEndIndex()) {
      TextLayout tl = lbm.nextLayout(w);
      tl.draw(g2, x, y + tl.getAscent());
      y += tl.getDescent() + tl.getLeading() + tl.getAscent();
    }
    g2.dispose();
  }
}

答案 1 :(得分:2)

最简单的解决方案:使用JTextArea。

你可以通过将背景设置为null来使其看起来像JTextArea,使其不可聚焦,并且如果你调用setLineWrap(true)和{{1 }} 在上面。要让它填充JPanel,给面板一个BorderLayout,并添加JTextArea BorderLayout.CENTER。如果需要,您甚至可以设置保证金。