与使用setLocation()“传送”它的方式相比,如何更顺利地将JFrame移动到特定位置?
我试图建立一个方法“移动()”,我可以使用frame.setLocation(int x,int y)方法移动JFrame时从开始到结束位置的动画方式。我尝试了以下方法,并将框架放在正确的位置,但问题在于动画首先在x轴上下移,然后才沿y轴下移,但我的目标是使它看起来像是一个对角线运动目的地点。我知道它是因为第一个forloop,因为他们没有合适的条件将setLocation方法的过程分解为单个部分,但我完全不知道如何解决这个问题。与使用setLocation()“传送”它的方式相比,如何更顺利地将JFrame移动到特定位置?
public int currentX() {
return (int) frame.getLocation().getX();
}
public int currentY() {
return (int) frame.getLocation().getY();
}
public void move(int x, int y) {
for (int newX = currentX(); newX < x; newX++) {
frame.setLocation(currentX() + 1, currentY());
for(int newY = currentY(); newY < y; newY++) {
frame.setLocation(currentX(), currentY() + 1);
}
}
}
预先感谢您!
Swing是单线程,您需要将for-loop
从主线程移出。秋千也不是线程安全的,所以任何修改UI的状态应的范围内完成主(事件调度)线程 - 捕22 - 最简单的解决方法是使用一个Swing Timer
为见How to use Swing Timers更多细节
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Hello"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
move(frame, 100, 100);
}
});
}
});
}
public static void move(JFrame frame, int deltaX, int deltaY) {
int xMoveBy = deltaX > 0 ? 4 : -4;
int yMoveBy = deltaY > 0 ? 4 : -4;
int targetX = frame.getX() + deltaX;
int targetY = frame.getY() + deltaY;
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int frameX = frame.getX();
int frameY = frame.getY();
if (deltaX > 0) {
frameX = Math.min(targetX, frameX + xMoveBy);
} else {
frameX = Math.max(targetX, frameX - xMoveBy);
}
if (deltaY > 0) {
frameY = Math.min(targetY, frameY + yMoveBy);
} else {
frameY = Math.max(targetY, frameY - yMoveBy);
}
frame.setLocation(frameX, frameY);
if (frameX == targetX && frameY == targetY) {
((Timer)e.getSource()).stop();
}
}
});
timer.start();
}
}
非常感谢您的快速解决方案。我尝试了你的代码,它完美的工作。现在我真的必须阅读很多关于你使用的东西,因为我不了解它,并认为实现我的想法会容易得多。 – NarcatasCor
@NarcatasCor Swing中的动画并不难,但它需要不同的方法和思维方式 – MadProgrammer
您的第二个循环一直运行,直到完成,您需要同时移动框架,并且只在需要时增加X
或Y
!
public int currentX() {
return (int) frame.getLocation().getX();
}
public int currentY() {
return (int) frame.getLocation().getY();
}
public void move(int x, int y) {
for (int newX = currentX(), newY = currentY(); newX < x || newY < y; ) {
frame.setLocation(newX, newY);
if (newX < x) newX++;
if (newY < y) newY++;
}
}
这就是我已经尝试过的,尽管这种情况下的动画会以一种诊断方式移动窗口,但最终的位置将是错误的。 – NarcatasCor
这仍然会阻塞事件调度线程,导致OP正在经历的结果没有变化 – MadProgrammer
@MadProgrammer但他清楚地表示“动画首先在x轴上下移,然后才沿y轴下移”这意味着他注意到动画,所以我猜他没有从主线程启动它,这不是他真正的问题!为什么我会修理一些没有损坏的东西! – BaSsGaz
Swing是单线程,您需要将'for-loop'移出主线程。 Swing也不是线程安全的,所以任何对UI状态的修改应该在主(Event Dispatching)线程的上下文中完成 - catch 22 - 最简单的解决方案是使用Swing Timer。 – MadProgrammer
可能的[有没有办法在Java中动画整个Jframe,以便它移动?](https://stackoverflow.com/questions/14950694/is-there-a-way-to-animate-an-entire-jframe-in- java-so-it-it) – BaSsGaz