0

这是我的简单代码的一部分。我想在单击左键后实现将椭圆移动到光标 X 轴位置。问题是我只能看到椭圆的最后一个位置(当它已经停止时)。我认为 while 块中的重绘方法不起作用如我所愿。我希望看到椭圆的每一次移动都进入光标位置。谢谢您的建议。

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;

public class Testfile extends JPanel implements Runnable,MouseListener{
public static JFrame frame;
public int x;
public int y;
public int pointX;
public int pointY;

 public void paintComponent(Graphics g){
     super.paintComponent(g);

     g.fillOval(x, y, 20, 20);
 }

 public static void main(String args[])throws InterruptedException{
     Testfile z=new Testfile();
     z.setBackground(Color.cyan);

     frame=new JFrame("Test");
     frame.setSize(500,500);
     frame.add(z);
     frame.addMouseListener(z);
     frame.setVisible(true);
}
public void mouseClicked(MouseEvent e){
    pointX=(int)MouseInfo.getPointerInfo().getLocation().getX();
    pointY=(int)MouseInfo.getPointerInfo().getLocation().getY();

    try{
    while(x!=pointX){
        x=x+1;
        Thread.sleep(10);
        repaint();
        }
    }
        catch(InterruptedException v){System.out.println(v);}
}
4

2 回答 2

3

.我认为 while 块中的重绘方法无法正常工作

您的问题与重新绘制“不工作”无关,而与您绑定 Swing 事件线程有关。如果您在 Swing Event Dispatch Thread(或 EDT)上运行一个长时间运行的进程,该线程负责绘制 GUI 并与用户交互,您的 GUI 将冻结并且在 EDT 发布之前不会自行绘制或响应。

解决方案:不要使用 while (true) 循环或Thread.sleep(...)在 Swing 事件线程上。还:

  • 改为使用 Swing Timer 作为动画“循环”。
  • 另一种可能的解决方案是使用后台线程来执行Thread.sleep(...),但在我看来,这不值得麻烦,因为 Swing Timer 可以很好地工作并且更容易正确实现。

还:

  • 不要将 MouseListener 添加到 JFrame,而是添加到绘图 JPanel。否则你会发现你会在 y 方向偏离标题栏的高度。
  • 不要使用这种mousePressed(...)方法,mouseClicked(...)因为前者更宽容。
  • 获取 mousePressed 上的 deltaX 和 deltaY,通过从 pointX 中减去 x 和从 pointY 中减去 y 来获得圆的方向。
  • manHattanDistance = Math.abs(x - pointX) + Math.abs(y - pointY);通过检查 x 和 y 以及 pointX ( ) 和 pointY之间的曼哈顿距离,我已经让你的代码工作,如果它低于最小值,则停止计时器。我还保存了之前的曼哈顿距离,并检查了新旧距离之间的差异,以确保椭圆不会过冲,有点像故障保险。
  • 使用双精度来保存您的 x、y、pointX、pointY 等,并在绘图时转换为 int。
  • 不要忘记将您的 Graphics 对象转换为 Graphics2D 并使用 RenderingHints 打开抗锯齿功能。这将使图形更漂亮。
  • 避免“魔术”数字。请改用常量。
  • 考虑使用 x 和 y 作为圆的中心,而不是左上角。

例如,我的paintComponent(...)方法可能如下所示:

public void paintComponent(Graphics g) {
  super.paintComponent(g);
  Graphics2D g2 = (Graphics2D) g;
  g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);

  // RADIUS is an int const and = 10
  g.fillOval((int) x - RADIUS, (int) y - RADIUS, 2 * RADIUS, 2 * RADIUS);
}
于 2013-07-26T22:33:36.290 回答
0

如上。你需要在不同的线程上做这些事情。

有时您需要减少 x 以检查它是否已经大于单击的点,否则程序将无限期地增加它。你也可能想对 y 做同样的事情

于 2013-07-26T22:39:19.250 回答