Multi Line Label extends JComponent : Label « Swing Components « Java






Multi Line Label extends JComponent

    
/*
 * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
 * 
 * http://izpack.org/
 * http://izpack.codehaus.org/
 * 
 * Copyright 1997,2002 Elmar Grom
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */



import javax.swing.*;
import java.awt.*;
import java.util.Vector;

/*---------------------------------------------------------------------------*/
/**
 * <BR>
 * <code>MultiLineLabel</code> may be used in place of javax.swing.JLabel. <BR>
 * <BR>
 * This class implements a component that is capable of displaying multiple lines of text. Line
 * breaks are inserted automatically whenever a line of text extends beyond the predefined maximum
 * line length. Line breaks will only be inserted between words, except where a single word is
 * longer than the maximum line length. Line breaks may be forced at any location in the text by
 * inserting a newline (\n). White space that is not valuable (i.e. is placed at the beginning of a
 * new line or at the very beginning or end of the text) is removed. <br>
 * <br>
 * <b>Note:</b> you can set the maximum width of the label either through one of the constructors
 * or you can call <code>setMaxWidth()</code> explicitly. If this is not set,
 * <code>MultiLineLabel</code> will derive its width from the parent component.
 *
 * @author Elmar Grom
 * @version 1.0 / 04-13-02
 */
/*---------------------------------------------------------------------------*
 * Reviving some old code here that was written before there was swing.
 * The original was written to work with awt. I had to do some masaging to
 * make it a JComponent and I hope it behaves like a reasonably good mannered
 * swing component.
 *---------------------------------------------------------------------------*/
public class MultiLineLabel extends JComponent
{

    /**
     *
     */
    private static final long serialVersionUID = 4051045255031894837L;

    public static final int LEFT = 0; // alignment constants

    public static final int CENTER = 1;

    public static final int RIGHT = 2;

    public static final int DEFAULT_MARGIN = 10;

    public static final int DEFAULT_ALIGN = LEFT;

    public static final int LEAST_ALLOWED = 200; // default setting for

    // maxAllowed

    private static final int FOUND = 0; // constants for string search.

    private static final int NOT_FOUND = 1;

    private static final int NOT_DONE = 0;

    private static final int DONE = 1;

    private static final char[] WHITE_SPACE = {' ', '\n', '\t'};

    private static final char[] SPACES = {' ', '\t'};

    private static final char NEW_LINE = '\n';

    protected Vector<String> line = new Vector<String>();// text lines to display

    protected String labelText; // text lines to display

    protected int numLines; // the number of lines

    protected int marginHeight; // top and bottom margins

    protected int marginWidth; // left and right margins

    protected int lineHeight; // total height of the font

    protected int lineAscent; // font height above the baseline

    protected int lineDescent; // font hight below the baseline

    protected int[] lineWidth; // width of each line

    protected int maxWidth; // width of the widest line

    private int maxAllowed = LEAST_ALLOWED; // max width allowed to use

    private boolean maxAllowedSet = false; // signals if the max allowed width

    // has been explicitly set

    protected int alignment = LEFT; // default text alignment

    /*-------------------------------------------------------------------*/
    /**
     * Constructor
     *
     * @param text       the text to be displayed
     * @param horMargin  the horizontal margin for the label
     * @param vertMargin the vertical margin for the label
     * @param maxWidth   the maximum allowed width of the text
     * @param justify    the text alignment for the label
     */
    /*-------------------------------------------------------------------*
     * <detailed description / implementation details if applicable>
     *-------------------------------------------------------------------*/
    public MultiLineLabel(String text, int horMargin, int vertMargin, int maxWidth, int justify)
    {
        this.labelText = text;
        this.marginWidth = horMargin;
        this.marginHeight = vertMargin;
        this.maxAllowed = maxWidth;
        this.maxAllowedSet = true;
        this.alignment = justify;
    }

    /*-------------------------------------------------------------------*/
    /**
     * Constructor using default max-width and alignment.
     *
     * @param label        the text to be displayed
     * @param marginWidth  the horizontal margin for the label
     * @param marginHeight the vertical margin for the label
     */
    /*-------------------------------------------------------------------*
     * <detailed description / implementation details if applicable>
     *-------------------------------------------------------------------*/
    public MultiLineLabel(String label, int marginWidth, int marginHeight)
    {
        this.labelText = label;
        this.marginWidth = marginWidth;
        this.marginHeight = marginHeight;
    }

