2

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

vefthym
  • 7,422
  • 6
  • 32
  • 58
  • Swing components don't like been rotated, as you've not accounted for things like the change in dimensions or translated events. You can, however, use J(X)Layer, for [example](http://stackoverflow.com/questions/22976226/is-there-any-way-i-can-rotate-this-90-degrees/22976755#22976755) and [example](http://stackoverflow.com/questions/25252127/java-rotating-non-square-jpanel-component/25253453#25253453) – MadProgrammer Aug 11 '15 at 10:23
  • Try giving more height to the component that displays them? – milez Aug 11 '15 at 10:28

5 Answers5

2

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);
}
StanislavL
  • 56,971
  • 9
  • 68
  • 98
2

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.

d_air
  • 631
  • 1
  • 4
  • 12
  • @HiepChelsea Yes it does not solve. But it attempts to give you a hint or clue to the solution. If you notice in the example above. You will find that the labels on the upper part are aligned. But since all the labels do not fit in one line, it continues on the next line. This is one of the reasons that the labels appear to be not aligned. And if you experiment on the preferred sizes, you should find that it affects too. – d_air Aug 13 '15 at 11:54
  • @HiepChelsea Its hard pinpoint exactly the problem of your program because it's hard to replicate it exactly. If you can add more of your code so that we replicate your problem here, you can better help us helping you. see this: http://meta.stackexchange.com/questions/22754/sscce-how-to-provide-examples-for-programming-questions and this http://sscce.org/ – d_air Aug 13 '15 at 12:02
  • yes. you mean when labels is rotated, their height and width would change together. But i also wanna try to change preferredSize, it's still not work – Hiep Chelsea Aug 15 '15 at 09:10
2

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.

FredK
  • 4,094
  • 1
  • 9
  • 11
2

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.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • what is the library or package of TextIcon? My IDE here does not recognized it. – d_air Aug 11 '15 at 15:10
  • @d_air, I gave you a link to the blog containing information about the class. It is not a standard JDK libraray. – camickr Aug 11 '15 at 15:20
  • @HiepChelsea, What can't be solved? Be specific when you have a problem. It works fine for me. See the edit. – camickr Aug 13 '15 at 16:03
  • I've tried and it's only works with single label. I try to rotate with many labels then it's not work – Hiep Chelsea Aug 15 '15 at 09:08
  • @HiepChelsea, I gave you working code!!! If you can't copy and test the posted code I gave you, thn there is not much more I can do to help you. I am not a mind reader, I can't guess why your code is different my code. – camickr Aug 15 '15 at 14:50
-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; }
}
Pochmurnik
  • 780
  • 6
  • 18
  • 35
  • Hey @HiepChelsea, This is a test file that I was working on. I think I got it. Try this, if it works. The key is in the paintComponent function. Basically you need to set the original clip again after the rotation. This is just a test file and its not related to your code. Although you can grab the basic idea from and use it as per your code requirements. – Nimish Sogani Apr 05 '16 at 09:39