Hiep Chelsea
Hiep Chelsea

Reputation: 67

Swing Java Rotate JLabel but text be erased

I'm using swing Java to try to do something with java. Now I want to rotate JLabel and I did that. But unfortunelately, a part of my text in JLabel is erased (as in the image below). I have tried search but seem no one has problems as same as mine. I guess it's occured caused JLabels they overlaped.

enter image description here

and this is my code

serviceName[j] = new JLabel(name){
    protected void paintComponent(Graphics g) {

        Graphics2D g2 = (Graphics2D)g;
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        AffineTransform aT = g2.getTransform();
        Shape oldshape = g2.getClip();
        aT.rotate(Math.toRadians(300));
        g2.setTransform(aT);
        g2.setClip(oldshape);
        super.paintComponent(g);
    }
};

Can you give me the way to solved it

Upvotes: 2

Views: 1463

Answers (5)

Nimish Sogani
Nimish Sogani

Reputation: 1

import java.awt.Color; 
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;

public class Test {
    public static void main(String[] args) {
        // Create the first label, which will be rotated later.
        Test.RotateLabel one = new Test.RotateLabel( "Rotated", 100, 100 );
        one.setRotation( 270 );
        JLayeredPane pane = new JLayeredPane();
        pane.setLayer( one, JLayeredPane.DEFAULT_LAYER );
        pane.add( one );
        pane.setBorder(new javax.swing.border.LineBorder(Color.BLACK,1));
        // Put the container pane in a frame and show the frame.
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( pane );
        frame.setSize( 500, 500 );
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }

    static class RotateLabel extends JLabel {
        private static final long serialVersionUID = 1L;
        private int angle = 0;
        public RotateLabel( String text, int x, int y ) {
        super( text );
        setBorder( new javax.swing.border.CompoundBorder( 
            new javax.swing.border.LineBorder( Color.red, 1), getBorder() ) );
        int width = getPreferredSize().width;
        int height = getPreferredSize().height;
        setBounds(x, y, width, height);
    }

    @Override
    public void paintComponent( Graphics g ) {
        Graphics2D gx = (Graphics2D) g;
        Shape old = gx.getClip();
        gx.rotate(-Math.toRadians(45), getWidth() / 2, getHeight() / 2);
        gx.setClip(old);
        super.paintComponent(gx);
    }

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

Upvotes: -1

d_air
d_air

Reputation: 641

You may find some hints from this small program. Experiment on the values of setPrefferedSize to have more ideas. If you still can't solve the problem, please edit and add more codes in your question above.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.*;

public class InclinedLabels extends JFrame{
    /** Creates a new instance of InclinedLabels */
    public InclinedLabels() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        JPanel jPanel1 = new JPanel();
        jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        add(jPanel1);

        JPanel jPanel2 = new JPanel();
        jPanel2.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        jPanel2.setPreferredSize(new Dimension(10, 100));
        add(jPanel2, BorderLayout.NORTH);


        jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        jPanel1.setPreferredSize(new java.awt.Dimension(200, 200));
        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-400)/2, (screenSize.height-352)/2, 300, 352);



        String str = "The quick brown fox jumps over the lazy dog";
        String[] word = str.split(" ");
        JLabel[] serviceName = new JLabel[str.length()];
        String name;
        for (int j=0; j<word.length; j++) {
            name = word[j];
            serviceName[j]  = new JLabel(name){
                protected void paintComponent(Graphics g) {

                    Graphics2D g2 = (Graphics2D)g;
                    g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                    AffineTransform aT = g2.getTransform();
                    Shape oldshape = g2.getClip();
                    aT.rotate(Math.toRadians(300));
                    g2.setTransform(aT);
                    g2.setClip(oldshape);
                    super.paintComponent(g);
                }
            };
            serviceName[j].setPreferredSize(new Dimension(50,20));
            serviceName[j].setBorder(BorderFactory.createLineBorder(Color.RED));
            jPanel1.add(serviceName[j]);
        }

    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new InclinedLabels().setVisible(true);
            }
        });
    }
}

