Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to create a wrapping and/or multiline label in AWT.

0.00/5 (No votes)
12 Aug 2001 1  
How to create a wrapping and/or multiline label in AWT

Introduction

VWrappingLabel is based on the Symantec WrappingLabel. Here is a brief blurb taken straight from Daniel Kirkdorffers Visual Cafe Tips, which was the place this code was found originally.

Symantec's WrappingLabel is a very handy component. On top of the ability to automatically wrap label text to fit the width of the component, WrappingLabel can work as a good substitute for the basic Label component in cases where you want to modify foreground or background colors of your label.

A number of people have asked if it is possible for WrappingLabel to take the newline character "\n" into consideration when wrapping to force a newline in certain places. Unfortunately WrappingLabel eats newlines. However in response to the interest, Paul Williams has written another version of WrappingLabel that does handle newlines. I have copies of the source code, compiled class file, and the .desc description file. The key to using this component in Visual Caf� is to set the text of the label with the setText() method in code, as opposed to setting the text in the Property List window at design time. Visual Caf� will substitute "\n" with "\\n" otherwise. Paul has also added the nice feature of setting horizontal and vertical alignment of your text via the setHAlignStyle() and setVAlignStyle() methods, or through alternate constructors.

Kudos to Paul Williams formerly of Criterion Inc. I tried to contact you, but it seems your old email address is a dead end. I promise I only made a few minor modifications.

import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.FontMetrics;
import java.awt.Dimension;
import java.awt.Label;
import java.util.Vector;
import java.util.Enumeration;

/**
 * VWrappingLabel is based on Symantec's class WrappingLabel; however, this
class
 * can format the text vertically, too.  It also wraps text at newlines
embedded
 * in the label's text.
 *
 * @see symantec.awt.WrappingLabel
 * @author    Paul F. Williams  (mailto:paul@criterioninc.com)
 *          Criterion, Inc.   (http://www.criterioninc.com)
 * @author      Kyle Morris       (mailto:morriskg@nexusfusion.com)
 *
 */


public class VWrappingLabel extends Canvas
{
    //--------------------------------------------------

    // constants

    //--------------------------------------------------


    //--------------------------------------------------

    // class variables

    //--------------------------------------------------



    //--------------------------------------------------

    // member variables

    //--------------------------------------------------

    protected String text;
    protected float m_nHAlign;
    protected float m_nVAlign;
    protected int baseline;
    protected FontMetrics fm;


    //--------------------------------------------------

    // constructors

    //--------------------------------------------------


    public VWrappingLabel()
    {
        this("");
    }

    public VWrappingLabel(String s)
    {
        this(s, Canvas.LEFT_ALIGNMENT, Canvas.CENTER_ALIGNMENT);
    }

    public VWrappingLabel(String s, float nHorizontal, float nVertical)
    {
        setText(s);
        setHAlignStyle(nHorizontal);
        setVAlignStyle(nVertical);
    }


    //--------------------------------------------------

    // accessor members

    //--------------------------------------------------


    public float    getHAlignStyle() { return m_nHAlign; }
    public float    getVAlignStyle() { return m_nVAlign; }
    public String getText()        { return text;      }

    public void setHAlignStyle(float a)
    {
        m_nHAlign = a;
        invalidate();
    }

    public void setVAlignStyle(float a)
    {
        m_nVAlign = a;
        invalidate();
    }

    public void setText(String s)
    {
        text = s;
        repaint();
    }


    //--------------------------------------------------

    // member methods

    //--------------------------------------------------


    public String paramString()
    {
        return "";
    }

