JFrame与Ubuntu(Unity?)的错误位置



似乎Ubuntu有一个错误(也许只有unity)。JFrame的装饰被考虑在getLocation()getSize(),但不考虑setLocation()setSize()。这会导致奇怪的行为。例如,如果您在显示框架并更改尺寸后使用 pack(),则框架将下降 20 像素......

为了说明一个具体案例,当它变得非常烦人时,我做了一个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 问题,我什至不知道如何确定我的用户是否正在使用 Unity......

有什么解决方法的想法吗?

编辑 :好的,MadProgrammer确实提供了更好的代码,但有时仍然会出现错误。我相应地编辑了我的鼠标侦听器以跟踪错误:

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

每次 2 个值相同时,都意味着该错误将在下次单击时发生。否则,值会有所不同。在其他操作系统上,值始终相同。实际上,它们应该总是或相同,或者总是不同的。我不明白他们怎么会有时相等,有时不同......

我没有

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.MouseMotionListener;
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.addMouseListener(ma);
                pane.addMouseMotionListener(ma);
            }
        });
    }
}

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