Update: I found a much closer hint that may solve this problem. The big factor here is the component layout. The null layout allows overlapping of JLabel components so it is the most appropriate layout to be used here. Then you have to customize the location and size of the labels through the setBounds method. In the code below there is serviceName[j].setBounds(xOffset + j*20,180, 170, 15); So in every loop iteration, the x location of the label is increased by 20. The size of all labels is 170 by 15. I also placed temporary borders to the components to help in understanding the output.

import java.awt.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;

public class InclinedLabels extends JFrame{

    /** Creates a new instance of InclinedLabels */
    public InclinedLabels() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-360)/2, (screenSize.height-352)/2, 360, 352);

        JPanel jPanel1 = new JPanel();
        jPanel1.setBorder(BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        jPanel1.setLayout(null);  // null layout allows overlapping of components
        add(jPanel1);

        JPanel jPanel2 = new JPanel();
        jPanel2.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        jPanel2.setPreferredSize(new Dimension(10, 100));
        add(jPanel2, BorderLayout.NORTH);


        String str = "The quick brown fox jumpsssssssssssss123456 over the lazy dogssssssssssssss123456";
        String[] word = str.split(" ");
        JLabel[] serviceName = new JLabel[str.length()];
        String name;
        int xOffset = 30;
        for (int j=0; j<word.length; j++) {
            name = word[j];
            serviceName[j]  = new JLabel(name){
                protected void paintComponent(Graphics g) {
                    Graphics2D g2 = (Graphics2D)g;
                    g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                    AffineTransform aT = g2.getTransform();
                    Shape oldshape = g2.getClip();
                    aT.rotate(Math.toRadians(300));
                    g2.setTransform(aT);
                    g2.setClip(oldshape);
                    super.paintComponent(g2);

                }
            };

            serviceName[j].setBounds(xOffset + j*20,180, 170, 15); // experiment here
            serviceName[j].setBorder(BorderFactory.createLineBorder(Color.RED));

            jPanel1.add(serviceName[j]);
        }

    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new InclinedLabels().setVisible(true);
            }
        });
    }

}

The limitation that I found in the code above is the width of the parent panel. In the example, the label having the text dogssssssssssssss123456 was not printed in whole. This can be overcome by increasing the width of the frame which in turn increases the width of jPanel1.

Upvotes: 2

camickr
camickr

Reputation: 324108

Instead of attempting to rotate the component, another approach would be to create a Text Icon and add the Icon to a JLabel.

Once you have created the TextIcon you can then create a Rotated Icon to add to the label. The RotatedIcon will calculate the proper size of the Icon so therefore the size of the label will also be correct and no custom painting is required.

So the basic code would be something like:

JLabel label = new JLabel();
TextIcon textlIcon = new TextIcon(label, "Rotated Text");
label.setIcon( new RotatedIcon(textIcon, 300) );

Edit:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.border.*;
import javax.swing.table.*;
import java.io.*;

public class SSCCE extends JPanel
{
    public SSCCE()
    {
        OverlapLayout layout = new OverlapLayout(new Point(20, 0));
        setLayout( layout );

        addLabel("one");
        addLabel("two");
        addLabel("three or more");
        addLabel("four");
    }

    private void addLabel(String text)
    {
        JLabel label = new JLabel();
        TextIcon textIcon = new TextIcon(label, text);
        label.setIcon( new RotatedIcon(textIcon, 300) );
        label.setVerticalAlignment(JLabel.BOTTOM);
        add(label);
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new SSCCE());
        frame.setLocationByPlatform( true );
        frame.pack();
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}

This example also uses the Overlap Layout so the labels can be painted over top of one another.

Upvotes: 2

FredK
FredK

Reputation: 4084

Your JLabel subclass should also override getPreferredSize() to report the size it will be when it is rotated; otherwise the any layout manager that uses asks your component for its preferred size will use JLabel's version, which assumes the text is drawn horizontally.

Upvotes: 2

StanislavL
StanislavL

Reputation: 57381

You should restore original transform and clip after your painting. Like this

protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D)g;
    g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    AffineTransform aT = g2.getTransform();
    Shape oldshape = g2.getClip();

    g2.rotate(Math.toRadians(300));
    super.paintComponent(g);

    g2.setTransform(aT);
    g2.setClip(oldshape);
}

Upvotes: 2

Related Questions