Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to flip a JFrame and its children upside down?

This may seem silly (and it probably is) but how can I flip all the components in a JFrame upside down? Everything in the JFrame must be flipped vertically around an axis halfway down the JFrame including text on the controls. Preferably with JTextFields, JButtons etc. working as expected even though flipped.

I've done some searching but have not found anything helpful on the subject.

Is there an easier way than manually changing the layout and then extending and overriding the paint methods of each of the controls used?

EDIT: I managed to get it working. You can see my answer below.

like image 763
ughzan Avatar asked Feb 22 '12 09:02

ughzan


2 Answers

You can easily flip the GUI without having to modify all components, simply modify the paint method of your top-most container:

class ReversedPanel extends Component {
    @Override
    public void paint(Graphics g) {
        BufferedImage im = new BufferedImage(this.getWidth(), this.getHeight(),
                BufferedImage.TYPE_3BYTE_BGR);
        // Paint normally but on the image
        super.paint(im.getGraphics());

        // Reverse the image
        AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
        tx.translate(0, -im.getHeight());
        AffineTransformOp op = new AffineTransformOp(tx,
                AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
        im = op.filter(im, null);

        // Draw the reversed image on the screen
        g.drawImage(im, 0, 0, null);
    }
}

The illusion is not perfect though: when the user hovers over the original position of a button, the button will be displayed correctly.

And obviously this doesn't take care of reversing events, which is considerably more complex.

like image 136
ARRG Avatar answered Nov 08 '22 02:11

ARRG


I managed to create a small working flipped application. So far all the child controls used (JTextArea, JLabel, JButton) work as expected, events and all.

Here is a screenshot...

It's flipped!

And the code...

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTextArea;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;

public class FlipUpsideDown {

    public static void main(String[] args) {
        JTextArea textArea = new JTextArea("This is a working text area\n\nI LOVE SWING", 4, 0);
        // The cursor still use the wrong mouse position so...
        textArea.setCursor(Cursor.getDefaultCursor());

        final JPanel mainPanel = new JPanel(new BorderLayout(5, 5));

        mainPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
        mainPanel.add(new JLabel("A Normal Label"), BorderLayout.NORTH);
        mainPanel.add(textArea, BorderLayout.CENTER);
        mainPanel.add(new JButton("Hello World!"), BorderLayout.SOUTH);

        // The root pane is responsible for drawing all the children of the 
        // frame. All the paint calls go through the root pane since dirty
        // painting of individual controls are blocked (see below). So we can 
        // use the paint method of the root pane to flip the painted controls.
        final JFrame f = new JFrame("FlipUpsideDown") {

            protected JRootPane createRootPane() {
                JRootPane rp = new JRootPane() {

                    public void paint(Graphics g) {
                        BufferedImage im = new BufferedImage(this.getWidth(), this.getHeight(),
                                BufferedImage.TYPE_3BYTE_BGR);
                        // Paint normally but on the image
                        super.paint(im.getGraphics());

                        // Reverse the image
                        AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
                        tx.translate(0, -im.getHeight());
                        AffineTransformOp op = new AffineTransformOp(tx,
                                AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
                        im = op.filter(im, null);

                        // Draw the reversed image on the screen
                        g.drawImage(im, 0, 0, null);
                    }
                };
                rp.setOpaque(true);
                return rp;
            }
        };

        // Override the RepaintManager so that we always repaint the entire 
        // frame when a region is set to dirty.
        RepaintManager repaintManager = new RepaintManager() {

            public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
                schedulePaint();
            }

            public void addDirtyRegion(Window window, int x, int y, int w, int h) {
                schedulePaint();
            }

            public void paintDirtyRegions() {
                schedulePaint();
            }

            private void schedulePaint() {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        f.paint(f.getGraphics());
                    }
                });
            }
        };
        RepaintManager.setCurrentManager(repaintManager);

        // Intercept mouse events and flip their positions around in the JFrame
        EventQueue queue = new EventQueue() {

            protected void dispatchEvent(AWTEvent event) {
                if (event instanceof MouseEvent) {
                    MouseEvent me = (MouseEvent) event;
                    MouseEvent evt = new MouseEvent(
                            me.getComponent(),
                            me.getID(),
                            me.getWhen(),
                            me.getModifiers(),
                            f.getWidth() - me.getX() + f.getInsets().right - f.getInsets().left,
                            f.getHeight() - me.getY() + f.getInsets().top - f.getInsets().bottom,
                            me.getClickCount(),
                            false,
                            me.getButton());
                    event = evt;
                }
                super.dispatchEvent(event);
            }
        };
        Toolkit.getDefaultToolkit().getSystemEventQueue().push(queue);

        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationByPlatform(true);
        f.add(mainPanel);
        f.pack();
        f.setVisible(true);
    }
}
like image 23
ughzan Avatar answered Nov 08 '22 01:11

ughzan