Swing:在Linux中调整像框架一样的JFrame,例如

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

(1)resize前的状态

在此处输入图像描述

(2)用户开始下垂(在红色圆圈)

在此处输入图像描述

(3)用户释放鼠标,框架resize

在此处输入图像描述

是否有可能在Java Swing中意识到这一点?

编辑:

由于这个程序有一天也应该在较低的Java RE中作为7运行,我尝试将mKorbel建议与translucend Frame的注释中的建议结合起来。 结果接近目标,除了

  • 在我停止移动鼠标后,contentPane的内容会resize,而不是在释放鼠标时
  • 帧标题立即resize,而不仅仅是我停止拖动框架边框。
  • 它仅在从右侧或底部resize时才起作用,否则内容随拖动而移动。

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

该代码稍微修改了Java Tutorials中的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); } }); } } 

+1给mKorbel和Denis Tulskiy的答案。

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

基本上我做的是:

  • MouseMotionListenerMouseListener添加到JFrame
  • 覆盖mouseDragged(..)mouseMoved(..)mousePressed(..)mouseReleased(..)
  • JFrame设置为不可resize。
  • mouseMoved(..)监听鼠标从底部或右侧是10px或更少。 然后,它设置适当的resize(高度或宽度),更改鼠标CursorCursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)进行最右边/宽度调整, Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)进行底部/高度调整, Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)用于帧高度resize或Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)用于左侧宽度resize)并调用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(..) ,当mouseReleased(..) resizePanel(...)调用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); } }); } } 

如果将预览窗口,则仅显示未来的大小,而原始内容未resize。 一旦用户释放鼠标,Frame就会调整为该大小

非常复杂的想法,但是

  • ComponentListener添加到JFrame

  • override componentResized(ComponentEvent e)

  • 添加具有短延迟(400-600)的Swing Timer ,输出到Swing Action

  • 如果继续resize,则调用Timer#restart()

编辑

使用此代码进行测试

 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 listSomeString = new Vector(); private Vector listSomeAnotherString = new Vector(); 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."); } } 

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

  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未修饰并执行所有操作,如自己resize,移动,关闭等。

但同样,这种行为是由窗口管理器或合成管理器控制的(例如,你可以调整compiz为你做这样的事情)。 我认为实时resize是NeXT的主要广告function之一,当时迈出了重要的一步:)

此外,我尝试的另一个技巧是基于java 7报告在事件发生时调整事件大小,而不是鼠标释放,因此可以在首次resize后保存窗口大小,然后恢复它,直到resize完成。 但是,工作不顺利:

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