简体   繁体   中英

Java Rotating Icon in JLabel

Hi im having a problem trying to rotate an image inside a JLabel. I get this code from StackOverflow, and im trying to change it a little bit so that insted of the image rotating in a Tab is rotating in a JLabel.

public class ProgressTabbedPane {

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            JFrame frame = new JFrame("RotatingIcon"); 
            JTabbedPane tabbedPane = new JTabbedPane();
            JLabel lable = new JLabel();



            tabbedPane.addTab("Searching", new RotatingIcon(new ImageIcon("disk.png"), tabbedPane, 10), new JLabel( /*new ImageIcon( "resources/images/rotatingIcon.gif" )*/));               
            frame.getContentPane().add(tabbedPane);                
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            //frame.setUndecorated(true);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);

        }
    });
}

private static class RotatingIcon implements Icon {

    private final Icon delegateIcon;
    private double angleInDegrees = 90;
    final private Timer rotatingTimer;

    private RotatingIcon(Icon icon, final JComponent component, int vrotating) {
        delegateIcon = icon;
        rotatingTimer = new Timer(vrotating, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                angleInDegrees = angleInDegrees + 1;
                if (angleInDegrees == 360) {
                    angleInDegrees = 0;
                }
                component.repaint();

            }
        });
        rotatingTimer.setRepeats(false);
        rotatingTimer.start();

    }

    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
        rotatingTimer.stop();
        Graphics2D g2 = (Graphics2D) g.create();
        int cWidth = delegateIcon.getIconWidth() / 2;
        int cHeight = delegateIcon.getIconHeight() / 2;
        Rectangle r = new Rectangle(x, y, delegateIcon.getIconWidth(), delegateIcon.getIconHeight());
        g2.setClip(r);
        AffineTransform original = g2.getTransform();
        AffineTransform at = new AffineTransform();
        at.concatenate(original);
        at.rotate(Math.toRadians(angleInDegrees), x + cWidth, y + cHeight);
        g2.setTransform(at);
        delegateIcon.paintIcon(c, g2, x, y);
        g2.setTransform(original);
        rotatingTimer.start();
    }

    @Override
    public int getIconWidth() {
        return delegateIcon.getIconWidth();
    }

    @Override
    public int getIconHeight() {
        return delegateIcon.getIconHeight();
    }
}

} This is working, the image is rotating. However when i change it to this.

public class ProgressTabbedPane {

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            JFrame frame = new JFrame("RotatingIcon"); 
            JTabbedPane tabbedPane = new JTabbedPane();
            JLabel lable = new JLabel();




            lable.setIcon(new RotatingIcon(new ImageIcon(disk.png"), tabbedPane, 10));                
            frame.getContentPane().add(lable);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            //frame.setUndecorated(true);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);

        }
    });
}

private static class RotatingIcon implements Icon {

    private final Icon delegateIcon;
    private double angleInDegrees = 90;
    final private Timer rotatingTimer;

    private RotatingIcon(Icon icon, final JComponent component, int vrotating) {
        delegateIcon = icon;
        rotatingTimer = new Timer(vrotating, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                angleInDegrees = angleInDegrees + 1;
                if (angleInDegrees == 360) {
                    angleInDegrees = 0;
                }
                component.repaint();

            }
        });
        rotatingTimer.setRepeats(false);
        rotatingTimer.start();

    }

    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
        rotatingTimer.stop();
        Graphics2D g2 = (Graphics2D) g.create();
        int cWidth = delegateIcon.getIconWidth() / 2;
        int cHeight = delegateIcon.getIconHeight() / 2;
        Rectangle r = new Rectangle(x, y, delegateIcon.getIconWidth(), delegateIcon.getIconHeight());
        g2.setClip(r);
        AffineTransform original = g2.getTransform();
        AffineTransform at = new AffineTransform();
        at.concatenate(original);
        at.rotate(Math.toRadians(angleInDegrees), x + cWidth, y + cHeight);
        g2.setTransform(at);
        delegateIcon.paintIcon(c, g2, x, y);
        g2.setTransform(original);
        rotatingTimer.start();
    }

    @Override
    public int getIconWidth() {
        return delegateIcon.getIconWidth();
    }

    @Override
    public int getIconHeight() {
        return delegateIcon.getIconHeight();
    }
}

}

this stops working, im sorry if it is a stupid question, but i dont seem to find the answer.

Thank you

A painting method should only be used to paint something. It should not stop/start a Timer. So I would guess that you need get rid of the Timer logic from the painting method and then set the Timer to repeat so that continuous events are generated.

For an alternative approach check out the Animated Icon .

The Animated Icon will hold a list of Icons to display sequentially based on a Timer. When the Timer fires the next Icon in the cycle is displaye. You can configure the animation to be continuous or specify the number of cycles to display each Icon.

Note: this solution should be more efficient because it only repaints the Icon, not the entire Component.

If you don't like the idea of creating all the Icons for the animation then you can use the Rotated Icon . With this class you set the degrees of rotation for the Icon. Then the Timer becomes completely separated from the class. Then when the Timer code fires you would increment the degrees of rotation.

Simple example using the AnimatedIcon :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SSCCE extends JPanel
{
    public SSCCE()
    {
        setLayout( new BorderLayout() );

        JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.add("1", new JPanel());
        tabbedPane.add("2", new JPanel());
        add(tabbedPane);

        AnimatedIcon icon = new AnimatedIcon(tabbedPane, 250, 3);
        ImageIcon duke = new ImageIcon( "copy16.gif" );
        icon.addIcon( duke );

        for (int angle = 30; angle < 360; angle += 30)
        {
            icon.addIcon( new RotatedIcon(duke, angle) );
        }

        tabbedPane.setIconAt(0, icon);
        icon.start();
    }


    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( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM