Question

This is a code for drawing points on calculated locations by Bresenham's algorithm:

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

The list 'bresenham' contains all the points which are pre-calculated with the help of Bresenham's line drawing algorithm. I want to set a delay of 1 second inside the 'for' loop so that each and every point is drawn after an interval of 1 second. The portion listed in the 'delay' section doesn't work. How to make 'delay' work? More specifically, I want to see all the points being drawn one by one on the screen in an interval of 1 second.

Was it helpful?

Solution

I'm assuming you're calling this method in a paint/paintComponent method.

Just a pointer: Never ever ever sleep the paint process

Instead use a javax.swing.Timer for repeated tasks. What I would do is

  • Have two Lists. Your List<Point> bresenham and another List<Point> paintList. The bresenham will hold your data, and the paintList will be initially empty.

  • Use the paintList to paint your points

    @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);
        }
    }
    
  • Though there's nothing initially in the paintList, you will add a new Point to the list every firing of a timer event.

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

    The basic timer of the constructor is firs the delay, which is the time delayed between "iterations", and second argument in the listener that actually listens for the timer event that is fired every delay milliseconds. So what the code above basically does is add a Point to the paintList taken from the bresenham list, then removes the item the repaint which calls the paintComponent. When the list is empty, the timer will stop.


UPDATE

Here's a complete running example

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

OTHER TIPS

The value for the sleep method is in milliseconds, so there you are sleeping for 10ms. Changing it to 1000 will create a more noticeable interrupt.

As pointed out, you should never have any time consuming or even worse locking mechanisms on the EDT since it will hang your entire application. You could use a Timer to fire off events and draw one point at a time. This previous SO post should do what you need.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top