JPanel闪烁问题

时间:2015-12-02 01:21:58

标签: java swing jpanel

对于我的游戏,我绘制到java.awt.Image然后将图像绘制到JPanel上。我之所以这样做有几个原因,主要是因为我不希望游戏渲染在EDT上占用cpu周期,以及便携性。

使用

时出现导致java.awt.JPanel闪烁的问题
  

graphics#drawImage(Image img,int x,int y,int width,int height,   ImageObserver观察者)

然而,

  

graphics#drawImage(Image img,int x,int y,ImageObserver observer)

没有引起这个问题。

这是我的代码:

Sandbox.java

public class Sandbox implements Paintable {

public static void main(String[] args) throws Exception {
    GameWindow window = new GameWindow("Test", 800, 600);
    GameScreen screen = new GameScreen(800, 600);
    Sandbox sandbox = new Sandbox();

    window.add(screen);
    window.setVisible(true);

    boolean running = true;
    while(running) {
        sandbox.update();
        screen.getPaintBuffer().clear();
        screen.getPaintBuffer().paint(sandbox);
        screen.repaint();
        Thread.sleep(1000 / 60);
    }

}

private int x = 0, y = 0;

public void update() {
    x++;
    y++;
}

public void paint(Graphics g) {
    g.drawRect(x, y, 50, 50);
}

}

GameWindow.java

public class GameWindow extends JFrame {

public GameWindow(String title, int width, int height) {
    setTitle(title);
    setSize(width, height);
    setResizable(false);
    setLocationByPlatform(true);
    setDefaultCloseOperation(3);
}

}

GameScreen.java

public class GameScreen extends JPanel {

private ImageBuffer buffer;

public GameScreen(int width, int height) {
    buffer = new ImageBuffer(width, height);
}

public void paint(Graphics g) {
    g.drawImage(getPaintBuffer().getBuffer(), 0, 0, getWidth(), getHeight(), null);
}

public ImageBuffer getPaintBuffer() {
    return buffer;
}

}

Paintable.java

public interface Paintable {

public void paint(Graphics g);

}

ImageBuffer.java

public class ImageBuffer {

private final Image buffer;
private int width, height;

public ImageBuffer(int width, int height) {
    buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    this.width = width;
    this.height = height;
}

public void paint(Paintable paintable) {
    paintable.paint(buffer.getGraphics());
}

public void clear() {
    buffer.getGraphics().clearRect(0, 0, width, height);
}

public Image getBuffer() {
    return buffer;
}

}

1 个答案:

答案 0 :(得分:4)

GameScreen的{​​{1}}方法更改为...

  1. 改为覆盖paint
  2. 致电paintComponent以维持油漆连锁店的合约
  3. super.paintComponent作为this参数传递给ImageObsever
  4. 例如......

    drawImage

    请查看Painting in AWT and SwingPerforming Custom Painting,了解有关绘画如何运作的详细信息

    <强>更新

    基本问题是缩放问题......

    您用来绘制的图片是public class GameScreen extends JPanel { private ImageBuffer buffer; public GameScreen(int width, int height) { buffer = new ImageBuffer(width, height); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(getPaintBuffer().getBuffer(), 0, 0, getWidth(), getHeight(), this); } public ImageBuffer getPaintBuffer() { return buffer; } } ,但800x600实际上是GameScreen(在我的电脑上),这会导致图像缩放。现在,Swing的默认缩放比例并不高,一般都是基于速度而非质量。

    现在,有很多方法可以改善这一点,但快速的方法是应用一些更高的渲染提示,例如

    794x572

    现在,我已经过度使用了这个,所以你可能想删除一些,看看有什么变化

    <强>更新

    渲染提示可能会降低渲染过程的速度,因此更好的解决方案可能会覆盖@Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); g2d.drawImage(getPaintBuffer().getBuffer(), 0, 0, getWidth(), getHeight(), this); g2d.dispose(); } 的{​​{1}}方法并返回预期的大小

    getPreferredSize

    然后,而不是将大小传递给GameScreen,只需调用public static class GameScreen extends JPanel { private ImageBuffer buffer; private Dimension size; public GameScreen(int width, int height) { buffer = new ImageBuffer(width, height); this.size = new Dimension(width, height); } @Override public Dimension getPreferredSize() { return new Dimension(800, 600); }

    即可
    GameWindow

    这样,每个人都有相同的规模