Java 调用paint()方法时图像闪烁
我得到了扩展JFrame的第一个类,它包含以下类Java 调用paint()方法时图像闪烁,java,swing,jframe,paint,bufferedimage,Java,Swing,Jframe,Paint,Bufferedimage,我得到了扩展JFrame的第一个类,它包含以下类 package Game; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.*; import Maps.*; public class Window extends JFrame implements KeyListener { private Insets inset
package Game;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
import Maps.*;
public class Window extends JFrame implements KeyListener
{
private Insets insets;
private int currentMapX;
private int currentMapY;
public Window()
{
super();
setSize(new Dimension(1920, 1080));
setLayout(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setUndecorated(true);
setFocusable(true);
setContentPane(new Container());
setBackground(Color.BLACK);
addKeyListener(this);
}
public void startGame()
{
insets = getInsets();
currentMapX = 960 - (Game.level_01.getWidth() / 2);
currentMapY = 540 - (Game.level_01.getHeight() / 2);
Game.level_01.setBounds(currentMapX, currentMapY, Game.level_01.getWidth(), Game.level_01.getHeight());
add(Game.level_01);
}
private void moveMapRight()
{
Game.level_01.setBounds(++currentMapX, currentMapY, Game.level_01.getWidth(), Game.level_01.getHeight());
}
private void moveMapLeft()
{
Game.level_01.setBounds(--currentMapX, currentMapY, Game.level_01.getWidth(), Game.level_01.getHeight());
}
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Game.player.paint(g2d);
}
public void keyPressed(KeyEvent k)
{
if(k.getKeyCode() == KeyEvent.VK_RIGHT) moveMapRight();
if(k.getKeyCode() == KeyEvent.VK_LEFT) moveMapLeft();
}
public void keyReleased(KeyEvent k){}
public void keyTyped(KeyEvent k){}
}
最后,这个类是播放器的类,即BuffereImage。我的问题是,当我启动程序时,播放器图像开始闪烁,因为当我在JFrame类中调用paint()方法时,它首先绘制jpanel,然后绘制播放器图像。如何解决图像闪烁问题?
提前谢谢
paint(Graphics)
,如JFrame
(非双缓冲)。而是在JPanel
中进行自定义绘制(该是双缓冲的)paint(Graphics)
,如JFrame
(非双缓冲)。而是在JPanel
中进行自定义绘制(该是双缓冲的)正如其他人所说,您不应该覆盖顶级组件中的
paint(Graphics g)
,因此这是问题的一部分,但您还需要小心确保每次重新绘制时只在屏幕上绘制一次:
我的问题是,当我启动程序时,播放器图像会启动
闪烁,因为当我在JFrame中调用paint()方法时
类,这将首先绘制jpanel,然后绘制播放器图像
现在的情况是,每次调用一个方法来修改绘制(图形屏幕)
方法中的图形
对象时,它都会直接修改屏幕内容,迫使屏幕在您完成绘制真正想要的东西之前刷新-播放器
。通过先绘制到super
,然后再次使用自定义渲染,实际上绘制到屏幕至少两次,从而导致闪烁。您可以通过双缓冲来解决这个问题
双缓冲首先渲染图像,然后将图像绘制到屏幕。使用组件
类提供的内置方法(请记住JPanel
扩展了组件
),您可以获得组件的可视区域的大小。创建一个大小相同的buffereImage
,然后调用buffereImage.createGraphics()
-这将为您提供一个Graphics2D
对象,您可以使用它在buffereImage
上绘制。渲染到bufferedImage
后,调用screen.drawImage(bufferedImage,0,0,null)
。这允许您在不进行屏幕刷新的情况下修改缓冲区图像
,然后在一次调用中将缓冲区的内容绘制到屏幕
其他信息
我应该在前面指出,我对屏幕上的实际布局一无所知,因此您可能需要对播放器屏幕区域的边界以及调用drawImage(Image,x,y,ImageObserver)
时左上角的位置进行一些额外的检查。还要注意buffereImage
中的透明度或缺乏透明度-如果在屏幕上的其他重要内容上绘制不透明像素,您很容易迷失方向
试试这个(但不要保留)
同样,我不建议您在顶级组件中进行所有绘制,但您可以在过渡期间尝试这样做:
package Player;
import java.awt.*;
import Game.*;
public class Player
{
private int x;
private int y;
private int xa;
private int ya;
private Graphics2D g2d;
public Player(double x, double y)
{
super();
this.x = (int)x;
this.y = (int)y;
xa = 0;
ya = 1;
}
public void movePlayer()
{
x += xa;
y += ya;
}
public void setDirection(int xa, int ya)
{
this.xa = xa;
this.ya = ya;
}
public void paint(Graphics g)
{
g2d = (Graphics2D)g;
g2d.drawImage(Game.playerImages[6], x , y, Game.tileSize, Game.tileSize, null);
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getXA()
{
return xa;
}
public int getYA()
{
return ya;
}
}
正如其他人所说,您不应该覆盖顶级组件中的
paint(Graphics g)
,因此这是问题的一部分,但您还需要小心确保每次重新绘制时只在屏幕上绘制一次:
我的问题是,当我启动程序时,播放器图像会启动
闪烁,因为当我在JFrame中调用paint()方法时
类,这将首先绘制jpanel,然后绘制播放器图像
现在的情况是,每次调用一个方法来修改绘制(图形屏幕)
方法中的图形
对象时,它都会直接修改屏幕内容,迫使屏幕在您完成绘制真正想要的东西之前刷新-播放器
。通过先绘制到super
,然后再次使用自定义渲染,实际上绘制到屏幕至少两次,从而导致闪烁。您可以通过双缓冲来解决这个问题
双缓冲首先渲染图像,然后将图像绘制到屏幕。使用组件
类提供的内置方法(请记住JPanel
扩展了组件
),您可以获得组件的可视区域的大小。创建一个大小相同的buffereImage
,然后调用buffereImage.createGraphics()
-这将为您提供一个Graphics2D
对象,您可以使用它在buffereImage
上绘制。渲染到bufferedImage
后,调用screen.drawImage(bufferedImage,0,0,null)
。这允许您在不进行屏幕刷新的情况下修改缓冲区图像
,然后在一次调用中将缓冲区的内容绘制到屏幕
其他信息
我应该在前面指出,我对屏幕上的实际布局一无所知,因此您可能需要对播放器屏幕区域的边界以及调用drawImage(Image,x,y,ImageObserver)
时左上角的位置进行一些额外的检查。A.
package Player;
import java.awt.*;
import Game.*;
public class Player
{
private int x;
private int y;
private int xa;
private int ya;
private Graphics2D g2d;
public Player(double x, double y)
{
super();
this.x = (int)x;
this.y = (int)y;
xa = 0;
ya = 1;
}
public void movePlayer()
{
x += xa;
y += ya;
}
public void setDirection(int xa, int ya)
{
this.xa = xa;
this.ya = ya;
}
public void paint(Graphics g)
{
g2d = (Graphics2D)g;
g2d.drawImage(Game.playerImages[6], x , y, Game.tileSize, Game.tileSize, null);
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getXA()
{
return xa;
}
public int getYA()
{
return ya;
}
}
//This is in the Window class:
public void paint(Graphics screen)
{
//Render everything first to a BufferedImage:
BufferedImage bufferedImage = ... //Initialize based on Window's
//size and bounds.
Graphics2D buf = bufferedImage.createGraphics();
super.paint(buf);
buf.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Game.player.paint(buf);
//Now paint the buffer to screen:
int x = ... //set to top-left x-coordinate, probably 0
int y = ... //set to top-left y-coordinate, probably 0
screen.drawImage(buf,x,y,null);
}