Re: Graphics - how to show partial progress.
On Fri, 21 Dec 2007 18:22:31 +0000, rossum <rossum48@coldmail.com>
wrote:
Thankyou all for your ongoing help. Rather than scatter my responses
through the thread, I will put them all together here.
Lew: I am not sure about the problem with some end-of-lines not
registering. I developed the code in NetBeans, pasted into an offline
text editor and did final touchup in the Forte Agent built-in editor.
It displays fine in all of these as well as in Google Groups. All of
this on Windows. I am not sure which stage of the process introduced
the problem with some line terminations, and I cannot repdoduce it on
my PC. My apologies.
I thought that "volatile" would be neccessary, but not sufficient on
its own. As you can probably tell, threading is not my strong point.
Knute, Lew: I see the point about not starting threads from inside
constructors. Since this is just a test piece, I have made the
GraphPanel class final so I can be sure that the thread start is
really the final line of construction. I will change that when I move
to the actual program.
Lew, Daniel: I read that repaint() was one of the few thread safe
methods in Swing, so I felt reasonably confident in using it.
Mark: Thanks for the SwingWorker suggestion, I had not picked that up
when I moved to Java 6. As you can see from the code below, I have
incorporated it.
My thanks again, and apologies in advance to Lew if the EoL problem is
still there. :(
rossum
// --- Partial Code Starts ---
final class GraphPanel extends JPanel {
final int biXpos = 30;
final int biYpos = 60;
final int biHeight = 100;
final int biWidth = 150;
volatile BufferedImage mOffScreenImage;
public GraphPanel() {
// Set up off screen image
mOffScreenImage = new BufferedImage(biWidth,
biHeight, BufferedImage.TYPE_INT_BGR);
// Start pixel calculation thread
PixelCalc pc = new PixelCalc();
/** @todo - move thread start out of constructor. */
pc.execute();
} // end constructor
/** Calculates colours for pixels */
class PixelCalc extends SwingWorker<BufferedImage,
BufferedImage> {
BufferedImage mBim = new BufferedImage(biWidth,
biHeight, BufferedImage.TYPE_INT_BGR);;
@Override
public BufferedImage doInBackground() {
Graphics2D g2d = mBim.createGraphics();
final int xLimit = mBim.getWidth();
final int yLimit = mBim.getHeight();
for (int x = 0; x < xLimit; ++x) {
for (int y = 0; y < yLimit; ++y) {
g2d.setColor(pickColour(x, y));
g2d.drawLine(x, y, x + 1, y + 1);
} // end for
// Check for termination request
if (isCancelled()) { return null; }
Thread.yield(); // Play nice
// Publish partial progress
if (x % 50 == 49) {
publish(mBim);
} // end if
// Artificial Delay
try {
Thread.sleep(25);
} catch (InterruptedException iex) {
return null;
} // end try/catch
} // end for
g2d.dispose();
// Return completed image
return mBim;
} // end doInBackground()
@Override
protected void process(List<BufferedImage> images) {
if (images == null || images.size() == 0) { return; }
BufferedImage latest = images.get(images.size() - 1);
mOffScreenImage = latest;
repaint();
} // end process()
@Override
protected void done() {
try {
mOffScreenImage = get();
} catch (InterruptedException ignore) {
// Do nothing
} catch (java.util.concurrent.ExecutionException eex)
{
throw new RuntimeException("PixelCalc.done: " +
"Unable to calculate image.", eex);
} // end try/catch
repaint();
} // end done()
private Color pickColour(int x, int y) {
switch ((x + y) % 3) {
case 0: return Color.CYAN;
case 1: return Color.GREEN;
case 2: return Color.MAGENTA;
default: return Color.BLACK;
} // end switch
} // end pickColor()
} // end class PixelCalc
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Resize
Container parent = this.getParent();
this.setSize(parent.getWidth(), parent.getHeight());
// Show image
g.drawImage(mOffScreenImage, biXpos, biYpos, null);
} // end paintComponent()
} // end class GraphPanel
// --- Partial Code Finishes ---