Currently, I am using the following code to drag and move my undecordated JFrames.

private void initialiseGUI(Component component){
    //<editor-fold defaultstate="collapsed" desc="code">
    component.addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
            posX = e.getX();
            posY = e.getY();
        }
    });

    component.addMouseMotionListener(new MouseAdapter() {
        public void mouseDragged(MouseEvent evt) {
            //sets frame position when mouse dragged            
            Rectangle rectangle = getBounds();
            getGUI().setBounds(evt.getXOnScreen() - posX, evt.getYOnScreen() - posY, rectangle.width, rectangle.height);
        }
    });
    //</editor-fold>
}

What must I write so that the user can resize it like a decorated window, by dragging the side?


Solution 1:

You can check out mr Rob Camick's ComponentResizer class. Pretty simple and straight forward to use.

Just instantiate the ComponentResizer and register the frame with something like:

JFrame frame = new JFrame();
ComponentResizer cr = new ComponentResizer();
cr.registerComponent(frame);
cr.setSnapSize(new Dimension(10, 10));
cr.setMaximumSize(new Dimension(...));
cr.setMinimumSize(new Dimension(...));

Here's a complete example of using the class

enter image description here

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

public class UndecoratedExample {

    private JFrame frame = new JFrame();

    class MainPanel extends JPanel {

        public MainPanel() {
            setBackground(Color.gray);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }
    }

    class BorderPanel extends JPanel {

        private JLabel label;
        int pX, pY;

        public BorderPanel() {
            label = new JLabel(" X ");
            label.setOpaque(true);
            label.setBackground(Color.RED);
            label.setForeground(Color.WHITE);

            setBackground(Color.black);
            setLayout(new FlowLayout(FlowLayout.RIGHT));

            add(label);

            label.addMouseListener(new MouseAdapter() {
                public void mouseReleased(MouseEvent e) {
                    System.exit(0);
                }
            });
            addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent me) {
                    // Get x,y and store them
                    pX = me.getX();
                    pY = me.getY();

                }

                 public void mouseDragged(MouseEvent me) {

                    frame.setLocation(frame.getLocation().x + me.getX() - pX,
                            frame.getLocation().y + me.getY() - pY);
                }
            });

            addMouseMotionListener(new MouseMotionAdapter() {
                public void mouseDragged(MouseEvent me) {

                    frame.setLocation(frame.getLocation().x + me.getX() - pX,
                            frame.getLocation().y + me.getY() - pY);
                }
            });
        }
    }

    class OutsidePanel extends JPanel {

        public OutsidePanel() {
            setLayout(new BorderLayout());
            add(new MainPanel(), BorderLayout.CENTER);
            add(new BorderPanel(), BorderLayout.PAGE_START);
            setBorder(new LineBorder(Color.BLACK, 5));
        }
    }

    private void createAnsShowGui() {
        ComponentResizer cr = new ComponentResizer();
        cr.setMinimumSize(new Dimension(300, 300));
        cr.setMaximumSize(new Dimension(800, 600));
        cr.registerComponent(frame);
        cr.setSnapSize(new Dimension(10, 10));
        frame.setUndecorated(true);
        frame.add(new OutsidePanel());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new UndecoratedExample().createAnsShowGui();
            }
        });
    }
}

Solution 2:

I have recently built my own prototype for this. Maybe you will find this useful.

It uses 2 different components one on top of the other. Unlike Rob Camick's ComponentResizer on which this is inspired, the mouse listeners set to the components in the JFrame will be functional. You will not get the JFrame to capture all the mouse events making it useless to attach listeners to the components in the JFrame. It captures mouse events only when and where a double headed arrow must be displayed.

The key is this method in the top component:

@Override
public boolean contains(int x, int y) {
    return x < insets.left || y < insets.top
            || getHeight() - y < insets.bottom
            || getWidth() - x < insets.right;
}

Here is the code:

import java.awt.Component;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

public class BackgroundComponentDragger implements MouseMotionListener {

    private Component controlledComponent;

    /*
     * Point where cursor was last clicked.
     */
    private Point originPoint;

    public BackgroundComponentDragger(Component component) {
        this.controlledComponent = component;
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        Point currentFramePosition = controlledComponent.getLocation();
        Point newFramePosition = new Point(currentFramePosition.x + e.getX()
                - originPoint.x, currentFramePosition.y + e.getY() - originPoint.y);
        controlledComponent.setLocation(newFramePosition);
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        originPoint = e.getPoint();
    }
}



import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.HashMap;
import java.util.Map;

public class ComponentBorderDragger implements MouseMotionListener {

    private Component controlledComponent;

    private byte direction;
    protected static final byte NORTH = 1;
    protected static final byte WEST = 2;
    protected static final byte SOUTH = 4;
    protected static final byte EAST = 8;

    private Cursor sourceCursor;

    private static Map<Byte, Integer> cursors = new HashMap<Byte, Integer>();
    {
        cursors.put((byte) 1, Cursor.N_RESIZE_CURSOR);
        cursors.put((byte) 2, Cursor.W_RESIZE_CURSOR);
        cursors.put((byte) 4, Cursor.S_RESIZE_CURSOR);
        cursors.put((byte) 8, Cursor.E_RESIZE_CURSOR);
        cursors.put((byte) 3, Cursor.NW_RESIZE_CURSOR);
        cursors.put((byte) 9, Cursor.NE_RESIZE_CURSOR);
        cursors.put((byte) 6, Cursor.SW_RESIZE_CURSOR);
        cursors.put((byte) 12, Cursor.SE_RESIZE_CURSOR);
    }

