Java: Vertical Label in Swing

This is an article I’ve published over 8 years ago on jroller. I’ve now republished it on my current blog because I was asked to clarify the license terms (see next paragraph) and I found it better to do it here than to update a post on a blog I’m not maintaining anymore.

License clarification: You can use the code of any article on this blog as you wish. I’ve just published this code in the hope to be helpful and do not expect anything in return. So from my point of view you can consider it being released under the WTFPL license terms.

Today, let’s see how to implement a vertical label in Swing. This component should extend JLabel and provide the possibility to rotate 90° to the right or to the left.

Like normal JLabel, it should work whether it contains an icon, a text or both.

Here’s a screenshot of how it should look like:

vertical label

The label with a rotation to the left, no rotation and a rotation to the right.

So that the label painted according to the current look and feel, I didn’t want to paint it myself but to delegate it and rotate it.

In order to do this, I had to rotate and translate the graphics object. The remaining problem is that the UI delegate uses some methods of the label to get the size of the component and the insets. So we have to trick the UI delegate into thinking that the component is horizontal and not vertical.

  public Insets getInsets(Insets insets) {
        insets = super.getInsets(insets);
        if (painting) {
            if (rotation == ROTATE_LEFT) {
                int temp = insets.bottom;
                insets.bottom = insets.left;
                insets.left = insets.top;
                insets.top = insets.right;
                insets.right = temp;
            }
            else if (rotation == ROTATE_RIGHT) {
                int temp = insets.bottom;
                insets.bottom = insets.right;
                insets.right = insets.top;
                insets.top = insets.left;
                insets.left = temp;
            }
        }
        return insets;
    }
    public Insets getInsets() {
        Insets insets = super.getInsets();
        if (painting) {
            if (rotation == ROTATE_LEFT) {
                int temp = insets.bottom;
                insets.bottom = insets.left;
                insets.left = insets.top;
                insets.top = insets.right;
                insets.right = temp;
            }
            else if (rotation == ROTATE_RIGHT) {
                int temp = insets.bottom;
                insets.bottom = insets.right;
                insets.right = insets.top;
                insets.top = insets.left;
                insets.left = temp;
            }
        }
        return insets;
    }
    public int getWidth() {
        if ((painting) && (isRotated()))
            return super.getHeight();
        return super.getWidth();
    }
    public int getHeight() {
        if ((painting) && (isRotated()))
            return super.getWidth();
        return super.getHeight();
    }

The painting variable is set in the paintComponent method just before calling the method of the super class:

protected void paintComponent(Graphics g) {
	Graphics2D g2d = (Graphics2D) g;

	if (isRotated())
		g2d.rotate(Math.toRadians(90 * rotation));
	if (rotation == ROTATE_RIGHT)
		g2d.translate(0, -this.getWidth());
	else if (rotation == ROTATE_LEFT)
		g2d.translate(-this.getHeight(), 0);
	painting = true;

	super.paintComponent(g2d);

	painting = false;
	if (isRotated())
		g2d.rotate(-Math.toRadians(90 * rotation));
	if (rotation == ROTATE_RIGHT)
		g2d.translate(-this.getWidth(), 0);
	else if (rotation == ROTATE_LEFT)
		g2d.translate(0, -this.getHeight());
}

Now one remaining problem is that a normal label uses the icon and the text to compute it’s preferred, minimum and maximum size assuming it’s layed out horizontally. Now the layour managers use this methods to layout the components. So we need to return sizes based on a vertical layout. Since we do not want to compute the sizes ourselves, we have to let the super class compute it and switch height and width (when there’s a rotation):

public Dimension getPreferredSize() {
	Dimension d = super.getPreferredSize();
	if (isRotated()) {
		int width = d.width;
		d.width = d.height;
		d.height = width;
	}
	return d;
}

public Dimension getMinimumSize() {
	Dimension d = super.getMinimumSize();
	if (isRotated()) {
		int width = d.width;
		d.width = d.height;
		d.height = width;
	}
	return d;
}

public Dimension getMaximumSize() {
	Dimension d = super.getMaximumSize();
	if (isRotated()) {
		int width = d.width;
		d.width = d.height + 10;
		d.height = width + 10;
	}
	return d;
}

That’s it, now our component behaves exactly like a JLabel except that it can be rotated to the left or to the right. The whole source code here for your reference:

package org.jroller.henribenoit.swing;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;

