Swing: resizing a JFrame like Frames in Linux e.g

前端 未结 3 1430
慢半拍i
慢半拍i 2020-12-03 19:01

I would like to know if theres a possibility to implement the resizing of a JFrame in that manner, that it\'s been resized like for example the standart windows in linux. To

相关标签:
3条回答
  • 2020-12-03 19:27

    only the future size if the window will be previewed, while the original content is not resized. As soon as the user releases the mouse, the Frame resizes to that size

    very complicated idea, but

    • add ComponentListener to the JFrame

    • override componentResized(ComponentEvent e)

    • add there Swing Timer with short delay (400-600) with output to the Swing Action

    • if resize continue, then call Timer#restart()

    EDIT

    use this code for testing

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.util.Vector;
    
    public class ComponentEventDemo extends JPanel
            implements ComponentListener, HierarchyListener,
            ItemListener {
    
        private JFrame frame;
        private static final long serialVersionUID = 1L;
        private JTextArea display;
        private JLabel label;
        private JComboBox comboBox;
        private JComboBox comboBox1;
        private String newline = "\n";
        private Vector<String> listSomeString = new Vector<String>();
        private Vector<String> listSomeAnotherString = new Vector<String>();
    
        public ComponentEventDemo() {
            listSomeString.add("-");
            listSomeString.add("Snowboarding");
            listSomeString.add("Rowing");
            listSomeString.add("Knitting");
            listSomeString.add("Speed reading");
            listSomeString.add("Pool");
            listSomeString.add("None of the above");
    //
            listSomeAnotherString.add("-");
            listSomeAnotherString.add("XxxZxx Snowboarding");
            listSomeAnotherString.add("AaaBbb Rowing");
            listSomeAnotherString.add("CccDdd Knitting");
            listSomeAnotherString.add("Eee Fff Speed reading");
            listSomeAnotherString.add("Eee Fff Pool");
            listSomeAnotherString.add("Eee Fff None of the above");
            comboBox = new JComboBox(listSomeString);
            comboBox1 = new JComboBox(listSomeAnotherString);
            display = new JTextArea();
            display.setEditable(false);
            JScrollPane scrollPane = new JScrollPane(display);
            scrollPane.setPreferredSize(new Dimension(350, 200));
    
            label = new JLabel("This is a label", JLabel.CENTER);
            label.addComponentListener(this);
    
            JCheckBox checkbox = new JCheckBox("Label visible", true);
            checkbox.addItemListener(this);
            checkbox.addComponentListener(this);
    
            JPanel panel = new JPanel(new GridLayout(1, 2));
            panel.add(label);
            panel.add(checkbox);
            panel.addComponentListener(this);
            frame = new JFrame("ComponentEventDemo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(scrollPane, BorderLayout.CENTER);
            frame.add(panel, BorderLayout.PAGE_END);
            frame.pack();
            frame.setVisible(true);
        }
    
        public void itemStateChanged(ItemEvent e) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                label.setVisible(true);
                label.revalidate();
                label.repaint();
            } else {
                label.setVisible(false);
            }
        }
    
        protected void displayMessage(String message) {
            //If the text area is not yet realized, and
            //we tell it to draw text, it could cause
            //a text/AWT tree deadlock. Our solution is
            //to ensure that the text area is realized
            //before attempting to draw text.
            // if (display.isShowing()) {
            display.append(message + newline);
            display.setCaretPosition(display.getDocument().getLength());
            //}
        }
    
        public void componentHidden(ComponentEvent e) {
            displayMessage(e.getComponent().getClass().getName() + " --- Hidden");
        }
    
        public void componentMoved(ComponentEvent e) {
            displayMessage(e.getComponent().getClass().getName() + " --- Moved");
        }
    
        public void componentResized(ComponentEvent e) {
            displayMessage(e.getComponent().getClass().getName() + " --- Resized ");
        }
    
        public void componentShown(ComponentEvent e) {
            displayMessage(e.getComponent().getClass().getName() + " --- Shown");
    
        }
    
        public static void main(String[] args) {
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
    
                public void run() {
                    ComponentEventDemo componentEventDemo = new ComponentEventDemo();
                }
            });
        }
    
        public void hierarchyChanged(HierarchyEvent e) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }
    
    0 讨论(0)
  • 2020-12-03 19:35

    A simple trick to mimic such behavior is to make the frame non resizable and dedicate some part of the frame to be the resize handles, and then add mouse listeners and resize it yourself:

        public static class GroundFrame extends JFrame {
            private boolean doResize = false;
    
            public GroundFrame() throws HeadlessException {
                setResizable(false);
    
                getContentPane().addMouseListener(new MouseAdapter() {
                    @Override
                    public void mousePressed(MouseEvent e) {
                        Point point = e.getPoint();
                        if (point.x >= getWidth() - 50) {
                            doResize = true;
                        }
                    }
    
                    @Override
                    public void mouseDragged(MouseEvent e) {
                    }
    
                    @Override
                    public void mouseReleased(MouseEvent e) {
                        if (doResize) {
                            setSize(e.getX(), getHeight());
                            doResize = false;
                        }
                    }
                });
            }
        }
    

    you can even make the jframe undecorated and perform all operations like resizing, moving, closing etc. yourself.

    but again, this behavior is controlled by the window manager, or compositing manager (you can tweak compiz to do such thing for you, for example). I think live-resizing was one of the key advertised features of NeXT, a major step forward at that time :)

    Also, another trick I tried is based on that java 7 reports resizing events as they happen, not on mouse release, so one can save window size after first resize, and then restore it, until resize is finished. Doesn't work very smoothly, though:

        public static class GroundFrame extends JFrame {
            private Timer timer;
            private Dimension oldSize;
    
            public GroundFrame() throws HeadlessException {
                timer = new Timer(500, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        oldSize = null;
                        invalidate();
                    }
                });
                timer.setRepeats(false);
    
                addComponentListener(new ComponentAdapter() {
                    public void componentResized(ComponentEvent e) {
                        if (oldSize == null) {
                            oldSize = getSize();
                            timer.start();
                        } else {
                            setSize(oldSize);
                            timer.restart();
                        }
                    }
                });
            }
        }
    
    0 讨论(0)
  • 2020-12-03 19:37

    +1 to mKorbel and Denis Tulskiy's answers.

    I did a sort of abstract solution which might be of help. It supports resizing (increasing and decreasing height and width) of JFrame from all four sides of the JFrame (NORTH, EAST, SOUTH and WEST) it also can be re-sized by width and height simultaneously when mouse is moved to one of the for corners.

    Basically what I did was:

    • Add MouseMotionListener and MouseListener to JFrame
    • Override mouseDragged(..), mouseMoved(..), mousePressed(..) and mouseReleased(..) of Listeners.
    • set JFrame to be non resizable.
    • In mouseMoved(..) listen for when mouse is 10px or less from bottom or right side. of JFrame, it then sets the appropriate direction of resize (height or width), changes mouse Cursor (Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) for far right/width resizing, Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) for bottom/hieght resizing, Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR) for top of frame height resizing or Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR) for left side width resizing) accordingly and call canResize(true).
    • In mouseDragged(..) update the width or height for new size as its dragged in direction
    • In mouseReleased(..) set the JFrame to the new size.
    • In mousePressed(..) we check for user pressed co-ordinates (this allows us to see if frame size is decreasing/increasing).

    Check out this example I made:

    import java.awt.Cursor;
    import java.awt.Dimension;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class JFrameSizeAfterDrag extends JFrame {
    
        //direction holds the position of drag
        private int w = 0, h = 0, direction, startX = 0, startY = 0;
    
        public JFrameSizeAfterDrag() {
            setResizable(false);
            setDefaultCloseOperation(EXIT_ON_CLOSE);
    
            addMouseListener(new MouseAdapter() {
                //so we can see if from where the user clikced is he increasing or decraesing size
                @Override
                public void mousePressed(MouseEvent me) {
                    super.mouseClicked(me);
                    startX = me.getX();
                    startY = me.getY();
                    System.out.println("Clicked: " + startX + "," + startY);
                }
    
                //when the mouse is relaeased set size
                @Override
                public void mouseReleased(MouseEvent me) {
                    super.mouseReleased(me);
                    System.out.println("Mouse released");
                    if (direction == 1 || direction == 2 || direction == 5 || direction == 6) {
                        setSize(w, h);
                    } else {//this should move x and y by as much as the mouse moved then use setBounds(x,y,w,h);
                        setBounds(getX() - (startX - me.getX()), getY() - (startY - me.getY()), w, h);
                    }
                    validate();
                }
            });
    
            addMouseMotionListener(new MouseAdapter() {
                private boolean canResize;
    
                //while dragging check direction of drag
                @Override
                public void mouseDragged(MouseEvent me) {
                    super.mouseDragged(me);
                    System.out.println("Dragging:" + me.getX() + "," + me.getY());
                    if (canResize && direction == 1) {//frame height  change
                        if (startY > me.getY()) {//decrease in height
                            h -= 4;
                        } else {//increase in height
                            h += 4;
                        }
                    } else if (canResize && direction == 2) {//frame width  change
                        if (startX > me.getX()) {//decrease in width
                            w -= 4;
                        } else {//increase in width
                            w += 4;
                        }
                    } else if (canResize && direction == 3) {//frame height  change
                        if (startX > me.getX()) {//decrease in width
                            w += 4;
                        } else {//increase in width
                            w -= 4;
                        }
                    } else if (canResize && direction == 4) {//frame width  change
                        if (startY > me.getY()) {//decrease in height
                            h += 4;
                        } else {//increase in height
                            h -= 4;
                        }
                    } else if (canResize && direction == 5) {//frame width and height  change bottom right
                        if (startY > me.getY() && startX > me.getX()) {//increase in height and width
                            h -= 4;
                            w -= 4;
                        } else {//decrease in height and with
                            h += 4;
                            w += 4;
                        }
                    } /* Windows dont usually support reszing from top but if you want :) uncomment code in mouseMoved(..) also
                     else if (canResize && direction == 6) {//frame width and height  change top left
                     if (startY > me.getY() && startX > me.getX()) {//decrease in height and with
                     h += 4;
                     w += 4;
                     } else {//increase in height and width
                     h -= 4;
                     w -= 4;
                     }
                     } else if (canResize && direction == 8) {//frame width and height  change top right
                     if (startY > me.getY() && startX > me.getX()) {//increase in height and width
                     h -= 4;
                     w -= 4;
                     } else {//decrease in height and with
                     h += 4;
                     w += 4;
                     }
                     }
                     */ else if (canResize && direction == 7) {//frame width and height  change bottom left
                        if (startY > me.getY() && startX > me.getX()) {//increase in height and width
                            h -= 4;
                            w -= 4;
                        } else {//decrease in height and with
                            h += 4;
                            w += 4;
                        }
                    }
                }
    
                @Override
                public void mouseMoved(MouseEvent me) {
                    super.mouseMoved(me);
                    if (me.getY() >= getHeight() - 10 && me.getX() >= getWidth() - 10) {//close to bottom and right side of frame show south east cursor and allow height witdh simaltneous increase/decrease
                        //System.out.println("resize allowed..");
                        canResize = true;
                        setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
                        direction = 5;
                    } /*Windows dont usually support reszing from top but if you want :) uncomment code in mouseDragged(..) too
                     else if (me.getY() <= 28 && me.getX() <= 28) {//close to top side and left side of frame show north west cursor and only allow increase/decrease in width and height simultaneosly
                     //System.out.println("resize allowed..");
                     canResize = true;
                     setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
                     direction = 6;
                     }  else if (me.getY() <= 28 && me.getX() >= getWidth() - 10) {//close to top and right side of frame show north east cursor and only allow increase/decrease in width and height simultaneosly
                     //System.out.println("resize allowed..");
                     canResize = true;
                     setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
                     direction = 8;
                     } 
                     */ else if (me.getY() >= getHeight() - 10 && me.getX() <= 10) {//close to bottom side and left side of frame show north west cursor and only allow increase/decrease in width and height simultaneosly
                        //System.out.println("resize allowed..");
                        canResize = true;
                        setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
                        direction = 7;
                    } else if (me.getY() >= getHeight() - 10) {//close to bottom of frame show south resize cursor and only allow increase height
                        //System.out.println("resize allowed");
                        canResize = true;
                        setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
                        direction = 1;
                    } else if (me.getX() >= getWidth() - 10) {//close to right side of frame show east cursor and only allow increase width
                        //System.out.println("resize allowed");
                        canResize = true;
                        setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
                        direction = 2;
                    } else if (me.getX() <= 10) {//close to left side of frame show east cursor and only allow increase width
                        //System.out.println("resize allowed");
                        canResize = true;
                        setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
                        direction = 3;
                    } else if (me.getY() <= 28) {//close to top side of frame show east cursor and only allow increase height
                        // System.out.println("resize allowed..");
                        canResize = true;
                        setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
                        direction = 4;
                    } else {
                        canResize = false;
                        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                        // System.out.println("resize not allowed");
                    }
                }
            });
    
            //just so GUI is visible and not small
            add(new JPanel() {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(200, 200);
                }
            });
    
            pack();
            setVisible(true);
        }
    
        @Override
        public void setVisible(boolean bln) {
            super.setVisible(bln);
            w = getWidth();
            h = getHeight();
        }
    
        public static void main(String[] args) {
    
            /**
             * Create GUI and components on Event-Dispatch-Thread
             */
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new JFrameSizeAfterDrag();
                }
            });
        }
    }
    

    UPDATE:

    Great example you made I fixed the code by adding MouseAdapter which overrides mouseReleased(..) which calls resizePanel(...) when mouseReleased(..)

    see here for the fixed code (also fixed a few minor things like added ComponentAdapter instead of ComponentListener and AbstractAction instead of Action):

    import java.awt.*;
    import static java.awt.GraphicsDevice.WindowTranslucency.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ComponentAdapter;
    import java.awt.event.ComponentEvent;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.*;
    
    public class JFrameSizeAfterDrag2 extends JFrame {
    
        private Timer timer;
        private JPanel panel2;
        boolean canResize = true,firstTime = true;
    
    
        public JFrameSizeAfterDrag2() {
            super("GradientTranslucentWindow");
    
            setBackground(new Color(0, 0, 0, 0));
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            setContentPane(new JPanel(null) {//contentpane layout is null only
                @Override
                protected void paintComponent(Graphics g) {
                    Paint p = new GradientPaint(0.0f, 0.0f, new Color(0, 0, 0, 0), 0.0f, getHeight(), new Color(0, 0, 0, 0), true);
                    Graphics2D g2d = (Graphics2D) g;
                    g2d.setPaint(p);
                    g2d.fillRect(0, 0, getWidth(), getHeight());
                }
    
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(300, 300);
                }
            });
    
            panel2 = new JPanel();
            panel2.setBackground(Color.black);
            getContentPane().add(panel2);
    
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseReleased(MouseEvent me) {
                    super.mouseReleased(me);
                    if (canResize) {
                        resizePanel(getContentPane().getSize());
                    }
                }
            });
    
            addComponentListener(new ComponentAdapter() {
    
                @Override
                public void componentResized(ComponentEvent e) {
                    timer = new Timer(50, new AbstractAction() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            if (timer.isRunning()) {
                                canResize = false;
                            } else {
                                canResize = true;
                                if (firstTime == true) {
                                    firstTime = false;
                                    resizePanel(getContentPane().getSize());
                                }
                            }
                        }
                    });
                    timer.setRepeats(false);
                    timer.start();
    
                }
            });
            pack();
        }
    
        public void resizePanel(Dimension dim) {
            panel2.setBounds(0, 0, dim.width, dim.height);
            revalidate();
        }
    
        public static void main(String[] args) {
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            GraphicsDevice gd = ge.getDefaultScreenDevice();
            boolean isPerPixelTranslucencySupported = gd.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);
    
            if (!isPerPixelTranslucencySupported) {
                System.out.println("Per-pixel translucency is not supported");
                System.exit(0);
            }
    
            JFrame.setDefaultLookAndFeelDecorated(true);
    
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrameSizeAfterDrag2 gtw = new JFrameSizeAfterDrag2();
                    gtw.setVisible(true);
                }
            });
        }
    }
    
    0 讨论(0)
提交回复
热议问题