    private Insets dragInsets;
    private Dimension minSize;

    private Point basePoint;

    public ComponentBorderDragger(Component controlledComponent, Insets dragInsets,
            Dimension minSize) {
        super();
        this.controlledComponent = controlledComponent;
        this.dragInsets = dragInsets;
        this.minSize = minSize;
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        if (direction == 0) {
            return;
        }

        Point newPoint = e.getPoint();
        int x, y, width, height, newBasePointX, newBasePointY;
        x = controlledComponent.getX();
        y = controlledComponent.getY();
        width = controlledComponent.getWidth();
        height = controlledComponent.getHeight();
        newBasePointX = newPoint.x;
        newBasePointY = newPoint.y;

        if ((direction & EAST) == EAST) {
            int newWidth;
            newWidth = Math.max(minSize.width, width + newPoint.x
                    - basePoint.x);
            width = newWidth;
        }
        if ((direction & SOUTH) == SOUTH) {
            int novoAlto;
            novoAlto = Math.max(minSize.height, height + newPoint.y
                    - basePoint.y);
            height = novoAlto;
        }
        if ((direction & WEST) == WEST) {
            int newWidth, newX;
            newWidth = Math.max(minSize.width, width - newPoint.x
                    + basePoint.x);
            newX = Math.min(x + width - minSize.width, x + newPoint.x
                    - basePoint.x);

            // Changing coordenates of new base point to refer to the new component position
            newBasePointX -= newX - x;
            x = newX;
            width = newWidth;
        }
        if ((direction & NORTH) == NORTH) {
            int newHeigth, newY;
            newHeigth = Math.max(minSize.height, height - newPoint.y
                    + basePoint.y);
            newY = Math.min(y + height - minSize.height, y + newPoint.y
                    - basePoint.y);
            // Changing coordenates of new base point to refer to the new component position
            newBasePointY -= newY - y;
            y = newY;
            height = newHeigth;
        }
        controlledComponent.setBounds(x, y, width, height);
        basePoint = new Point(newBasePointX, newBasePointY);
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        Component originator = e.getComponent();
        if (direction == 0) {
            sourceCursor = originator.getCursor();
        }
        calculateDirection(e.getPoint(), e.getComponent().getSize());
        setCursor(e.getComponent());
        basePoint = e.getPoint();
    }

    private void setCursor(Component component) {
        if (direction == 0) {
            component.setCursor(sourceCursor);
        } else {
            int cursorType = cursors.get(direction);
            Cursor cursor = Cursor.getPredefinedCursor(cursorType);
            component.setCursor(cursor);
        }
    }

    private void calculateDirection(Point point, Dimension componentSize) {
        direction = 0;
        if (point.x < dragInsets.left) {
            direction |= WEST;
        }
        if (point.y < dragInsets.top) {
            direction |= NORTH;
        }
        if (point.x > componentSize.width - dragInsets.right) {
            direction |= EAST;
        }
        if (point.y > componentSize.height - dragInsets.bottom) {
            direction |= SOUTH;
        }
    }
}


import java.awt.Insets;

import javax.swing.JComponent;

public class FrameComponent extends JComponent {

    private static final long serialVersionUID = 3383070502274306213L;

    private Insets insets;

    @Override
    public boolean contains(int x, int y) {
        return x < insets.left || y < insets.top || getHeight() - y < insets.bottom || getWidth() - x < insets.right;
    }

    public FrameComponent(Insets insets) {
        this.insets = insets;
    }
}


import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class GUI {

    private JFrame compoundFrame;
    private JPanel backgroundPanel;

    Dimension gUISize = new Dimension(400, 400);

    public GUI() {
        buildResizeableFrame();
    }

    public void activate() {
        compoundFrame.setVisible(true);
    }

    private void buildResizeableFrame() {
        compoundFrame = new JFrame();
        FrameComponent frame = new FrameComponent(new Insets(5, 5, 5, 5));
        backgroundPanel = new JPanel();
        compoundFrame.setLayout(null);
        compoundFrame.add(frame);
        compoundFrame.add(backgroundPanel);
        setFrameSizeController(frame, backgroundPanel);
        setFrameController(frame);
        setBackgroundPanelController(backgroundPanel);
        Dimension dimPant = Toolkit.getDefaultToolkit().getScreenSize();
        compoundFrame.setBounds(dimPant.width / 4, dimPant.height / 4, dimPant.width / 2, dimPant.height / 2);
        compoundFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        compoundFrame.setUndecorated(true);
    }

    private void setFrameSizeController(FrameComponent frame, JPanel panel) {
        compoundFrame.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                Dimension sizeIn = ((JFrame) e.getComponent()).getContentPane().getSize();
                frame.setSize(sizeIn);
                panel.setSize(sizeIn);
            }
        });
    }

    private void setFrameController(FrameComponent frame) {
        ComponentBorderDragger controller = new ComponentBorderDragger(compoundFrame,
                new Insets(5, 5, 5, 5), new Dimension(10, 10));
        frame.addMouseMotionListener(controller);
    }

    private void setBackgroundPanelController(JPanel panel) {
        panel.addMouseMotionListener(new BackgroundComponentDragger(compoundFrame));
    }

    public static void main(String[] args) {
        new GUI().activate();
    }
}

Note: This code sets a null LayoutManager and a listener to the container to resize the inner component when needed. This practice is discouraged. This logic should be moved to a custom layout manager.