Example video:
TransformRootPane.java
Code: Select all
package misc;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
public class TransformRootPane extends JRootPane {
private double rotation = 0.0;
private double scaleX = 1.0;
private double scaleY = 1.0;
private double translateX = 0.0;
private double translateY = 0.0;
public TransformRootPane() {
TransformGlassPane gp = new TransformGlassPane(this);
setGlassPane(gp);
gp.setVisible(true);
setLayout(new TransformRootPaneLayout());
}
protected static Dimension getMaximumSize(Component c) {
Dimension size = c.getSize();
if (size.getWidth() == 0.0 && size.getHeight() == 0.0)
size = c.getPreferredSize();
double dist = Point.distance(0.0, 0.0, size.getWidth(), size.getHeight());
return new Dimension((int) dist, (int) dist);
}
public Point convertPoint(Point point) {
Container cp = getContentPane();
Dimension maxSize = getMaximumSize(cp);
double w = maxSize.getWidth();
double h = maxSize.getHeight();
AffineTransform trans = AffineTransform.getScaleInstance(scaleX, scaleY);
trans.rotate(rotation,
(translateX + w / 2.0) * scaleX,
(translateY + h / 2.0) * scaleY);
Point2D ptSrc = new Point2D.Double(point.getX(), point.getY());
Point2D ptDst = trans.transform(ptSrc, null);
return new Point(
(int) (ptDst.getX() + translateX + (w / 2 - cp.getWidth() / 2)),
(int) (ptDst.getY() + translateY + (h / 2 - cp.getHeight() / 2)));
}
public Point revertPoint(Point point) {
Container cp = getContentPane();
Dimension maxSize = getMaximumSize(cp);
double w = maxSize.getWidth();
double h = maxSize.getHeight();
AffineTransform trans = AffineTransform.getScaleInstance(
scaleX == 0.0 ? 0.0 : 1.0 / scaleX,
scaleY == 0.0 ? 0.0 : 1.0 / scaleY);
trans.rotate(-rotation,
(translateX + w / 2.0) * scaleX,
(translateY + h / 2.0) * scaleY);
Point2D ptSrc = new Point2D.Double(point.getX(), point.getY());
Point2D ptDst = trans.transform(ptSrc, null);
return new Point(
(int) (ptDst.getX() - translateX - (w / 2 - cp.getWidth() / 2)),
(int) (ptDst.getY() - translateY - (h / 2 - cp.getHeight() / 2)));
}
@Override public Dimension getPreferredSize() {
Container cp = getContentPane();
Dimension cpd = cp.getPreferredSize();
Dimension d = super.getPreferredSize();
Dimension maxcpd = getMaximumSize(cp);
return new Dimension(
(int) (d.getWidth() - cpd.getWidth()
+ scaleX * (maxcpd.getWidth() + translateX)),
(int) (d.getHeight() - cpd.getHeight()
+ scaleY * (maxcpd.getHeight() + translateY)));
}
public double getRotation() { return rotation; }
public double getScaleX() { return scaleX; }
public double getScaleY() { return scaleY; }
public double getTranslateX() { return translateX; }
public double getTranslateY() { return translateY; }
public void setRotation(double rotation) { this.rotation = rotation; }
public void setScaleX(double scaleX) { this.scaleX = scaleX; }
public void setScaleY(double scaleY) { this.scaleY = scaleY; }
public void setTranslateX(double translateX) { this.translateX = translateX; }
public void setTranslateY(double translateY) { this.translateY = translateY; }
protected class TransformGlassPane extends JComponent {
private JRootPane rootPane;
public TransformGlassPane(JRootPane rootPane) {
this.rootPane = rootPane;
MouseInputDispatcher listener = new MouseInputDispatcher(
this, rootPane.getContentPane());
addMouseListener(listener);
addMouseMotionListener(listener);
setVisible(true);
}
@Override protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Container cp = rootPane.getContentPane();
Dimension maxSize = getMaximumSize(cp);
double w = maxSize.getWidth();
double h = maxSize.getHeight();
BufferedImage buffer = new BufferedImage(
(int) (w + translateX),
(int) (h + translateY),
BufferedImage.TYPE_INT_ARGB);
Graphics2D bg2 = buffer.createGraphics();
bg2.translate(
(w / 2.0 - cp.getWidth() / 2.0) + translateX,
(h / 2.0 - cp.getHeight() / 2.0) + translateY);
cp.paint(bg2);
bg2.dispose();
g2.setColor(cp.getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
g2.rotate(rotation,
(translateX + w / 2.0) * scaleX,
(translateY + h / 2.0) * scaleY);
g2.scale(scaleX, scaleY);
g2.drawImage(buffer, 0, 0, this);
}
}
protected class MouseInputDispatcher extends MouseInputAdapter {
private TransformGlassPane glassPane;
private Container contentPane;
private Component lastComponent;
public MouseInputDispatcher(TransformGlassPane glassPane, Container contentPane) {
this.glassPane = glassPane;
this.contentPane = contentPane;
}
protected void dispatch(MouseEvent e) {
Point glassPanePoint = revertPoint(e.getPoint());
Point containerPoint = SwingUtilities.convertPoint(
glassPane, glassPanePoint, contentPane);
Component component = SwingUtilities.getDeepestComponentAt(
contentPane, containerPoint.x, containerPoint.y);
if (component == null)
component = lastComponent;
if (component != null) {
Point componentPoint = SwingUtilities.convertPoint(
glassPane, glassPanePoint, component);
component.dispatchEvent(new MouseEvent(component,
e.getID(),
e.getWhen(),
e.getModifiers(),
componentPoint.x,
componentPoint.y,
e.getClickCount(),
e.isPopupTrigger()));
}
lastComponent = component;
glassPane.repaint();
}
@Override public void mouseClicked(MouseEvent e) { dispatch(e); }
@Override public void mousePressed(MouseEvent e) { dispatch(e); }
@Override public void mouseReleased(MouseEvent e) { dispatch(e); }
@Override public void mouseEntered(MouseEvent e) { dispatch(e); }
@Override public void mouseExited(MouseEvent e) { dispatch(e); }
@Override public void mouseDragged(MouseEvent e) { dispatch(e); }
@Override public void mouseMoved(MouseEvent e) { dispatch(e); }
}
protected class TransformRootPaneLayout extends RootLayout {
@Override public void layoutContainer(Container parent) {
Rectangle b = parent.getBounds();
Insets i = getInsets();
int contentY = 0;
int w = b.width - i.right - i.left;
int h = b.height - i.top - i.bottom;
if (layeredPane != null)
layeredPane.setBounds(i.left, i.top, w, h);
if (glassPane != null)
glassPane.setBounds(i.left, i.top, w, h);
if (menuBar != null && menuBar.isVisible()) {
Dimension mbd = menuBar.getPreferredSize();
menuBar.setBounds(0, 0, w, mbd.height);
contentY += mbd.height;
}
if (contentPane != null) {
Dimension cpd = contentPane.getPreferredSize();
contentPane.setBounds(0, contentY,
(int) cpd.getWidth(), (int) cpd.getHeight());
}
}
}
private static void createAndShowGUI() {
JFrame f = new JFrame() {
@Override protected JRootPane createRootPane() {
final TransformRootPane rp = new TransformRootPane();
new Timer(5, new ActionListener() {
final int ROTATIONS = 5;
final double RADIANS_360 = Math.toRadians(360);
double speed = 20.0;
double scale = 0.0;
int rotationsCount = 0;
public void actionPerformed(ActionEvent e) {
if (rotationsCount <= ROTATIONS) {
rp.setRotation(rp.getRotation() + Math.toRadians(speed));
rp.setScaleX(scale);
rp.setScaleY(scale);
scale += 0.0095;
if (rp.getRotation() / RADIANS_360 >= rotationsCount) {
rotationsCount++;
speed --;
}
} else {
rp.setRotation(0.0);
}
repaint();
}
}).start();
return rp;
}
};
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setBackground(Color.DARK_GRAY);
JPanel p = new JPanel(new BorderLayout());
p.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
p.setBackground(Color.LIGHT_GRAY);
p.add(new JLabel("<html>Notice<p /><hr /><p /><p /></html>"), BorderLayout.NORTH);
p.add(new JLabel("<html>Let's see your damned<p />"
+ "Qt Widgets do this!<p /><hr /><p /><p /></html>"), BorderLayout.CENTER);
p.add(new JButton("OK"), BorderLayout.SOUTH);
f.add(p);
f.pack();
f.setLocation(400, 400);
f.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
// no-op
}
createAndShowGUI();
}
});
}
}