Swing:在 Linux 中调整 JFrame 的大小,例如 Frames

我想知道是否有可能以这种方式实现 JFrame 的大小调整,它的大小已经被调整,例如 linux 中的标准窗口.更准确的说:如果用户开始拖动,只有未来的窗口大小会被预览,而原始内容不会被调整大小.一旦用户释放鼠标,Frame 就会调整为该大小.在图片中:

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 be more precise: If the user starts do drag, 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. In images:

(1) 调整大小前的状态

(2) 用户开始拖动(在红色圆圈处)

(3) 用户释放鼠标,框架调整大小

是否有可能在 Java Swing 中实现这一点?

Is it possible to realize that in Java Swing?

由于这个程序有一天也应该在较低的 Java RE 中运行 7,所以我尝试将 mKorbel 建议与半透明框架结合起来,并将评论中的建议与半透明框架结合起来.结果接近目标,除了

As this program one day should run also in lower Java RE as the 7, I tried to combine mKorbel suggestions with and the suggestion in the comment with the translucend Frame. The result is close to the goal, except that

  • contentPane 的内容在我停止移动鼠标后调整大小,而不是在释放鼠标时
  • 框架标题会立即调整大小,而不仅仅是当我停止拖动框架边框时.
  • 仅在从右侧或底部调整大小时才有效,否则内容会随着拖动而移动.

我认为第一点可以通过代码和 MouseListener 的组合来解决,例如 if mouseReleased(), then resize .这是代码,请随意尝试.对于进一步的建议,我仍然对任何建议感到高兴.

I think the first point is resolvable by a combination of the code and a MouseListener, something like if mouseReleased(), then resize . Here is the code, feel free to try it. For further suggestions I'm still happy about any suggestions.

代码是对 GradientTranslucentWindowDemo 稍作修改.java 来自 Java 教程.我希望它被允许在这里发布,否则请指出任何侵犯版权的原因.黑色的 JPanel 应该是应用程序的内容,因为 contentPane 保持不可见.

The code is a slightly modification of the GradientTranslucentWindowDemo.java from the Java Tutorials. I hope it's permitted to post it here, otherwise please indicate me any violation against copyright causas. The black JPanel is supposed to be the content of the application, where as the contentPane stays invisible.

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

推荐答案

+1 对 mKorbel 和 Denis Tulskiy 的回答.

+1 to mKorbel and Denis Tulskiy's answers.

我做了一种可能会有所帮助的抽象解决方案.它支持从 JFrame 的所有四个侧面(NORTH、EAST、SOUTH 和 WEST)调整 JFrame 的大小(增加和减少高度和宽度)它也可以调整大小当鼠标移动到 for 角之一时,同时按宽度和高度.

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.

基本上我所做的是:

  • MouseMotionListenerMouseListener 添加到 JFrame
  • 覆盖 mouseDragged(..)mouseMoved(..)mousePressed(..)mouseReleased(..)Listeners.
  • JFrame 设置为不可调整大小.
  • mouseMoved(..) 中监听鼠标距离底部或右侧10px 或更少的时间.JFrame,然后设置适当的resize方向(高度或宽度),改变鼠标Cursor (Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)用于最右侧/宽度调整,Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) 用于底部/高度调整,Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR) 用于顶部帧高度调整或Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR) 用于调整左侧宽度)并调用 canResize(true).
  • mouseDragged(..) 中根据拖动方向更新宽度或高度为新尺寸
  • mouseReleased(..) 中将 JFrame 设置为新大小.
  • mousePressed(..) 中,我们检查用户按下的坐标(这允许我们查看帧大小是否在减小/增大).
  • 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).

看看我做的这个例子:

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 来修复代码,它覆盖了调用 resizePanel(...)mouseReleased(..)mouseReleased(..)

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

查看这里的固定代码(还修复了一些小问题,例如添加 ComponentAdapter 而不是 ComponentListenerAbstractAction 而不是 行动):

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

相关文章