我有一个简单的java gui(下面的代码),由于某种原因,当我第一次尝试移动或调整它的大小时,它会“跳”回原来的位置。所以基本上我必须移动 GUI 两次才能让它移动一次,因为一旦我第一次释放鼠标,它就会弹回到原来出现的位置。
import javax.swing.*;
public class JFrameTester {
public static void main(String[] args) {
JFrame f = new JFrame("A JFrame");
f.setSize(250, 250);
f.setLocation(300,200);
f.getContentPane().add(new JTextArea(10, 40));
//f.pack();
f.setVisible(true);
//f.validate();
}
}
我在 GNU Linux 上运行 java 1.6。我正在将显示导出回我的 Windows 计算机,想知道它是否与 X11 转发有关,因为当我在 Windows 中运行 gui 时,它没有显示此行为。但是,当我在 Fedora Linux 机器(带有 java 1.7)上运行此 gui 时,它根本不显示此行为 - 无论是否导出显示。
几个明显的问题:
仅在事件调度线程上构建和操作 Swing GUI 对象。如果不这样做,就会产生竞争条件,这种条件可能会很模糊,直到不同的平台或网络延迟将其暴露出来。
pack()
,这“会导致
Window
的大小适合其子组件的首选大小和布局。”如果不这样做,会导致在移动或调整大小时验证无效的
Container
。当过早可见的组件移动到定义的位置时,它们看起来会“跳跃”。
setVisible()
设为影响初始外观的last操作。
import java.awt.EventQueue;
import javax.swing.*;
public class JFrameTester {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame("A JFrame");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(new JTextArea(10, 40)));
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
});
}
}
setLocation
或
setLocationRelativeTo
在构造窗口对象时。 (但是如果 你不调用
setLocation
,那么窗口就会出现在左上角 拐角处,不方便。)具体症状是:当第一次显示窗口或对话框时,并且 用户尝试通过拖动标题栏来移动它,拖动后 完成后,窗口跳回到原来的位置。在那之后, 移动窗口工作正常。
我找到的解决方案是以编程方式调整窗口的位置 首次显示后不久:
// Call this *before* 'setVisible(true)'.
f.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowOpened(java.awt.event.WindowEvent e) {
final java.awt.Window w = e.getWindow();
javax.swing.Timer t = new javax.swing.Timer(100 /*ms*/,
new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
// Slightly adjust the window position to work around a
// bug where the window manager "rejects" the first
// attempt to move the window.
int y = w.getLocation().y;
w.setLocation(w.getLocation().x, y+1);
}
});
t.setRepeats(false);
t.start();
}
});
如上所述,这必须在 setVisible(true)
之前调用,否则你 可能会错过
windowOpened
活动。使用时这一点也很重要 a
JDialog
因为在这种情况下,
setVisible(true)
会阻塞,直到 对话框已关闭。选择移动 1 个像素是为了最大限度地减少干扰,因为调整 通常对用户可见。我说通常是因为有时(也许 四分之一)调整不会发生,即使 成功解除了潜在的错误。移动 0 像素不会 解除错误。
不幸的是,计时器对于避免失去竞争条件是必要的 与窗口管理器。在我的测试中,没有计时器,窗口 当 用户首先移动它。使用 100 毫秒计时器时,我从未观察到它失败 (经过超过 100 次测试),但 50 毫秒还不够。这将取决于 当然是机器速度。
版本:Linux 上的 Java 1.8.0_92 和 Windows 10 上的 cygwin 3.4.7。