Rotating a JTextField vertically

I've seen a number of questions that ask how to rotate a JLabel or image at an arbitrary angle. All I need to do is rotate my text field 90 degrees, but I haven't found an easier way specifically for that angle. I thought I copied the answers correctly, but my text field is not rotating.

Here's an SSCCE of what I'm doing:

import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class VerticalRotationSSCCE {

private static class VerticalTextField extends JTextField {

    private static final long serialVersionUID = 1L;

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

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        int cx = getWidth() / 2;
        int cy = getHeight() / 2;
        g2.rotate(1/2 * Math.PI, cx, cy);
        super.paintComponent(g2);
    }

}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            JFrame frame = new JFrame();
            frame.getContentPane().add(new VerticalTextField("Foo"));
            frame.pack();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }

    });
}

}

What am I missing from the answers on how to rotate components?


Solution 1:

Actually, yes, it can be done, but will require some additional libraries and access to some source code which has vanished off the net.

Using JXLayer, it is possible to transform live components at runtime...

enter image description here

public class JLayerTransform {

    public static void main(String[] args) {
        new JLayerTransform();
    }

    public JLayerTransform() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new ExamplePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ExamplePane extends JPanel {

        private JSlider slider;
        private FieldPane fieldPane;
        private DefaultTransformModel transformModel;

        public ExamplePane() {

            setLayout(new BorderLayout());

            slider = new JSlider(0, 360);
            slider.setValue(0);
            slider.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {

                    transformModel.setRotation(Math.toRadians(slider.getValue()));

                }
            });

            fieldPane = new FieldPane();

            transformModel = new DefaultTransformModel();
            transformModel.setRotation(Math.toRadians(0));
            transformModel.setScaleToPreferredSize(true);
            JXLayer<JComponent> rotatePane = TransformUtils.createTransformJXLayer(fieldPane, transformModel);

            add(slider, BorderLayout.NORTH);
            add(rotatePane);

        }
    }

    public class FieldPane extends JPanel {

        public FieldPane() {
            setLayout(new GridBagLayout());

            JTextField field = new JTextField(10);
            field.setText("Hello world");

            add(field);

        }
    }
}

Caveats

This requires JXLayer (I was using version 3), SwingX (I was using version 1.6.4) and Piet Blok's excellent examples, which no longer seem to be available on the net...

I've put all the source code of JXLayer (version 3) and Piet's examples into a single zip and I would suggest, if you are interested, you grab a copy and store it some where safe.

Solution 2:

You can't usefully rotate interactive components without also transforming the mouse coordinates, but you can rotate the graphics context to render non-interactive components like JLabel, as shown here.

In your example, 1/2 * Math.PI != Math.PI / 2.

image