用Ubuntu(JFrame)错误的位置?

似乎有一个Ubuntu的错误(也许只有统一)。 getLocation()getSize()将考虑JFrame的装饰,但不适用于setLocation()setSize() 。 这导致了怪异的行为。 例如,如果在显示框架并更改了尺寸后使用pack(),则框架将减less20个像素…

为了说明一个真正烦人的具体案例,我做了一个SSCCE。 这是一个带有基本JPanel的JFrame。 如果拖动面板,则JFrame应该移动。

在Windows下,它按预期工作。 在Ubuntu下,如果我做了setUndecorated(true)它也可以正常工作,但如果我让装饰,JFrame变得疯狂!

 public class Test { private static JFrame mainFrame; public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { mainFrame = new JFrame("test"); mainFrame.setSize(300,20); mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); mainFrame.setVisible(true); Container pane = mainFrame.getContentPane(); pane.addMouseMotionListener(new MouseMotionListener() { private int posX = 0, posY = 0; @Override public void mouseDragged(MouseEvent e) { int x = e.getX() - posX + mainFrame.getX(); int y = e.getY() - posY + mainFrame.getY(); mainFrame.setLocation(x, y); } @Override public void mouseMoved(MouseEvent e) { posX = e.getX(); posY = e.getY(); } }); } }); } } 

我不知道如何解决这个问题。 我怎样才能得到窗户装饰的大小? 我不知道Ubuntu的哪个版本。 如果这只是一个统一的问题,我甚至不知道如何找出我的用户是否使用Unity …

任何想法的解决方法?

编辑 :好的,MadProgrammer确实提供了一个更好的代码,但是这个bug有时候还是会出现的。 我相应地编辑了我的MouseListener来跟踪这个bug:

  pane.addMouseMotionListener(new MouseMotionListener() { private int posX = 0, posY = 0; @Override public void mouseDragged(MouseEvent e) { int x = e.getXOnScreen() - posX; int y = e.getYOnScreen() - posY; mainFrame.setLocation(x, y); System.out.println("drag : border ignored / border considered : "+(mainFrame.getY()+e.getY())+" / "+e.getYOnScreen()); } @Override public void mouseMoved(MouseEvent e) { posX = e.getXOnScreen() - mainFrame.getX(); posY = e.getYOnScreen() - mainFrame.getY(); System.out.println("move : border ignored / border considered : "+e.getY()+" / "+posY); } }); 

每次这两个值是相同的,这意味着该错误将发生在下一次点击。 否则,值是不同的。 在其他操作系统上,值总是相同的。 实际上,他们应该总是或者总是不一样的。 我不明白他们有时会是平等的,有时甚至是不同的。

我没有Ubuntu测试,但是我在MacOS和Windows上使用了类似的东西

 import java.awt.Container; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionlistner; import javax.swing.JFrame; import javax.swing.SwingUtilities; public class Test { private static JFrame mainFrame; public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { mainFrame = new JFrame("test"); mainFrame.setSize(300, 100); mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); mainFrame.setVisible(true); Container pane = mainFrame.getContentPane(); MouseAdapter ma = new MouseAdapter() { private Point offset; @Override public void mouseDragged(MouseEvent e) { if (offset != null) { Point pos = e.getLocationOnScreen(); int x = pos.x - offset.x; int y = pos.y - offset.y; System.out.println(x + "x" + y); SwingUtilities.getWindowAncestor(e.getComponent()).setLocation(x, y); } } @Override public void mousePressed(MouseEvent e) { Point pos = SwingUtilities.getWindowAncestor(e.getComponent()).getLocation(); // Point pos = e.getComponent().getLocationOnScreen(); offset = new Point(e.getLocationOnScreen()); System.out.println(pos + "/" + offset); offset.x -= pos.x; offset.y -= pos.y; System.out.println(offset); } }; pane.addMouselistner(ma); pane.addMouseMotionlistner(ma); } }); } } 

这应该适用于装饰窗和未装饰窗,因为它取决于组件的位置(在屏幕上)和窗口当前位置之间的差异。 拖动时,它会计算点击点的移动距离,并相应地更新窗口的位置(允许点击的原始偏移量)