【问题标题】:JFrame wrong location with Ubuntu (Unity ?)Ubuntu 的 JFrame 位置错误(Unity?)
【发布时间】:2015-06-15 01:19:11
【问题描述】:

似乎 Ubuntu 有一个错误(可能只是统一)。 getLocation()getSize() 考虑了 JFrame 的装饰,但 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 确实提供了更好的代码,但有时仍会出现该错误。我相应地编辑了我的 MouseListener 以跟踪错误:

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

每次两个值相同时,意味着下次点击时会出现该错误。否则,值不同。在其他操作系统上,这些值始终相同。实际上,它们应该总是或相同,或总是不同。我不明白它们为什么有时相同有时不同......

【问题讨论】:

  • 鼠标事件与生成它们的容器相关,这意味着位置 0x0 实际上是容器的左上角。由于您已经在contentPane 上注册了MouseListener,因此您的鼠标坐标在它的上下文中。也许可以尝试将MouseEvent坐标转换为屏幕坐标,这样会更兼容框架的坐标
  • 嗯...我尝试了getLocationOnScreen和getLocation的各种组合,但我没有成功获得预期的行为...看起来在移动之后,getLocation方法将返回正确的值,但经过一些毫秒后,它会考虑边框...
  • 我可能不会在mouseMoved 事件上更新posXposY,就个人而言,我会使用mouseClicked 设置锚点,然后计算与此的距离你已经拖动了(考虑到点击点和框架的原始位置之间的差异)
  • 这是另一种可能性,但我相信它不会改变任何事情。如果我的方法是错误的,它不会与 setUndecorated(true) 一起使用。它只会使代码更复杂,因为我需要同时监听 Mouse 事件和 MouseMotion 事件。但我认为您对 getYOnScreen() 的看法是正确的。如果不考虑边界,我应该能够找到返回 0 的计算,否则返回边界的高度。

标签: java swing ubuntu jframe location


【解决方案1】:

我没有要测试的 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);
            }
        });
    }
}

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

【讨论】:

  • 耶!做得好。它比以前好得多。有时jframe“跳转”时仍然存在。当我单击窗格时会发生这种情况。我正在检查是否发现问题。还是非常感谢!
  • 不,我不明白。我认为 JFrame 只是随机愚蠢。无论如何,我认为我们不能比你建议的做得更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多