    public void paint(Graphics g)
    {
        if (text != null)
        {
            Dimension d;
            int currentY = 0;
            Vector lines;

            // Set up some class variables

            fm = getFontMetrics(getFont());
            baseline = fm.getMaxAscent();

            // Get the maximum height and width of the current control

            d = getSize();

            lines = breakIntoLines (text, d.width);

            //if (m_nVAlign == V_ALIGN_CENTER)

            if (m_nVAlign == Canvas.CENTER_ALIGNMENT)
            {
                int center = (d.height / 2);
                currentY = center - ( (lines.size() / 2) * fm.getHeight() );
            }
            //else if (m_nVAlign == V_ALIGN_BOTTOM)

            else if (m_nVAlign == Canvas.BOTTOM_ALIGNMENT)
            {
                currentY = d.height - ( lines.size() * fm.getHeight() );
            }

            // now we have broken into substrings, print them

            Enumeration elements = lines.elements();
            while (elements.hasMoreElements())
            {
                drawAlignedString(g, 
                  (String)(elements.nextElement()), 
                  0, currentY, d.width);
                currentY += fm.getHeight();
            }

            // We're done with the font metrics...

            fm = null;
        }
    }


    protected Vector breakIntoLines (String s, int width)
    {
        int fromIndex = 0;
        int pos = 0;
        int bestpos;
        String largestString;
        Vector lines = new Vector();

        // while we haven't run past the end of the string...

        while (fromIndex != -1)
        {
            // Automatically skip any spaces at the beginning of the line

            while (fromIndex < text.length() 
                   && text.charAt(fromIndex) == ' ')
            {
                ++fromIndex;
                // If we hit the end of line

                // while skipping spaces, we're done.

                if (fromIndex >= text.length()) break;
            }

            // fromIndex represents the beginning of the line

            pos = fromIndex;
            bestpos = -1;
            largestString = null;

            while (pos >= fromIndex)
            {
                boolean bHardNewline = false;
                int newlinePos = text.indexOf('\n', pos);
                int spacePos   = text.indexOf(' ', pos);

                if (newlinePos != -1 &&    // there is a newline and either

                     ((spacePos == -1) ||  // 1. there is no space, or

                      (spacePos != -1 && 
                        newlinePos < spacePos))) 
                        // 2. the newline is first

                {
                    pos = newlinePos;
                    bHardNewline = true;
                }
                else
                {
                    pos = spacePos;
                    bHardNewline = false;
                }

                // Couldn't find another space?

                if (pos == -1)
                {
                    s = text.substring(fromIndex);
                }
                else
                {
                    s = text.substring(fromIndex, pos);
                }

                // If the string fits, keep track of it.

                if (fm.stringWidth(s) < width)
                {
                    largestString = s;
                    bestpos = pos;

                    // If we've hit the end of the

                    // string or a newline, use it.

                    if (bHardNewline)
                        bestpos++;
                    if (pos == -1 || bHardNewline) break;
                }
                else
                {
                    break;
                }

                ++pos;
            }

            if (largestString == null)
            {
                // Couldn't wrap at a space, so find the largest line

                // that fits and print that.  Note that this will be

                // slightly off -- the width of a string will not necessarily

                // be the sum of the width of its characters, due to kerning.

                int totalWidth = 0;
                int oneCharWidth = 0;

                pos = fromIndex;

                while (pos < text.length())
                {
                    oneCharWidth = fm.charWidth(text.charAt(pos));
                    if ((totalWidth + oneCharWidth) >= width) break;
                    totalWidth += oneCharWidth;
                    ++pos;
                }

                lines.addElement (text.substring(fromIndex, pos));
                fromIndex = pos;
            }
            else
            {
                lines.addElement (largestString);
                fromIndex = bestpos;
            }
           }

           return lines;
       }


    protected void drawAlignedString(Graphics g, 
                   String s, int x, int y, int width)
    {
        int drawx;
        int drawy;

        drawx = x;
        drawy = y + baseline;

        if (m_nHAlign != Canvas.LEFT_ALIGNMENT)
        {
            int sw;

            sw = fm.stringWidth(s);

            if (m_nHAlign == Canvas.CENTER_ALIGNMENT)
            {
                drawx += (width - sw) / 2;
            }
            else if (m_nHAlign == Canvas.RIGHT_ALIGNMENT)
            {
                drawx = drawx + width - sw;
            }
        }

        g.drawString(s, drawx, drawy);
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here