停止重绘图形

时间:2012-10-31 23:19:27

标签: java swing graphics paint repaint

我完全陷入了一个问题,我正在使用这个程序,我必须画一个带摇摆的城市。基本上我正在尝试做的是让窗户不会改变每一帧。我已经尝试了我能想到的一切,但还没有任何工作。

这是绘制所有内容的主要类

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 个答案:

答案 0 :(得分:3)

很多事情立即向我跳出来......

您正在尝试使用屏幕外缓冲区,但每次刷到屏幕时都会重新创建它...

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

此外,该方法的最后一次调用是repaint。这是一个坏主意。这可能导致您paint方法一次又一次地被召回......

只有在需要更改后才能渲染后备缓冲区...

public void paint(Graphics g)
{
    super.paint(g); // YOU MUST CALL super.paint!!!!  

    //Clear the buffer
    Dimension d = getSize();
    checkOffscreenImage();

    //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);
        Graphics offG = mImage.getGraphics();
        offG.setColor(getBackground());
        offG.fillRect(0, 0, d.width, d.height);

        //Save frame to buffer
        paintOffscreen(offG);
        offG.dispose(); // If you create it, you must dispose of it...
    }
}

现在,这会引起缓冲区无效的一些问题。这可以通过覆盖invalidate并将mImage设置为null

来实现
public void invalidate() {  
    mImage = null;
    super.invalidate();
}

您正在从JFrame ???

扩展大部分组件

BuildingWindowBackground没有自己的绘画(来自Swing的内容),您只是调用draw方法。没有必要从JFrameJApplet延伸,它们不会给您的计划带来任何好处,只会让问题混乱。

您应该(很少)需要覆盖paint等顶级容器上的JFrame。最好使用JPanel之类的东西并覆盖paintComponent方法,如果没有其他原因,它们(顶级容器)不是双缓冲的。

我会将Skyline的逻辑移到JPanel,然后将其添加到JFrame进行显示 - 恕我直言

<强>已更新

我已经完成了代码并更新了它以我认为应该的(基本)方式工作,并在此过程中发现了其他一些事情......

这是个坏主意......

    public void mouseMoved(MouseEvent me) {
        Graphics g = getGraphics();
        mX = (int) me.getPoint().getX();
        mY = (int) me.getPoint().getY();
        update(g);
        //repaint();
    }

永远不需要你拨打update(Graphics),此外,你获得的Graphics上下文只是最后一次重绘的快照。这会以任何方式大大减慢您的绘画过程,因为它反复调用paint

所以,这是我的看法......

public class Skyline extends JFrame {

    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 static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                Skyline f = new Skyline();

                f.setSize(1017, 661); //Sets size of window
                f.setTitle("Skyline"); //Sets title of window
                f.setVisible(true);
            }
        });
    }

    public Skyline() {
        setLayout(new BorderLayout());
        add(new SkyLinePane());
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    public class SkyLinePane extends JPanel {

        private Image mImage; //Image buffer
        private boolean painting = false;

        private int mX, mY; //Mouse cooddinates

        public SkyLinePane() {
            addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent me) {
                    mX = (int) me.getPoint().getX();
                    mY = (int) me.getPoint().getY();
                    repaint();
                }
            });

        }

        protected void updateBuffer() {
            if (!painting && mImage == null) {
                painting = true;
                new BackgroundPainter(this).execute();
            }
        }

        //====================================BUFFER CODE========================================
        @Override
        public void paintComponent(Graphics g) {
            Dimension d = getSize();
            if (mImage != null) {
                g.drawImage(mImage, 0, 0, null);
            } else {
                updateBuffer();
            }
            g.setColor(Color.RED);
            g.drawOval(mX - 5, mY - 5, 10, 10);
        }
        //=======================================================================================

        protected void setBackground(Image image) {
            mImage = image;
            painting = false;
            repaint();
        }
    }

    public class BackgroundPainter extends SwingWorker<Image, Image> {

        private SkyLinePane skyLinePane;

        public BackgroundPainter(SkyLinePane skyLinePane) {
            this.skyLinePane = skyLinePane;
        }

        @Override
        protected Image doInBackground() throws Exception {
            Dimension d = skyLinePane.getSize();

            Image backgroundBuffer = null;
            if (d.width > 0 && d.height > 0) {

                System.out.println("Paint offscreen...");
                backgroundBuffer = createImage(d.width, d.height);
                Graphics offG = backgroundBuffer.getGraphics();
                offG.setColor(getBackground());
                offG.fillRect(0, 0, d.width, d.height);

                //Save frame to buffer
                paintOffscreen(offG);

                offG.dispose();
                System.out.println("Done Paint offscreen...");

            }

            return backgroundBuffer;
        }

        @Override
        protected void done() {
            try {
                skyLinePane.setBackground(get());
            } catch (ExecutionException exp) {
                exp.printStackTrace();
            } catch (InterruptedException exp) {
                exp.printStackTrace();
            }
        }

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

    //=======================================================================================
    public class Windows {

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

    public class Building {

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

    public class Background {

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

基本上,我将天窗的核心渲染移动到了自己的面板,并使用JComponent#paintComponent渲染天际线。

我使用SwingWorker将后备缓冲区的渲染卸载到另一个线程,允许UI在渲染后备缓冲区时保持响应。