Swing: изменение размера JFrame как фреймов в Linux e.g

Я хотел бы знать, есть ли возможность реализовать изменение размера JFrame таким образом, что он был изменен, как, например, стандартные окна в linux. Точнее: если пользователь начнет перетаскивать, только будущий размер, если окно будет предварительно просмотрено, а исходное содержимое не будет изменено. Как только пользователь отпускает мышь, кадр изменяется до этого размера. В изображениях:

(1) состояние до изменение размера

enter image description here

(2) пользователь начинает перетаскивать (на красный круг)

enter image description here

(3) пользователь отпускает мышь, кадр получает изменение размера

enter image description here

можно ли понять, что в Java Swing?

EDIT:

поскольку эта программа Однажды должна работать также в нижней Java RE Как 7, я попытался объединить предложения mKorbel С и предложение в комментарии с фреймом translucend. Результат близок к цели, за исключением того, что

  • содержимое contentPane изменяется после того, как я перестаю перемещать мышь, а не когда мышь освобождается
  • заголовок кадра сразу изменяется, не только whend я остановить перетаскивание границы кадра.
  • он работает только при изменении размера справа или снизу, в противном случае содержимое перемещается с перетаскиванием.

Я думаю, что первый пункт разрешима комбинацией кода и MouseListener, что-то вроде if mouseReleased(), затем resize . Вот код, не стесняйтесь попробовать. Для дальнейших предложений я все еще рад любым предложениям.

код является незначительной модификацией GradientTranslucentWindowDemo.java из учебников Java. Я надеюсь, что это разрешено размещать его здесь, иначе, пожалуйста, укажите мне любое нарушение авторских причин. Черный JPanel должен быть содержание приложения, где как contentPane остается невидимым.

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.beans.PropertyChangeListener;

import javax.swing.*;
import static java.awt.GraphicsDevice.WindowTranslucency.*;

public class GroundFrame extends JFrame {

    Timer timer;
    JPanel panel2;

    public GroundFrame() {
        super("GradientTranslucentWindow");

        setBackground(new Color(0,0,0,0));
        setSize(new Dimension(300,200));
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel() {
        panel.setBackground(new Color(0,0,0,0));
        setContentPane(panel);

        setLayout(null);
        panel2 = new JPanel();
        panel2.setBackground(Color.black);
        panel2.setBounds(0,0,getContentPane().getWidth(), getContentPane().getHeight());
        getContentPane().add(panel2);

        addComponentListener(new ComponentListener() {

            @Override
            public void componentShown(ComponentEvent e) {}

            @Override
            public void componentResized(ComponentEvent e) {
                timer = new Timer(50, new Action() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if(timer.isRunning()){

                        }else{
                            resizePanel(getContentPane().getSize());
                        }
                    }

                    @Override
                    public void setEnabled(boolean b) {}

                    @Override
                    public void removePropertyChangeListener(PropertyChangeListener listener) {}

                    @Override
                    public void putValue(String key, Object value) {}

                    @Override
                    public boolean isEnabled() {return false;}

                    @Override
                    public Object getValue(String key) {return null;}

                    @Override
                    public void addPropertyChangeListener(PropertyChangeListener listener) {}
                });
                timer.setRepeats(false);
                timer.start();

            }

            @Override
            public void componentMoved(ComponentEvent e) {}

            @Override
            public void componentHidden(ComponentEvent e) {}
        });
    }

    public void resizePanel(Dimension dim){
        panel2.setBounds(0,0,dim.width, dim.height);
        repaint();
    }

    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() {
                GroundFrame gtw = new GroundFrame();
                gtw.setVisible(true);
            }
        });
    }
}

3 ответов


+1 к ответам мкорбеля и Дениса Тульского.

я сделал своего рода абстрактное решение, которое может помочь. Он поддерживает изменение размера (увеличение и уменьшение высоты и ширины)JFrame со всех четырех сторон JFrame (север, восток, юг и Запад) он также может быть изменен по ширине и высоте одновременно, когда мышь перемещается в один из углов.

в основном то, что я сделал:

  • добавить MouseMotionListener и MouseListener для JFrame
  • переопределить mouseDragged(..), mouseMoved(..), mousePressed(..) и mouseReleased(..) of Listeners.
  • set JFrame не изменять.
  • на mouseMoved(..) слушайте, когда мышь значение 10px или меньше снизу или справа. из JFrame, затем он устанавливает соответствующее направление изменения размера (высота или ширина), изменяет мышь Cursor (Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) для крайнего правого / изменения ширины,Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) для нижнего/hieght изменения размера,Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR) для верхней части высоты рамки изменяя размер или Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR) для изменения ширины левой стороны) соответственно и вызовите canResize(true).
  • на mouseDragged(..) обновить ширину или высоту для нового размера, как его перетащили в направлении
  • на mouseReleased(..) установить JFrame к новому размеру.
  • на mousePressed(..) мы проверяем для потребителя отжатые координаты (это позволяет нам увидеть если размер рамки уменьшает/увеличивает).

проверьте этот пример I сделано:

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();
            }
        });
    }
}

обновление:

отличный пример, который вы сделали, я исправил код, добавив MouseAdapter, который переопределяет mouseReleased(..) которых звонки resizePanel(...), когда mouseReleased(..)

см. здесь для фиксированного кода (также исправлено несколько незначительных вещей, таких как added ComponentAdapter вместо ComponentListener и AbstractAction вместо 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);
            }
        });
    }
}

только будущий размер, если окно будет просмотрено, в то время как исходный контент не изменяется. Как только пользователь отпускает мышь, кадр изменяется до этого размера

очень сложная идея, но

редактировать

используйте этот код для тестирования

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.");
    }
}

простой трюк, чтобы имитировать такое поведение, чтобы сделать кадр без изменения размера и посвятить некоторую часть кадра, чтобы быть ручки изменения размера, а затем добавить прослушиватели мыши и изменить его самостоятельно:

    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;
                    }
                }
            });
        }
    }

вы даже можете сделать jframe undecorated и выполнить все операции, такие как изменение размера, перемещение, закрытие и т. д. себе.

но опять же, это поведение контролируется оконным менеджером или композитным менеджером (вы можете настроить compiz, чтобы сделать это для вас, для образец.) Я думаю, что live-resizing был одной из ключевых рекламируемых функций NeXT, крупным шагом вперед в то время :)

кроме того, еще один трюк, который я пробовал, основан на том, что java 7 сообщает об изменении размера событий, как они происходят, а не на выпуске мыши, поэтому можно сохранить размер окна после первого изменения размера, а затем восстановить его, пока изменение размера не будет завершено. Работает не очень гладко, хотя:

    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();
                    }
                }
            });
        }
    }