【问题标题】:Delay is not working in java graphics延迟在 Java 图形中不起作用
【发布时间】:2014-05-03 09:37:34
【问题描述】:

这是通过 Bresenham 算法在计算出的位置上绘制点的代码:

public void drawBresenhamPoints(Graphics2D g2, List<Point> bresenham) throws InterruptedException
{
       Graphics2D g = (Graphics2D) g2;

    if(bresenham == null)
        return;

    g.setColor(Color.DARK_GRAY);

    for(int i = 0; i < bresenham.size(); i = i+20)
    {
        int x = bresenham.get(i).x - pointWidth1/2;
        int y = bresenham.get(i).y - pointWidth1/2;

        int ovalW = pointWidth1;
        int ovalH = pointWidth1;

        g.fillOval(x, y, ovalW, ovalH);

            // delay
         try 
         {
             Thread.sleep(10);
         } 
         catch(Throwable e) 
         {
         System.out.println(e.getMessage()); 
         }
    }
}

列表“bresenham”包含所有在 Bresenham 的线条绘制算法的帮助下预先计算的点。我想在“for”循环内设置 1 秒的延迟,以便在 1 秒的间隔后绘制每个点。 “延迟”部分中列出的部分不起作用。如何让“延迟”发挥作用? 更具体地说,我希望以 1 秒的时间间隔在屏幕上看到所有点被一个一个地绘制出来。

【问题讨论】:

  • 阅读定时器,不要使用睡眠来避免 EDT 锁定

标签: java swing animation paintcomponent thread-sleep


【解决方案1】:

我假设您在 paint/paintComponent 方法中调用此方法。

只是一个指针:绘制过程永远不会休眠

改为使用javax.swing.Timer 来处理重复任务。 会做的是

  • 有两个Lists。你的List&lt;Point&gt; bresenham 和另一个List&lt;Point&gt; paintListbresenham 将保存您的数据,paintList 最初将为空。

  • 使用paintList 描绘你的观点

    @override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;
    
        for (Point p : paintList) {
            int x = bresenham.get(i).x - pointWidth1/2;
            int y = bresenham.get(i).y - pointWidth1/2;
    
            int ovalW = pointWidth1;
            int ovalH = pointWidth1;
    
            g.fillOval(x, y, ovalW, ovalH);
        }
    }
    
  • 虽然paintList 中最初没有任何内容,但您将在每次触发计时器事件时将新的Point 添加到列表中。

    Timer timer = new Timer(100, new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e) {
            if (bresenham.isEmpty()) {
                ((Timer)e.getSource()).stop();
            } else {
                paintList.add(bresemham.get(0));
                bresenham.remove(0);
            }
            repaint();  
        }
    });
    timer.start();
    

    构造函数的基本定时器是第一个delay,它是“迭代”和监听器中的第二个参数之间的延迟时间,监听器中实际监听每次触发的定时器事件delay 毫秒。因此,上面的代码基本上所做的是将Point 添加到从bresenham 列表中获取的paintList,然后删除调用paintComponent 的项目repaint。当列表为空时,计时器将停止。


更新

这是一个完整的运行示例

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;

public class BresenhamPoints extends JPanel {

    private static final int D_W = 500;
    private static final int D_H = 500;

    private List<Point> bresenhamList;
    private List<Point> paintList;

    public BresenhamPoints() {
        bresenhamList = createRandomPoints();
        paintList = new ArrayList<>();

        Timer timer = new Timer(100, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (bresenhamList.isEmpty()) {
                    ((Timer) e.getSource()).stop();
                } else {
                    paintList.add(bresenhamList.get(0));
                    bresenhamList.remove(0);
                }
                repaint();
            }
        });
        timer.start();
    }

    private List<Point> createRandomPoints() {
        Random rand = new Random();
        List<Point> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add(new Point(rand.nextInt(D_H), rand.nextInt(D_H)));
        }
        return list;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Point p : paintList) {
            g.fillOval(p.x - 5, p.y - 5, 10, 10);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(D_W, D_H);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new BresenhamPoints());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

【讨论】:

    【解决方案2】:

    sleep 方法的值以 毫秒 为单位,因此您在此睡眠 10 毫秒。将其更改为 1000 会产生更明显的中断。

    正如所指出的,您不应该在 EDT 上使用任何耗时甚至更糟糕的锁定机制,因为它会挂起您的整个应用程序。您可以使用Timer 触发事件并一次绘制一个点。 This 以前的 SO 帖子应该可以满足您的需求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多