java阻止某些图形重新绘制
我完全陷入了这个程序的一个问题,我必须用swing画一个城市。基本上,我想做的是使它的窗口不会改变每一帧。我已经尝试了我所能想到的一切,但没有任何效果
这里是绘制所有内容的主类
import java.applet.Applet;
import java.awt.*;
import java.util.*;
import javax.swing.JFrame;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class Skyline extends JFrame implements MouseMotionListener
{
private int mX, mY; //Mouse cooddinates
private Image mImage; //Image buffer
//private Image mImage2; //Image buffer
private int num = 0;
private Building bldg1 = new Building(305, 110, 30);
private Building bldg2 = new Building(380, 125, 170);
private Building bldg3 = new Building(245, 200, 325);
private Building bldg4 = new Building(470, 170, 555);
private Building bldg5 = new Building(395, 200, 755);
private Background bg = new Background();
public void init ()
{
}
public static void main(String []args)
{
Skyline f = new Skyline();
f.setSize(1017, 661); //Sets size of window
f.setTitle("Skyline"); //Sets title of window
f.show();
}
public void paintOffscreen(Graphics page)
{
//Draws the background
bg.draw(page);
//Moving square
num++;
if (num > 1200)
num = 0;
page.setColor(Color.yellow);
page.fillRect(num,100,100,100);
//Draws the buildings
bldg1.draw(page);
bldg2.draw(page);
bldg3.draw(page);
bldg4.draw(page);
bldg5.draw(page);
//Mouse move square
int s = 100;
page.setColor(Color.yellow);
page.fillRect(mX - s / 2, mY - s / 2, s, s);
repaint();
}
//====================================BUFFER CODE========================================
public void paint(Graphics g)
{
//Clear the buffer
Dimension d = getSize();
checkOffscreenImage();
Graphics offG = mImage.getGraphics();
offG.setColor(getBackground());
offG.fillRect(0, 0, d.width, d.height);
//Save frame to buffer
paintOffscreen(mImage.getGraphics());
//Draw the buffer
g.drawImage(mImage, 0, 0, null);
}
private void checkOffscreenImage()
{
Dimension d = getSize();
if (mImage == null || mImage.getWidth(null) != d.width || mImage.getHeight(null) != d.height)
mImage = createImage(d.width, d.height);
}
//=======================================================================================
//==================================MOUSE MOVE CODE======================================
public Skyline()
{
addMouseMotionListener(this);
setVisible(true);
}
public void mouseMoved(MouseEvent me)
{
Graphics g = getGraphics();
mX = (int) me.getPoint().getX();
mY = (int) me.getPoint().getY();
update(g);
//repaint();
}
public void mouseDragged(MouseEvent me)
{
mouseMoved(me);
}
//=======================================================================================
}
这是一个窗口类,它可能会以某种方式被修复
import java.applet.Applet;
import java.awt.*;
import java.util.Random;
import javax.swing.JFrame;
public class Windows extends JFrame
{
private Random gen = new Random();
private int height, width, locX;
private int onOff = 0;
public Windows()
{
height = 305;
width = 110;
locX = 30;
}
public Windows(int height, int width, int locX)
{
this.height = height;
this.width= width;
this.locX = locX;
}
public void draw(Graphics page)
{
page.setColor (Color.darkGray);
page.fillRect (locX, 550 - height, width, height);
for (int i = 550 - height + 5; i < 550; i += 15)
{
for (int x = locX + 5; x < locX + width; x += 15)
{
onOff = gen.nextInt(2);
if(onOff == 0)
page.setColor(Color.black);
else
page.setColor(Color.yellow);
page.fillRect (x,i,10,10);
}
}
}
}
这是建筑课以防万一
import java.applet.Applet;
import java.awt.*;
import javax.swing.JFrame;
public class Building extends JFrame
{
private int height, width, locX;
private int onOff;
private Windows windows1;// = new Windows(height, width, locX);
public Building()
{
height = 305;
width = 110;
locX = 30;
windows1 = new Windows(height, width, locX);
}
public Building(int height, int width, int locX)
{
this.width = width;
this.height = height;
this.locX = locX;
windows1 = new Windows(height, width, locX);
}
public void draw(Graphics page)
{
page.setColor (Color.darkGray);
page.fillRect (locX, 550 - height, width, height);
windows1.draw(page);
}
}
为了安全起见,还有bg班
import java.applet.Applet;
import java.awt.*;
public class Background extends Applet
{
private int height, width;
public Background()
{
height = 400;
width = 2000;
}
public Background(int height, int width)
{
this.height = height;
this.width = width;
}
public void draw(Graphics page)
{
//Draws the sky
page.setColor(Color.cyan);
page.fillRect(0,0,2000,2000);
//Draws the grass
page.setColor (Color.green);
page.fillRect (0,500,width,height);
}
}
# 1 楼答案
很多事情立刻向我袭来
您试图使用屏幕外缓冲区,但每次在屏幕上绘制时都会重新创建缓冲区
此外,该方法中的最后一个调用是
repaint
。这是个坏主意。这可能会导致paint
方法被一次又一次地调用您最好只在需要更改备份缓冲区时才渲染它
现在,这将引发一些关于使缓冲区无效的问题。这可以通过覆盖
invalidate
并将mImage
设置为null
来实现您正在从
JFrame
扩展大部分组件Building
、Window
和Background
没有自己的绘画(从Swing的内容来看),您只是调用draw
方法。没有必要从JFrame
或JApplet
扩展,它们没有给您的程序带来任何好处,只是混淆了问题在像
JFrame
这样的顶级容器上,您应该很少需要重写paint
。如果没有其他原因,它们(顶级容器)不是双缓冲的,那么最好使用JPanel
之类的方法并重写paintComponent
方法我会将
Skyline
的逻辑移到JPanel
中,然后将其添加到JFrame
中以显示-IMHO更新
我已经阅读了代码,并按照我认为应该的(基本)方式对其进行了更新,同时还发现了其他一些东西
这是个坏主意
你永远不需要调用
update(Graphics)
,此外,你得到的Graphics
上下文只是最后一次重新绘制的快照。这会以任何方式大大减慢绘制过程,因为它会反复调用paint
所以,这是我的看法
基本上,我将天际线的核心渲染移到了它自己的面板上,并使用
JComponent#paintComponent
来渲染天际线我使用了一个
SwingWorker
将备份缓冲区的呈现卸载到另一个线程,允许UI在呈现备份缓冲区时保持响应