The process of rotating a component is more complicated then just painting the rotated image. There are a number of interconnected layers which generate contractual obligations.
For example, the size of the clipping rectangle set to the Graphics
context that is passed to your component for painting is determined by the current size of the component, this size is calculated by the layout manager, but may consider the preferred size of the individual component...
That's a lot of re-wiring that needs to be considered...call my lazy, but if I can find a ready made solution, I'd prefer to use it, so based on this example, I can generate the following...
The red LineBorder
around the field panel is there to show that the entire component is been rotated, not just it's children. The use of pack
also demonstrates that this solution is still honouring it's contractual obligations to the rest of the API
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
import org.jdesktop.jxlayer.JXLayer;
import org.pbjar.jxlayer.demo.TransformUtils;
import org.pbjar.jxlayer.plaf.ext.transform.DefaultTransformModel;
public class RotateExample {
public static void main(String[] args) {
new RotateExample();
}
public RotateExample() {
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 FieldPane fieldPane;
private DefaultTransformModel transformModel;
private JButton rotate;
private double angle;
public ExamplePane() {
setLayout(new BorderLayout());
rotate = new JButton("Rotate");
rotate.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
transformModel.setRotation(Math.toRadians((angle += 90)));
SwingUtilities.getWindowAncestor(ExamplePane.this).pack();
}
});
fieldPane = new FieldPane();
transformModel = new DefaultTransformModel();
transformModel.setRotation(Math.toRadians(0));
transformModel.setScaleToPreferredSize(true);
JXLayer<JComponent> rotatePane = TransformUtils.createTransformJXLayer(fieldPane, transformModel);
JPanel content = new JPanel(new GridBagLayout());
content.add(rotatePane);
add(rotate, BorderLayout.SOUTH);
add(content);
}
}
public class FieldPane extends JPanel {
public FieldPane() {
setBorder(new LineBorder(Color.RED));
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.
You will also need JHLabs filters
Updated
And using your Screen
panel (without the custom painting)...
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…