Making a JPanel manually resizable
Asked Answered
V

5

15

I have a JFrame with BorderLayout as the layout manager.

In the south border, I have a JPanel, I want this JPanel's size to be adjustable by the user, i.e. the user can click on the edge of the border and drag it up to make it larger.

Is there any way you know that I can do this?

Vertumnus answered 13/7, 2009 at 15:4 Comment(0)
I
25

In order to make panels in a frame individually resizable you need to add them onto a JSplitPane.

Instead of putting it in the South portion of the Frame, put the JSplitPane in the Center. The split pane will make the bottom panel in the split seem like it is in the South, and the top panel in the split will be in the Center of the frame.

Make sure you set the orientation of the two panels with setOrientation(JSplitPane.VERTICAL_SPLIT ).

Then, you can resize the panels that are in the pane.

Izzy answered 13/7, 2009 at 15:15 Comment(0)
M
14

I think you meant to say JPanel. You can add a custom mouseListener and handle mouse clicks, drags and mouse releases and then resize the panel programmaticaly.

This will demonstrate this. Note that the jframe does NOT resize automatically with the JPanel. To make the effect more visible i painted the panel red and added a beveled border :

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;

@SuppressWarnings("serial")
public class ResizablePanel extends JPanel {

    private boolean drag = false;
    private Point dragLocation  = new Point();

    public  ResizablePanel() {
        setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
        setPreferredSize(new Dimension(500, 500));
        final JFrame f = new JFrame("Test");
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                drag = true;
                dragLocation = e.getPoint();
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                drag = false;
            }
        });
        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (drag) {
                    if (dragLocation.getX()> getWidth()-10 && dragLocation.getY()>getHeight()-10) {
                        System.err.println("in");
                        setSize((int)(getWidth()+(e.getPoint().getX()-dragLocation.getX())),
                                (int)(getHeight()+(e.getPoint().getY()-dragLocation.getY())));
                        dragLocation = e.getPoint();
                    }
                }
            }
        });
        f.getContentPane().setLayout(new BorderLayout());
        f.getContentPane().add(this,BorderLayout.CENTER);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }

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

    public void paintComponent(Graphics g) {
        g.setColor(Color.red);
        g.fillRect(0, 0, getWidth(), getHeight());
    }

}
Meganmeganthropus answered 13/7, 2009 at 15:7 Comment(5)
That is way over the top! A simple JSplitPane will get the job done.Izzy
i know. i just answered his question.Meganmeganthropus
It is an interesting solution though.Izzy
the problem is that the jframe does not automatically resize with the panel. i tried pack() in every call (expensive i know) but didn't work. Maybe a different layout manager will do the trick?Meganmeganthropus
It's a brilliant solution, great if you want to get rid of JSplitPane defaults (e.g. border size of the delimiter).Otes
D
0

