7

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

(1) 调整大小前的状态

在此处输入图像描述

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

在此处输入图像描述

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

在此处输入图像描述

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

编辑:

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

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

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

该代码是对 Java 教程中的GradientTranslucentWindowDemo.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);
            }
        });
    }
}
4

3 回答 3

6

如果窗口将被预览,则只有将来的大小,而原始内容不会调整大小。一旦用户释放鼠标,Frame 就会调整为该大小

非常复杂的想法,但是

编辑

使用此代码进行测试

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.");
    }
}
于 2012-10-25T09:04:41.090 回答
6

模仿这种行为的一个简单技巧是使框架不可调整大小并将框架的某些部分专用于调整大小句柄,然后添加鼠标侦听器并自行调整大小:

    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 不装饰,并自己执行所有操作,如调整大小、移动、关闭等。

但同样,此行为由窗口管理器或合成管理器控制(例如,您可以调整 compiz 为您做这样的事情)。我认为实时调整大小是 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();
                    }
                }
            });
        }
    }
于 2012-10-25T10:45:16.633 回答
6

+1 mKorbel 和 Denis Tulskiy 的回答。

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

基本上我所做的是:

  • 添加MouseMotionListenerMouseListenerJFrame
  • 覆盖mouseDragged(..),和s 。mouseMoved(..)_mousePressed(..)mouseReleased(..)Listener
  • 设置JFrame为不可调整大小。
  • mouseMoved(..)监听鼠标距离底部或右侧10px或更少的时间。,JFrame然后设置适当的调整大小方向(高度或宽度),相应地更改鼠标CursorCursor.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(..)我们检查用户按下的坐标(这允许我们查看帧大小是否在减少/增加)。

看看我做的这个例子:

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(..)

请参阅此处以获取固定代码(还修复了一些小问题,例如添加ComponentAdapter而不是ComponentListenerAbstractAction代替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);
            }
        });
    }
}
于 2012-10-25T11:06:41.703 回答