public class VerticalLabel extends JLabel {
    public final static int ROTATE_RIGHT = 1;

    public final static int DONT_ROTATE = 0;

    public final static int ROTATE_LEFT = -1;

    private int rotation = DONT_ROTATE;

    private boolean painting = false;

    public VerticalLabel() {
        super();
    }

    public VerticalLabel(Icon image, int horizontalAlignment) {
        super(image, horizontalAlignment);
    }

    public VerticalLabel(Icon image) {
        super(image);
    }

    public VerticalLabel(String text, Icon icon, int horizontalAlignment) {
        super(text, icon, horizontalAlignment);
    }

    public VerticalLabel(String text, int horizontalAlignment) {
        super(text, horizontalAlignment);
    }

    public VerticalLabel(String text) {
        super(text);
    }

    public int getRotation() {
        return rotation;
    }

    public void setRotation(int rotation) {
        this.rotation = rotation;
    }

    public boolean isRotated() {
        return rotation != DONT_ROTATE;
    }

    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;

        if (isRotated())
            g2d.rotate(Math.toRadians(90 * rotation));
        if (rotation == ROTATE_RIGHT)
            g2d.translate(0, -this.getWidth());
        else if (rotation == ROTATE_LEFT)
            g2d.translate(-this.getHeight(), 0);
        painting = true;

        super.paintComponent(g2d);

        painting = false;
        if (isRotated())
            g2d.rotate(-Math.toRadians(90 * rotation));
        if (rotation == ROTATE_RIGHT)
            g2d.translate(-this.getWidth(), 0);
        else if (rotation == ROTATE_LEFT)
            g2d.translate(0, -this.getHeight());
    }

    public Insets getInsets(Insets insets) {
        insets = super.getInsets(insets);
        if (painting) {
            if (rotation == ROTATE_LEFT) {
                int temp = insets.bottom;
                insets.bottom = insets.left;
                insets.left = insets.top;
                insets.top = insets.right;
                insets.right = temp;
            }
            else if (rotation == ROTATE_RIGHT) {
                int temp = insets.bottom;
                insets.bottom = insets.right;
                insets.right = insets.top;
                insets.top = insets.left;
                insets.left = temp;
            }
        }
        return insets;
    }

    public Insets getInsets() {
        Insets insets = super.getInsets();
        if (painting) {
            if (rotation == ROTATE_LEFT) {
                int temp = insets.bottom;
                insets.bottom = insets.left;
                insets.left = insets.top;
                insets.top = insets.right;
                insets.right = temp;
            }
            else if (rotation == ROTATE_RIGHT) {
                int temp = insets.bottom;
                insets.bottom = insets.right;
                insets.right = insets.top;
                insets.top = insets.left;
                insets.left = temp;
            }
        }
        return insets;
    }

    public int getWidth() {
        if ((painting) && (isRotated()))
            return super.getHeight();
        return super.getWidth();
    }

    public int getHeight() {
        if ((painting) && (isRotated()))
            return super.getWidth();
        return super.getHeight();
    }

    public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        if (isRotated()) {
            int width = d.width;
            d.width = d.height;
            d.height = width;
        }
        return d;
    }

    public Dimension getMinimumSize() {
        Dimension d = super.getMinimumSize();
        if (isRotated()) {
            int width = d.width;
            d.width = d.height;
            d.height = width;
        }
        return d;
    }

    public Dimension getMaximumSize() {
        Dimension d = super.getMaximumSize();
        if (isRotated()) {
            int width = d.width;
            d.width = d.height + 10;
            d.height = width + 10;
        }
        return d;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new FlowLayout());
        VerticalLabel label = new VerticalLabel("Testing something");
        VerticalLabel label2 = new VerticalLabel("Testing something");
        VerticalLabel label3 = new VerticalLabel("Testing something");
        label.setIcon(new ImageIcon("shortcut.png"));
        label2.setIcon(new ImageIcon("shortcut.png"));
        label3.setIcon(new ImageIcon("shortcut.png"));
        label.setRotation(VerticalLabel.ROTATE_LEFT);
        label2.setRotation(VerticalLabel.DONT_ROTATE);
        label3.setRotation(VerticalLabel.ROTATE_RIGHT);
        frame.getContentPane().add(label);
        frame.getContentPane().add(label2);
        frame.getContentPane().add(label3);
        frame.pack();
        frame.setVisible(true);
    }
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *