Java重绘问题 - 看到椭圆形每个移动

时间:2013-07-26 22:32:26

标签: java swing paintcomponent

我的简单代码的部分。我想在点击左键后实现将椭圆移动到光标X轴位置。问题是我只能看到椭圆的最后位置(当它已经停止时) 。我认为重复方法虽然块不能正常工作。我希望看到每个椭圆移动到达光标位置。谢谢你的建议。

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

2 个答案:

答案 0 :(得分:3)

  

。我认为重写方法虽然阻止不能正常工作

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

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

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

此外:

  • 不要将MouseListener添加到JFrame,而是添加到绘图JPanel。否则你会发现你将在y方向偏离标题栏的高度。
  • 使用mousePressed(...)方法而不是mouseClicked(...),因为前者更宽容。
  • 在mousePressed上获取deltaX和deltaY,圆圈的方向应该是从pointX减去x,从pointY减去y。
  • 我已经通过检查x和y以及pointX(manHattanDistance = Math.abs(x - pointX) + Math.abs(y - pointY);)和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);
}

答案 1 :(得分:0)

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

有时你需要递减x,所以检查它是否已经大于该点 单击,或程序将无限增加它。你也可能想用y

做同样的事情