Java重绘问题每次移动都会看到椭圆形

Java重绘问题每次移动都会看到椭圆形,java,swing,paintcomponent,Java,Swing,Paintcomponent,这是我简单代码的部分。我想在点击左键后实现将椭圆移动到光标X轴位置。问题是我只能看到椭圆的最后一个位置(当它已经停止时).我想while块中的重新绘制方法不能像我所希望的那样工作。我希望看到椭圆的每一个移动都能进入光标的位置。谢谢你的建议 import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.*; public class Test

这是我简单代码的部分。我想在点击左键后实现将椭圆移动到光标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);}
}
.我认为while块中的重新绘制方法不能像我希望的那样工作

您的问题与重新绘制“不工作”无关,而与绑定Swing事件线程有关。如果在Swing事件调度线程(或EDT)上运行长时间运行的进程,该线程负责绘制GUI并与用户交互,则GUI将冻结,直到释放EDT后才会绘制自身或响应

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

  • 使用摆动计时器作为动画“循环”
  • 另一种可能的解决方案是使用后台线程来执行
    线程.sleep(…)
    ,但在我看来,这不值得这么麻烦,因为Swing计时器工作得很好,更容易正确实现
此外:

  • 不要将鼠标听写器添加到JFrame中,而是添加到绘图JPanel中。否则,您会发现您将在y方向上偏离标题栏的高度
  • 使用
    mousePressed(…)
    方法不要
    mouseClicked(…)
    ,因为前者更宽容
  • 在鼠标上按下deltaX和deltaY,通过从点x减去x,从点y减去y来确定圆的方向
  • 我通过检查x和y与pointX之间的曼哈顿距离(
    manHattanDistance=Math.abs(x-pointX)+Math.abs(y-pointY);
    )和pointY,并在低于最小值时停止计时器,从而使您的代码正常工作。我还保留了之前的曼哈顿距离,并检查了新旧距离之间的差异,以确保椭圆形不会过度拍摄,有点像故障保护
  • 使用双精度键保持x、y、pointX、pointY等,并在绘图时转换为int
  • 不要忘记将图形对象强制转换为Graphics2D,并使用渲染提示启用抗锯齿。这将使图形更漂亮
  • 避免使用“神奇”数字。改用常量
  • 考虑使用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);
}
.我认为while块中的重新绘制方法不能像我希望的那样工作

您的问题与重新绘制“不工作”无关,而与绑定Swing事件线程有关。如果在Swing事件调度线程(或EDT)上运行长时间运行的进程,该线程负责绘制GUI并与用户交互,则GUI将冻结,直到释放EDT后才会绘制自身或响应

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

  • 使用摆动计时器作为动画“循环”
  • 另一种可能的解决方案是使用后台线程来执行
    线程.sleep(…)
    ,但在我看来,这不值得这么麻烦,因为Swing计时器工作得很好,更容易正确实现
此外:

  • 不要将鼠标听写器添加到JFrame中,而是添加到绘图JPanel中。否则,您会发现您将在y方向上偏离标题栏的高度
  • 使用
    mousePressed(…)
    方法不要
    mouseClicked(…)
    ,因为前者更宽容
  • 在鼠标上按下deltaX和deltaY,通过从点x减去x,从点y减去y来确定圆的方向
  • 我通过检查x和y与pointX之间的曼哈顿距离(
    manHattanDistance=Math.abs(x-pointX)+Math.abs(y-pointY);
    )和pointY,并在低于最小值时停止计时器,从而使您的代码正常工作。我还保留了之前的曼哈顿距离,并检查了新旧距离之间的差异,以确保椭圆形不会过度拍摄,有点像故障保护
  • 使用双精度键保持x、y、pointX、pointY等,并在绘图时转换为int
  • 不要忘记将图形对象强制转换为Graphics2D,并使用渲染提示启用抗锯齿。这将使图形更漂亮
  • 避免使用“神奇”数字。改用常量
  • 考虑使用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);
}

如上所述。您需要在单独的线程上执行这些操作

有时你需要减小x,所以检查它是否已经大于点
单击,否则程序将无限期递增。此外,您可能还希望对y执行与上述相同的操作。您需要在单独的线程上执行这些操作

有时你需要减小x,所以检查它是否已经大于点
单击,否则程序将无限期递增。另外,您可能也希望对y执行相同的操作

为什么要使用
多线程
标记?我在您的代码中没有看到任何多线程。您正在阻止
EDT
为什么有
多线程标记?我在你的代码中没有看到任何多线程。你今天阻止了
EDT
+1我看到你回答了相同的问题大约5次xD+1今天我看到你回答了相同的问题大约5次xD