    /*-------------------------------------------------------------------*/
    /**
     * Constructor using default max-width, and margin.
     *
     * @param label     the text to be displayed
     * @param alignment the text alignment for the label
     */
    /*-------------------------------------------------------------------*
     * <detailed description / implementation details if applicable>
     *-------------------------------------------------------------------*/
    public MultiLineLabel(String label, int alignment)
    {
        this.labelText = label;
        this.alignment = alignment;
    }

    /*-------------------------------------------------------------------*/
    /**
     * Constructor using default max-width, alignment, and margin.
     *
     * @param label the text to be displayed
     */
    /*-------------------------------------------------------------------*
     * <detailed description / implementation details if applicable>
     *-------------------------------------------------------------------*/
    public MultiLineLabel(String label)
    {
        this.labelText = label;
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method searches the target string for occurences of any of the characters in the source
     * string. The return value is the position of the first hit. Based on the mode parameter the
     * hit position is either the position where any of the source characters first was found or the
     * first position where none of the source characters where found.
     *
     * @param target the text to be searched
     * @param start  the start position for the search
     * @param source the list of characters to be searched for
     * @param mode   the search mode FOUND = reports first found NOT_FOUND = reports first not found
     * @return position of the first occurence
     */
    /*-------------------------------------------------------------------*
     * <detailed description / implementation details if applicable>
     *-------------------------------------------------------------------*/
    int getPosition(String target, int start, char[] source, int mode)
    {
        int status;
        int position;
        int scan;
        int targetEnd;
        int sourceLength;
        char temp;

        targetEnd = (target.length() - 1);
        sourceLength = source.length;
        position = start;

        if (mode == FOUND)
        {
            status = NOT_DONE;
            while (status != DONE)
            {
                position++;
                if (!(position < targetEnd)) // end of string reached, the
                // next
                { // statement would cause a runtime error
                    return (targetEnd);
                }
                temp = target.charAt(position);
                for (scan = 0; scan < sourceLength; scan++) // walk through the
                // source
                { // string and compare each char
                    if (source[scan] == temp)
                    {
                        status = DONE;
                    }
                }
            }
            return (position);
        }
        else if (mode == NOT_FOUND)
        {
            status = NOT_DONE;
            while (status != DONE)
            {
                position++;
                if (!(position < targetEnd)) // end of string reached, the
                // next
                { // statement would cause a runtime error
                    return (targetEnd);
                }
                temp = target.charAt(position);
                status = DONE;
                for (scan = 0; scan < sourceLength; scan++) // walk through the
                // source
                { // string and compare each char
                    if (source[scan] == temp)
                    {
                        status = NOT_DONE;
                    }
                }
            }
            return (position);
        }
        return (0);
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method scans the input string until the max allowed width is reached. The return value
     * indicates the position just before this happens.
     *
     * @param word word to break
     * @return position character position just before the string is too long
     */
    /*-------------------------------------------------------------------*
     * <detailed description / implementation details if applicable>
     *-------------------------------------------------------------------*/
    int breakWord(String word, FontMetrics fm)
    {
        int width;
        int currentPos;
        int endPos;

        width = 0;
        currentPos = 0;
        endPos = word.length() - 1;

        // make sure we don't end up with a negative position
        if (endPos <= 0)
        {
            return (currentPos);
        }
        // seek the position where the word first is longer than allowed
        while ((width < maxAllowed) && (currentPos < endPos))
        {
            currentPos++;
            width = fm.stringWidth(labelText.substring(0, currentPos));
        }
        // adjust to get the chatacter just before (this should make it a bit
        // shorter than allowed!)
        if (currentPos != endPos)
        {
            currentPos--;
        }
        return (currentPos);
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method breaks the label text up into multiple lines of text. Line breaks are established
     * based on the maximum available space. A new line is started whenever a line break is
     * encountered, even if the permissible length is not yet reached. Words are broken only if a
     * single word happens to be longer than one line.
     */
    /*-------------------------------------------------------------------*/
    private void divideLabel()
    {
        int width;
        int startPos;
        int currentPos;
        int lastPos;
        int endPos;

        line.clear();
        FontMetrics fm = this.getFontMetrics(this.getFont());

        startPos = 0;
        currentPos = startPos;
        lastPos = currentPos;
        endPos = (labelText.length() - 1);

        while (currentPos < endPos)
        {
            width = 0;
            // ----------------------------------------------------------------
            // find the first substring that occupies more than the granted
            // space.
            // Break at the end of the string or a line break
            // ----------------------------------------------------------------
            while ((width < maxAllowed) && (currentPos < endPos)
                    && (labelText.charAt(currentPos) != NEW_LINE))
            {
                lastPos = currentPos;
                currentPos = getPosition(labelText, currentPos, WHITE_SPACE, FOUND);
                width = fm.stringWidth(labelText.substring(startPos, currentPos));
            }
            // ----------------------------------------------------------------
            // if we have a line break we want to copy everything up to
            // currentPos
            // ----------------------------------------------------------------
            if (labelText.charAt(currentPos) == NEW_LINE)
            {
                lastPos = currentPos;
            }
            // ----------------------------------------------------------------
            // if we are at the end of the string we want to copy everything up
            // to
            // the last character. Since there seems to be a problem to get the
            // last
            // character if the substring definition ends at the very last
            // character
            // we have to call a different substring function than normal.
            // ----------------------------------------------------------------
            if (currentPos == endPos && width <= maxAllowed)
            {
                lastPos = currentPos;
                String s = labelText.substring(startPos);
                line.addElement(s);
            }
            // ----------------------------------------------------------------
            // in all other cases copy the substring that we have found to fit
            // and
            // add it as a new line of text to the line vector.
            // ----------------------------------------------------------------
            else
            {
                // ------------------------------------------------------------
                // make sure it's not a single word. If so we must break it at
                // the
                // proper location.
                // ------------------------------------------------------------
                if (lastPos == startPos)
                {
                    lastPos = startPos + breakWord(labelText.substring(startPos, currentPos), fm);
                }
                String s = labelText.substring(startPos, lastPos);
                line.addElement(s);
            }

            // ----------------------------------------------------------------
            // seek for the end of the white space to cut out any unnecessary
            // spaces
            // and tabs and set the new start condition.
            // ----------------------------------------------------------------
            startPos = getPosition(labelText, lastPos, SPACES, NOT_FOUND);
            currentPos = startPos;
        }

        numLines = line.size();
        lineWidth = new int[numLines];
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method finds the font size, each line width and the widest line.
     */
    /*-------------------------------------------------------------------*/
    protected void measure()
    {
        if (!maxAllowedSet)
        {
            maxAllowed = getParent().getSize().width;
        }

        // return if width is too small
        if (maxAllowed < (20))
        {
            return;
        }

        FontMetrics fm = this.getFontMetrics(this.getFont());

        // return if no font metrics available
        if (fm == null)
        {
            return;
        }

        divideLabel();

        this.lineHeight = fm.getHeight();
        this.lineDescent = fm.getDescent();
        this.maxWidth = 0;

        for (int i = 0; i < numLines; i++)
        {
            this.lineWidth[i] = fm.stringWidth(this.line.elementAt(i));
            if (this.lineWidth[i] > this.maxWidth)
            {
                this.maxWidth = this.lineWidth[i];
            }
        }
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method draws the label.
     *
     * @param graphics the device context
     */
    /*-------------------------------------------------------------------*/
    public void paint(Graphics graphics)
    {
        int x;
        int y;

        measure();
        Dimension d = this.getSize();

        y = lineAscent + (d.height - (numLines * lineHeight)) / 2;

        for (int i = 0; i < numLines; i++)
        {
            y += lineHeight;
            switch (alignment)
            {
                case LEFT:
                    x = marginWidth;
                    break;
                case CENTER:
                    x = (d.width - lineWidth[i]) / 2;
                    break;
                case RIGHT:
                    x = d.width - marginWidth - lineWidth[i];
                    break;
                default:
                    x = (d.width - lineWidth[i]) / 2;
            }
            graphics.drawString(line.elementAt(i), x, y);
        }
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to set the label text
     *
     * @param labelText the text to be displayed
     */
    /*-------------------------------------------------------------------*/
    public void setText(String labelText)
    {
        this.labelText = labelText;
        repaint();
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to set the font that should be used to draw the label
     *
     * @param font font to be used within the label
     */
    /*-------------------------------------------------------------------*/
    public void setFont(Font font)
    {
        super.setFont(font);
        repaint();
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to set the color in which the text should be drawn
     *
     * @param color the text color
     */
    /*-------------------------------------------------------------------*/
    public void setColor(Color color)
    {
        super.setForeground(color);
        repaint();
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to set the text alignment for the label
     *
     * @param alignment the alignment, possible values are LEFT, CENTER, RIGHT
     */
    /*-------------------------------------------------------------------*/
    public void setJustify(int alignment)
    {
        this.alignment = alignment;
        repaint();
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to set the max allowed line width
     *
     * @param width the max allowed line width in pixels
     */
    /*-------------------------------------------------------------------*/
    public void setMaxWidth(int width)
    {
        this.maxAllowed = width;
        this.maxAllowedSet = true;
        repaint();
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to set the horizontal margin
     *
     * @param margin the margin to the left and to the right of the label
     */
    /*-------------------------------------------------------------------*/
    public void setMarginWidth(int margin)
    {
        this.marginWidth = margin;
        repaint();
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to set the vertical margin for the label
     *
     * @param margin the margin on the top and bottom of the label
     */
    /*-------------------------------------------------------------------*/
    public void setMarginHeight(int margin)
    {
        this.marginHeight = margin;
        repaint();
    }

    /*-------------------------------------------------------------------*/
    /**
     * Moves and resizes this component. The new location of the top-left corner is specified by
     * <code>x</code> and <code>y</code>, and the new size is specified by <code>width</code>
     * and <code>height</code>.
     *
     * @param x      The new x-coordinate of this component.
     * @param y      The new y-coordinate of this component.
     * @param width  The new width of this component.
     * @param height The new height of this component.
     */
    /*-------------------------------------------------------------------*/
    public void setBounds(int x, int y, int width, int height)
    {
        super.setBounds(x, y, width, height);
        this.maxAllowed = width;
        this.maxAllowedSet = true;
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to retrieve the text alignment for the label
     *
     * @return alignment the text alignment currently in use for the label
     */
    /*-------------------------------------------------------------------*/
    public int getAlignment()
    {
        return (this.alignment);
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to retrieve the horizontal margin for the label
     *
     * @return marginWidth the margin currently in use to the left and right of the label
     */
    /*-------------------------------------------------------------------*/
    public int getMarginWidth()
    {
        return (this.marginWidth);
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method may be used to retrieve the vertical margin for the label
     *
     * @return marginHeight the margin currently in use on the top and bottom of the label
     */
    /*-------------------------------------------------------------------*/
    public int getMarginHeight()
    {
        return (this.marginHeight);
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method is typically used by the layout manager, it reports the necessary space to
     * display the label comfortably.
     */
    /*-------------------------------------------------------------------*/
    public Dimension getPreferredSize()
    {
        measure();
        return (new Dimension(maxAllowed, (numLines * (lineHeight + lineAscent + lineDescent))
                + (2 * marginHeight)));
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method is typically used by the layout manager, it reports the absolute minimum space
     * required to display the entire label.
     */
    /*-------------------------------------------------------------------*/
    public Dimension getMinimumSize()
    {
        measure();
        return (new Dimension(maxAllowed, (numLines * (lineHeight + lineAscent + lineDescent))
                + (2 * marginHeight)));
    }

    /*-------------------------------------------------------------------*/
    /**
     * This method is called by the system after this object is first created.
     */
    /*-------------------------------------------------------------------*/
    public void addNotify()
    {
        super.addNotify(); // invoke the superclass
    }
}
/*---------------------------------------------------------------------------*/

   
    
    
    
  








Related examples in the same category

1.MultiLine Label
2.Multi Line Label extends JPanel
3.Link Label
4.Vertical Label UI
5.Label with large font and ANTIALIAS paint
6.Label 3D
7.URL Label
8.Hyperlink Label
9.Bevel TextBevel Text
10.A JLabel that can be underlined, implements Scrollable
11.Gradient Label
12.Hyperlink Label 2
13.Computes a reasonable set of labels for a data interval and number of labels.
14.Multi-label Label
15.Shadow Label
16.Button Label