【问题标题】:Why is the paint() method not executing update() or paint() methods?为什么paint() 方法不执行update() 或paint() 方法?
【发布时间】:2011-05-07 09:32:16
【问题描述】:

我遇到了这个问题,当我执行 repaint() 时,类中的 paint()update() 方法没有被调用。代码如下:

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

这个类是这样实现的:

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

...然后在 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);
    }
}

我运行它时的输出是:

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

等等。我也无法在画布上看到任何图像(我假设它们从一开始就没有被绘制)。似乎完全跳过了重绘方法;调试语句“正在更新...”和“重新绘制...”永远不会出现。但是,重绘似乎也在执行;循环重复没有问题。为什么 repaint 方法不调用 paint() 或 update() 方法?

【问题讨论】:

  • 你现在已经发布了很多代码,但是你的代码仍然不是“独立的”(没有人可以尝试编译和运行它),并且没有显示面板是如何添加到顶级容器(frmae)。我建议您尝试将其简化为一个独立的完整示例,但也尽可能简单。
  • 请使用@Override注解。
  • @Grodriguez 好的,我想我明白你现在在说什么了。很抱歉造成误解:x @Ishtar 为什么?我看不出有什么理由……这样做是个好习惯吗?
  • 混合轻量级组件(JFrame、JPanel)和重量级组件(Canvas)可能会让你有些头疼。我建议要么坚持使用 AWT 并仅使用重量级,要么完全转向 Swing 并仅使用轻量级。无论如何,我认为您的问题现在解决了吗?
  • @Grodriguez 是的,但是谢谢! :D

标签: java awt doublebuffered


【解决方案1】:

确保BufferedDisplay 对象已添加到容器(例如Frame),并且容器本身是可见的。如果组件未显示,则对 repaint() 的调用不会导致 update() 被调用。

这只是一般建议。如果您发布一个可以编译和运行的self-contained example,它可能会更容易找出问题所在。

【讨论】:

  • 但是,即使组件不可见,也不应该调用paint()吗?
  • 没有。如果组件不可见,则不会调用 paint() 以响应 repaint()(如果您检查 Component.repaint() 的源代码,则可以轻松检查这一点)
【解决方案2】:

正如@camickr 在 cmets 中指出的那样,您使用的是重量级 AWT 画布。你真的应该使用轻量级的 Swing 组件。而不是:

public class BufferedDisplay extends Canvas implements Runnable {

我推荐:

 public class BufferedDisplay extends JPanel implements Runnable {

鉴于这个小小的改变,我会做以下事情:

当覆盖组件的默认绘制时,您应该覆盖 paintComponent() 方法。

所以,而不是:

public void paint( Graphics g )
{

应该是:

protected void paintComponent( Graphics g )
{

这可能会解决您的问题。

此外,您不必重写 update() 方法。相反,只需在绘制组件方法中省略对super.paintCompenent(g) 的调用。这应该会导致背景默认保持不变。

【讨论】:

  • 您的建议对 Swing 组件有效。因此,您还需要添加使用 JPanel 而不是 Canvas 的建议。这也是我对海报的建议。使用 Swing 而不是 AWT。
  • @cam,我完全错过了 OP 正在使用Canvas。感谢您的评论。
  • 从 AWT 切换到 Swing 不会神奇地解决 OP 的问题。尽管在大多数情况下 Swing 可能是更好的选择,但他没有理由不能单独使用 AWT 完成他想做的事情。
  • :-) 我不想成为一个痛苦的人,但我认为你错过了我的观点。我要说的是你的回答不会解决他的问题即使他切换到 Swing,因为你提出的所有建议都是关于如何从“正确的 AWT 代码”到“正确的 Swing 代码” .但是 OP 的原始代码中显然存在一些问题(可能在他没有显示的部分),所以无论他是否遵循您的建议并切换到 Swing,这个问题很可能仍然存在。
  • @DDP,我看到您将BufferedPanel 放在JPanel 上。您不应该像那样混合 Swing 和 AWT 组件。我真的认为你会从使用 JPanel 而不是画布中受益。
猜你喜欢
  • 2014-10-28
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 2011-04-09
  • 2016-03-06
  • 2010-10-04
  • 1970-01-01
  • 2019-09-01
相关资源
最近更新 更多