问题
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.
回答1:
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
. YourList<Point> bresenham
and anotherList<Point> paintList
. Thebresenham
will hold your data, and thepaintList
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 newPoint
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 everydelay
milliseconds. So what the code above basically does is add aPoint
to thepaintList
taken from thebresenham
list, then removes the item therepaint
which calls thepaintComponent
. 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);
}
});
}
}
回答2:
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.
来源:https://stackoverflow.com/questions/22636362/delay-is-not-working-in-java-graphics