1

I'm having this problem where the paint() or update() methods in a class isn't getting called when I execute repaint(). Here's the code:

public class BufferedDisplay extends Canvas implements Runnable {

// Contains all the images in order, ordered from background to foreground
private ArrayList<ImageStruct> images;
// Tracks the last insert ID of the last image for a particular layer
private TreeMap<Integer, Integer> insertIDs;
// Image that holds the buffered Image
private Image offscreen;

public BufferedDisplay() {
    images = new ArrayList<ImageStruct>();
    insertIDs = new TreeMap<Integer, Integer>();
}

public void addImageStruct(ImageStruct is) {
    int layer = is.getLayer();
    // Index to insert the image at
    int index = -1;
    if(insertIDs.containsKey(layer)) {
        index = insertIDs.get(layer)+1;
        insertIDs.put(layer, index);
    }
    else {
        index = images.size();
        insertIDs.put(layer, index);
    }
    if(index>-1) {
        images.add(index, is);
    }
}

public void run() {
    try
    {
        while(true)
        {
            System.out.print("\nSleeping... ");
            System.out.print("ArraySize:"+images.size()+" ");
            Thread.sleep(1000);
            System.out.print("Slept. ");
            repaint();
        }
    }
    catch(Exception e)
    {
        System.out.println("Display Error: ");
        e.printStackTrace();
        System.exit(-1);
    }
}

// Overrides method so the background isn't automatically cleared
public void update( Graphics g )
{
    System.out.print("Updating... ");
    paint(g);
}

public void paint( Graphics g )
{
    System.out.print("Painting... ");
    if(offscreen == null)
        offscreen = createImage(getSize().width, getSize().height);
    Graphics buffer = offscreen.getGraphics();
    buffer.setClip(0,0,getSize().width, getSize().height);
    g.setColor(Color.white);
    paintImages(buffer);
    g.drawImage(offscreen, 0, 0, null);
    buffer.dispose();
}

public void paintImages( Graphics window )
{
    for(ImageStruct i : images) {
        i.draw(window);
    }
}
}

This class is implemented in this:

public class Game extends JPanel{
// A reference to the C4Game class
private C4Game game;
// A reference to the BufferedDisplay class
private BufferedDisplay display;
// The Image used to initialize the game board
private Image tile;
private int tileSize = 75;
private int tileLayer = 5;
// Thread that controls animation for the BufferedDisplay
Thread animation;

public Game(C4Game game) {
    this.game = game;
    display = new BufferedDisplay();
    try {
        tile = ImageIO.read(new File("img\\tile.png"));
    } catch (IOException e) {
        System.out.println("ERROR: ");
        e.printStackTrace();
    }
    ((Component)display).setFocusable(true);
    add(display);
    animation = new Thread(display);
    animation.start();
    initBoard();
}

public void initBoard() {
    for(int x = 0; x<game.numRows()*tileSize; x+=tileSize) {
        for(int y = 0; y<game.numCols()*tileSize; y+=tileSize)  {
            System.out.println("Placing " +x +" " +y +"...");
            display.addImageStruct(new ImageStruct(tile, tileLayer, x, y, tileSize, tileSize));
        }
    }
}
}

...Which is then implemented in a JFrame.

public class TetraConnect extends JFrame{

    public TetraConnect() {
    super("TetraConnect", 800, 600);
    try {
        setIconImage(Toolkit.getDefaultToolkit().createImage("img/icon.png"));
        ms = new MainScreen(this);
        add(ms);
        ms.updateUI();
        C4Game c4g = new C4Game(5,6);
        Game g = new Game(c4g);
        add(g);
        g.updateUI();
    }
    catch(Exception e) {
        System.out.println("Init. Error: ");
        e.printStackTrace();
        System.exit(-1);
    }
}

The output when I run it, is:

Slept.
Sleeping... Slept.
Sleeping... Slept.
Sleeping... Slept.

And so forth. I'm also not able to see any images on the Canvas (I'm assuming they are never drawn in the first place). It seems to completely skip the repaint method; the debug statements "Updating... " and "Repainting... " never show up. However, repaint also seems to be executing; the loop repeats without problems. Why isn't the repaint method calling the paint() or update() methods?

4

2 回答 2

2

As @camickr noted in the comments, you are using the heavyweight AWT canvas. You should really be using lightweight Swing components. Instead of:

public class BufferedDisplay extends Canvas implements Runnable {

I recommend:

 public class BufferedDisplay extends JPanel implements Runnable {

Given that small change, I would then do the following:

When overriding the default paining of a component you should override the paintComponent() method.

So, instead of:

public void paint( Graphics g )
{

It should be:

protected void paintComponent( Graphics g )
{

That may fix your problem.

Also, you shouldn't have to override the update() method. Instead, just leave out a call to super.paintCompenent(g) in the paint component method. This should cause the background to be left alone by default.

于 2010-11-09T17:26:36.897 回答
1

Make sure that the BufferedDisplay object has been added to a container (e.g. a Frame), and that the container itself is visible. If the component is not showing, then calls to repaint() will not result in update() being called.

This is just generic advice. If you post a self-contained example that can be compiled and run it will probably be easier to find out what is wrong.

于 2010-11-09T18:22:05.910 回答