I made a class for that if you want to take a look. It isn`t finished yet.

package projetoSplitPainel;

import java.awt.Component;
import java.util.ArrayList;

import javax.swing.JSplitPane;

/**
 * This Components is based on the JSplitPane. JSplitPane is used to divide two
 * (and only two) Components. This class intend to manipulate the JSplitPane in
 * a way that can be placed as many Component as wanted.
 * 
 * @author Bode
 *
 */
public class JSplitPaneMultiTabs extends JSplitPane {
    private ArrayList<JSplitPane> ecanpsulationList = new ArrayList<JSplitPane>();
    private int numberOfComponents = 1;
    private int sizeOfDivision = 6;

    /**
     * Builds the Pane
     */
    public JSplitPaneMultiTabs() {
        super();
        this.setLeftComponent(null);
        this.setBorder(null);
        ecanpsulationList.add(this);
        setAllBorders(sizeOfDivision);
    }

    /**
     * 
     * @param comp - adds a Component to the Pane
     */
    public void addComponent(Component comp) {
        JSplitPane capsule = new JSplitPane();

        capsule.setRightComponent(null);
        capsule.setLeftComponent(comp);
        capsule.setDividerSize(sizeOfDivision);
        capsule.setBorder(null);

        ecanpsulationList.get(numberOfComponents - 1).setRightComponent(capsule);
        ecanpsulationList.add(capsule);
        numberOfComponents++;
        this.fixWeights();
    }

    /**
     * 
     * @param orientation
     *            JSplitPane.HORIZONTAL_SPLIT - sets the orientation of the
     *            Components to horizontal alignment
     * @param orientation
     *            JSplitPane.VERTICAL_SPLIT - sets the orientation of the
     *            Components to vertical alignment
     */
    public void setAlignment(int orientation) {
        for (int i = 0; i < numberOfComponents; i++) {
            ecanpsulationList.get(i).setOrientation(orientation);

        }
    }

    /**
     * 
     * @param newSize - resizes the borders of the all the Components of the Screen
     */
    public void setAllBorders(int newSize) {
        this.setDividerSize(newSize);
        for (int i = 0; i < numberOfComponents; i++) {
            ecanpsulationList.get(i).setDividerSize(newSize);
        }

    }

    /**
     * each Component added needs to be readapteded to the screen
     */
    private void fixWeights() {
        ecanpsulationList.get(0).setResizeWeight(1.0);
        for (int i = 1; i < numberOfComponents; i++) {
            double resize = (double) 1 / (double) (i + 1);
            ecanpsulationList.get(numberOfComponents - i - 1).setResizeWeight(
                    resize);
        }
        ecanpsulationList.get(numberOfComponents - 1).setResizeWeight(0.0);
    }

}
Dualistic answered 18/4, 2015 at 19:44 Comment(0)
A
0

So i Made a Class which does mostly what the OP wanted. Basically it is a Pannel which can be resized when clicking at the border. It also (tries) to resize all the components contained inside it to fit the new size. It also tries to detect collision between other components in the parent frame to prevent overlapping as much as possible.

Anyway here you go:

import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JDesktopPane;


@SuppressWarnings("serial")
public class ResizablePanel extends JDesktopPane {

    private boolean drag = false;
    private boolean top =false;
    private boolean bottom =false;
    private boolean left=false;
    private boolean right =false;
    private Point dragLocation  = new Point();
    public  ResizablePanel() {
        setMinimumSize(new Dimension(200, 200));
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                evaluateMousePress(e.getPoint());
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                drag = false;
                setCursor(Cursor.getDefaultCursor());
            }
        });
        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                evaluateMouseDrag(e.getPoint());
            }
            @Override
            public void mouseMoved(MouseEvent e) {
                evaluateMouseHover(e.getPoint());
            }
        });
    }
    @Override
    public void setBounds(int x, int y, int width, int height) {
        Rectangle oldBounds=getBounds();
        Rectangle newBounds = new Rectangle(x, y, width, height);
        super.setBounds(x, y, width, height);
        resizeSingleComponent(this,oldBounds, newBounds);
    }
    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        Stroke stroke = g2.getStroke();
        g2.setStroke(new BasicStroke(5));
        g.drawRect(0, 0, getBounds().width, getBounds().height);
        g2.setStroke(stroke);
    }
    private void resizeSingleComponent(Component component , Rectangle oldBounds , Rectangle newBounds) {
        
        if(component instanceof Container) {
            if(!component.equals(this)) {
                Rectangle componentBounds = component.getBounds();
                double x = getNew(componentBounds.getX(), oldBounds.getWidth(), newBounds.getWidth());
                double y = getNew(componentBounds.getY(), oldBounds.getHeight(), newBounds.getHeight());
                double width = getNew(componentBounds.getWidth(), oldBounds.getWidth(), newBounds.getWidth());
                double height = getNew(componentBounds.getHeight(), oldBounds.getHeight(), newBounds.getHeight());
                componentBounds.width = (int) Math.round(width);
                componentBounds.height = (int) Math.round(height);
                componentBounds.x = (int) Math.round(x);
                componentBounds.y = (int) Math.round(y);
                component.setBounds(componentBounds);
            }
            for(Component child:((Container) component).getComponents())
                resizeSingleComponent(child, oldBounds, newBounds);
        }
        else {
            Rectangle componentBounds = component.getBounds();
            double x = getNew(componentBounds.getX(), oldBounds.getWidth(), newBounds.getWidth());
            double y = getNew(componentBounds.getY(), oldBounds.getHeight(), newBounds.getHeight());
            double width = getNew(componentBounds.getWidth(), oldBounds.getWidth(), newBounds.getWidth());
            double height = getNew(componentBounds.getHeight(), oldBounds.getHeight(), newBounds.getHeight());
            componentBounds.width = (int) Math.round(width);
            componentBounds.height = (int) Math.round(height);
            componentBounds.x = (int) Math.round(x);
            componentBounds.y = (int) Math.round(y);
            component.setBounds(componentBounds);
        }
    }
    
    
    private void evaluateMouseDrag(Point point) {
        if (drag) {
            if (top || left || right || bottom) {
                int heightIncrement=0;
                int widthIncrement=0;
                int posX = getBounds().x;
                int posY = getBounds().y;
                if(top || bottom) 
                    heightIncrement = (int) (point.getY()-dragLocation.getY());
                if(left || right)
                    widthIncrement = (int) (point.getX()-dragLocation.getX());
                if(top) {
                    posY = posY+heightIncrement;
                    heightIncrement=-heightIncrement;
                }
                if(left) {
                    posX=posX+widthIncrement;
                    widthIncrement=-widthIncrement;
                }
                if(right)
                    dragLocation.x=(int) point.getX();
                if(bottom)
                    dragLocation.y=(int) point.getY();
                    
                Rectangle bounds = new Rectangle(posX, posY, getWidth()+ widthIncrement,getHeight()+ heightIncrement);    
                justifyCollision(bounds,point);
            }
        }
    }
    private void evaluateMousePress(Point point) {
         drag = true;
         dragLocation = point;
         top=dragLocation.getY() <=5;
         left=dragLocation.getX() <=5;
         bottom = dragLocation.getY() >=getHeight()-5;
         right = dragLocation.getX() >=getWidth()-5;
         setResizeCursor(point);
    }
    private void evaluateMouseHover(Point point) {
        if(!drag) {
            top=point.getY() <=5;
            left=point.getX() <=5;
            bottom = point.getY() >=getHeight()-5;
            right = point.getX() >=getWidth()-5;
            setResizeCursor(point);
        }
   }
    
    private void justifyCollision(Rectangle bounds, Point point) {
        //justify undersizing
        if(bounds.width<getMinimumSize().width) {
            if(left)
                bounds.x= getBounds().x;
            bounds.width=getWidth();
        }
        if(bounds.height<getMinimumSize().height) {
            if(top)
                bounds.y=getBounds().y;
            bounds.height=getHeight();
        }
        Container parent = getParent();
        //justify parent container bounds
        if(bounds.x<0 ||bounds.width+bounds.x>parent.getWidth()) {
            bounds.width = getWidth();
            if(right &&!(bounds.width+bounds.x>parent.getWidth()))
                dragLocation.x=(int) point.getX();
            if(bounds.x<0)
                bounds.x=0;
        }
        if(bounds.y<0 ||bounds.height+bounds.y>parent.getHeight()) {
            bounds.height = getHeight();
            if(bottom &&!(bounds.height+bounds.y>parent.getHeight()))
                dragLocation.y=(int) point.getY();
            if(bounds.y<0)
                bounds.y=0;
        }
        //justify any other component in it's way
        for(Component c:parent.getComponents()) {
            if(!c.equals(this) &&c.getBounds().intersects(bounds)) {
                evaluateOverlaps(bounds, c,point);
            }
        }
        setBounds(bounds);
    }
    private Rectangle evaluateOverlaps(Rectangle bounds , Component component,Point point) {
        if(bounds.intersects(component.getBounds())) {
            if(component instanceof ResizablePanel) {
                ResizablePanel panel=(ResizablePanel) component;
                Rectangle panelBound=panel.getBounds();
                if(top || bottom) {
                    panelBound.height = panelBound.height - bounds.intersection(panelBound).height;
                    if(panelBound.height<panel.getMinimumSize().height) {
                        panelBound.height=panel.getMinimumSize().height;
                        bounds.height = getHeight();
                        if(top) {
                            bounds.y = component.getBounds().y+component.getHeight();
                        }
                    }
                    else if(bottom) {
                        panelBound.y = panelBound.y + bounds.intersection(panelBound).height;
                    }
                }
                else if(left || right) {
                    panelBound.width = panelBound.width - bounds.intersection(panelBound).width;
                    if(panelBound.width<panel.getMinimumSize().width) {
                        panelBound.width=panel.getMinimumSize().width;
                        bounds.width = getWidth();
                        if(left) {
                            bounds.x = component.getBounds().x+component.getWidth();
                        }
                    }
                    else if(right) {
                        panelBound.x = panelBound.x + bounds.intersection(panelBound).width;
                    }
                }
                panel.setBounds(panelBound);
                return bounds;
            }
            
            if(left || right) {
                bounds.width = getWidth();
                if(left) {
                    bounds.x = component.getBounds().x+component.getWidth();
                }
            }
            if(top || bottom) {
                bounds.height = getHeight();
                if(top) {
                    bounds.y = component.getBounds().y+component.getHeight();
                }
            }
        }
        return bounds;
    }
    private void setResizeCursor(Point point) {
        if(top) { 
            if(left) 
                setCursor(new Cursor(Cursor.NW_RESIZE_CURSOR));
            else if(right)  
                setCursor(new Cursor(Cursor.NE_RESIZE_CURSOR));
            else 
                setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
        }
        else if(bottom) { 
            if(left)  
                setCursor(new Cursor(Cursor.SW_RESIZE_CURSOR));
            else if(right) 
                setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
            else 
                setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));
        }
        else if (left) 
            setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
        else if (right)
            setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
        else
            setCursor(Cursor.getDefaultCursor());
    }
    
    private long getNew(double size,double oldMax,double newMax) {
        double value = ((size/oldMax)*newMax);
        return Math.round(value);
    }
}
Auspex answered 3/9, 2021 at 13:28 Comment(0)
D
-4

You might have to specify JFrame.setResizeable = true; on both the Parent JFrame(the one with the border layout) and the child JFrame.

You also might want to use a JPanel in the south border.

Dichotomize answered 13/7, 2009 at 15:8 Comment(1)
He needs to resize the panel, not the frameIzzy

© 2022 - 2024 — McMap. All rights reserved.