Swing/GlyphVector のバックアップの現在との差分(No.6)
TITLE:JLabelの文字列を折り返し
JLabelの文字列を折り返し
編集者:Terai Atsuhiro~
作成日:2004-03-02
更新日:2021-10-21 (木) 19:06:59
概要
GlyphVector
を使って、ラベルの文字列を折り返して表示します。
Screenshot
Advertisement
概要
GlyphVectorを使って、ラベルの文字列を折り返して表示します。サンプルコード
#spanend
#spanadd
class WrappedLabel extends JLabel {
#spanend
private GlyphVector gvtext;
private int width = -1;
public WrappedLabel() {
this(null);
}
#spandel
#screenshot
#spanend
public WrappedLabel(String str) {
super(str);
}
#spandel
**サンプルコード [#b14ee862]
#spanend
#spandel
#code{{
#spanend
private GlyphVector getWrappedGlyphVector(String str,
float wrapping,
Font font,
FontRenderContext frc) {
Point2D gmPos = new Point2D.Double(0.0d, 0.0d);
GlyphVector gv = font.createGlyphVector(frc, str);
float lineheight = (float) (gv.getLogicalBounds().getHeight());
float xpos = 0.0f;
float advance = 0.0f;
int lineCount = 0;
GlyphMetrics gm;
for(int i=0;i<gv.getNumGlyphs();i++) {
gm = gv.getGlyphMetrics(i);
advance = gm.getAdvance();
if(xpos<wrapping && wrapping<=xpos+advance) {
lineCount++;
xpos = 0.0f;
}
gmPos.setLocation(xpos, lineheight*lineCount);
gv.setGlyphPosition(i, gmPos);
xpos = xpos + advance;
}
return gv;
}
@Override public void doLayout() {
Insets i = getInsets();
int w = getWidth() - i.left - i.right;
if (w != width) {
Font font = getFont();
FontMetrics fm = getFontMetrics(font);
FontRenderContext frc = fm.getFontRenderContext();
gvtext = getWrappedGlyphVector(getText(), w, font, frc);
width = w;
}
super.doLayout();
}
lbl2 = new JLabel() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
if(flg) {
int wrap = lbl2.getWidth()
-lbl2.getInsets().left
-lbl2.getInsets().right;
FontRenderContext frc = g2.getFontRenderContext();
gvtext = getWrappedGlyphVector(str, wrap, lbl2.getFont(), frc);
flg = false;
}
g2.setPaint(Color.RED);
g2.drawGlyphVector(gvtext,
lbl2.getInsets().left,
lbl2.getInsets().top+lbl2.getFont().getSize());
}
};
lbl2.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
flg = true;
lbl2.repaint();
}
});
@Override protected void paintComponent(Graphics g) {
if (gvtext == null) {
super.paintComponent(g);
} else {
Insets i = getInsets();
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(Color.RED);
g2.drawGlyphVector(gvtext, i.left, getFont().getSize() + i.top);
g2.dispose();
}
}
#spanadd
#spanend
private GlyphVector getWrappedGlyphVector(
String str, float width, Font font, FontRenderContext frc) {
Point2D gmPos = new Point2D.Double(0d, 0d);
GlyphVector gv = font.createGlyphVector(frc, str);
float lineheight = (float) (gv.getLogicalBounds().getHeight());
float xpos = 0f;
float advance = 0f;
int lineCount = 0;
GlyphMetrics gm;
for (int i = 0; i < gv.getNumGlyphs(); i++) {
gm = gv.getGlyphMetrics(i);
advance = gm.getAdvance();
if (xpos < width && width <= xpos + advance) {
lineCount++;
xpos = 0f;
}
gmPos.setLocation(xpos, lineheight * lineCount);
gv.setGlyphPosition(i, gmPos);
xpos = xpos + advance;
}
return gv;
}
#spanadd
}
#spanend
View in GitHub: Java, Kotlin- &jnlp;
- &jar;
- &zip;
解説
上記のサンプルでは、上が普通のラベルで、下はラベルの幅(余白に注意)で文字列を折り返すようになっています。折り返しは、ラベルのサイズが変更されるたびに、GlyphVectorを更新することで行っています。解説
- 上:
JLabel
- デフォルトの
JLabel
で折り返しせずに右側から...
で省略
- デフォルトの
- 中:
GlyphVector
- コンテナのサイズが変更されるたびに
GlyphVector
を更新して文字列の折り返しを実行 - 欧文などで合字(リガチャ)がある場合は
GlyphVector gv = font.createGlyphVector(frc, str);
ではなく、GlyphVector bounds and kerning, ligatures | Oracle Forumsのようにchar[] chars = text.toCharArray(); GlyphVector gv = font.layoutGlyphVector(frc, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT);
とした方が良さそう
- コンテナのサイズが変更されるたびに
- 下:
JTextArea
-
JLabel
のFont
と背景色を同じものに設定した編集不可のJTextArea
をsetLineWrap(true);
として文字列の折り返しを実行
-
label.setText("<html>文字列を適当なところで<br>折り返す。");
- -
- ラベルの幅ではなく任意の場所で文字列を改行したい場合は、以下のように
JLabel
にhtml
の<br>
タグを利用したり、編集不可にしたJTextPane
、JTextArea
などが使用可能- 参考: JTextPane、JLabelなどで複数行を表示
#spanend #spanadd label.setText("<html>文字列を適当なところで<br />折り返す。"); #spanend #spanadd
- 参考: JTextPane、JLabelなどで複数行を表示
参考リンク
- How Swing Components Are Displayed
- How to Use Labels
-
AttributedString
とLineBreakMeasurer
を使って文字列の折り返しを描画する方法もある#spanend #spanadd class WrappingLabel extends JLabel { #spanend public WrappingLabel(String text) { super(text); } #spandel **コメント [#ibb7abba] #spanend @Override protected void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g.create(); 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()); as.addAttribute(TextAttribute.FONT, getFont()); 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(); } #spanadd } #spanend #spanadd
参考リンク
- Drawing Multiple Lines of Text (The Java™ Tutorials > 2D Graphics > Working with Text APIs)
- LineBreakMeasurer (Java Platform SE 8)
- JDK-6479801 java.awt.font.LineBreakMeasurer code incorrect - Java Bug System