java jpanel如何优化绘画

时间:2017-07-05 15:25:07

标签: java swing optimization jpanel paintcomponent

我正在尝试实施langton的蚂蚁,我做得很好: langton's ant java simulation screen

在我的jPanel中绘画,我在每一步都覆盖了paintComponent,但是它需要花费很多时间来绘制每个黑色或白色矩形,我只想在每一步我只绘制两个已经改变的矩形!? 所以我的问题是,如何只绘制一个矩形而不改变前一帧中绘制的内容?

这是我的绘画代码

public void paintComponent(Graphics g){ 
        g.setColor(Color.white);
        g.fillRect(0,0,getWidth(),getHeight());
        g.setColor(Color.black);
        int careLargeur = getWidth() / m;
        int careHauteur = getHeight() / n;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++){
                if(map[i][j]) 
                    g.fillRect(j*careLargeur,i*careHauteur,careLargeur,careHauteur);
            }
        //draw fourmi
        g.setColor(Color.red);
        g.fillOval(jF*careLargeur, iF*careHauteur, careLargeur, careHauteur);
    }

任何帮助?或者我应该提供更多细节? 这是罐子:

1 个答案:

答案 0 :(得分:1)

将矩形绘制到BufferedImage,然后在paintComponent方法中绘制BufferedImage。您还可以使用指定要重新绘制的确切矩形区域的repaint(...)覆盖之一来限制重绘的数量。

所以你的paintComponent方法可以这么简单:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (img != null) {
        g.drawImage(img, 0, 0, this);
    }
    g.setColor(Color.red);
    g.fillOval(jF*careLargeur, iF*careHauteur, careLargeur, careHauteur);
}

img BufferedImage进行绘图更改。

假设您使用Swing Timer来驱动模型的状态更改,您可以

  1. 更改模型,然后
  2. 根据模型更改更新BufferedImage,
  3. 仅在更新后的区域调用repaint(...)
  4. 代码尝试不完整......尚未完成!

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    
    import javax.swing.*;
    import javax.swing.event.SwingPropertyChangeSupport;
    
    /**
     * https://en.wikipedia.org/wiki/Langton%27s_ant
     * https://stackoverflow.com/a/44930371/522444
     * @author Pete
     *
     */
    public class LangtonsAnt {
    
        private static final int TIMER_DELAY = 30;
    
        private static void createAndShowGui() {
            Model model = new Model(800);
            View view = new View(800);
            Controller controller = new Controller(model, view);
    
            JFrame frame = new JFrame("Langtons Ant");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(view);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
    
            controller.startTimer(TIMER_DELAY);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    
        private static class Model {
            public static final String POINT = "point";
            private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
            private int gridSize;
            private boolean[][] grid; // false is white. Better to use enums
            private Point oldValue;
            private Point point; // ant location
    
            public Model(int gridSize) {
                this.gridSize = gridSize;
                grid = new boolean[gridSize][gridSize];
                int x = gridSize / 2;
                int y = gridSize / 2;
                setPoint(new Point(x, y));
            }
    
            public void setPoint(Point point) {
                this.oldValue = this.point;
                Point newValue = point;
                this.point = point;
                support.firePropertyChange(POINT, oldValue, newValue);
            }
    
            public Point getPoint() {
                return point;
            }
    
            public boolean[][] getGrid() {
                return grid;
            }
    
            public int getGridSize() {
                return gridSize;
            }
    
            public void step() {
                // first will hold relative new positions
                int newX = 0;
                int newY = 0;
                boolean gridPoint = getGridPoint(point);
                if (oldValue == null) {
                    newX = point.x;
                    newY = point.y - 1;
                } else {
                    int dX = point.x - oldValue.x;
                    int dY = point.y - oldValue.y;
                    if (dX != 0) {
                        // from left or right
                        newY = dX > 0 ? 1 : -1;  // assume "white" or false
                        newY = gridPoint ? -newY : newY;  // if "black" then reverse
                    } else {
                        // from up or down
                        newX = dY > 0 ? -1 : 1; // assume "white" or false
                        newX = gridPoint ? -newX : newX; // if "black" then reverse
                    }
    
                    // convert from relative to absolute new positions
                    newX = point.x + newX;
                    newY = point.y + newY;
                }
                setGridPoint(point, !gridPoint);
                setPoint(new Point(newX, newY));            
            }
    
            public boolean getGridPoint(int x, int y) {
                return grid[x][y];
            }
    
            public boolean getGridPoint(Point p) {
                return getGridPoint(p.x, p.y);
            }
    
            public void setGridPoint(int x, int y, boolean b) {
                grid[x][y] = b;
            }
    
            public void setGridPoint(Point p, boolean b) {
                setGridPoint(p.x, p.y, b);
            }
    
            public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
                support.addPropertyChangeListener(propertyName, l);
            }
        }
    
        private static class Controller {
    
            private Model model;
            private View view;
            private Timer timer;
    
            public Controller(Model model, View view) {
                this.model = model;
                this.view = view;
                view.setAntImg(createAntImg()); 
                model.addPropertyChangeListener(Model.POINT, new ModelListener());
            }
    
            private BufferedImage createAntImg() {
                // trivial image for now
                BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
                Graphics g = img.getGraphics();
                g.setColor(Color.RED);
                g.fillRect(0, 0, 1, 1);
                g.dispose();
                return img;
            }
    
            public void startTimer(int delay) {
                timer = new Timer(delay, new TimerListener());
            }
    
            private class TimerListener implements ActionListener {
                @Override
                public void actionPerformed(ActionEvent e) {
                    model.step();
                }
            }
    
            private class ModelListener implements PropertyChangeListener {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    // TODO Finish this.
                    // get the new point and old point
                    // translate model coord to view coord
                    // Change the state of the view's buffered image
                    // repaint the limited region that was changed
    
                }
            }
    
        }
    
        private static class View extends JPanel {
            private static final Color BACKGROUND = Color.WHITE;
            private BufferedImage gridImg;
            private BufferedImage antImg;
            private Point guiAntLocation;
            private int pixelWidth;
    
            public View(int pixelWidth) {
                this.pixelWidth = pixelWidth;
                gridImg = new BufferedImage(pixelWidth, pixelWidth, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2 = gridImg.createGraphics();
                g2.setColor(BACKGROUND);
                g2.fillRect(0, 0, pixelWidth, pixelWidth);
                g2.dispose();
            }
    
            public int getPixelWidth() {
                return pixelWidth;
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (getGridImg() != null) {
                    g.drawImage(getGridImg(), 0, 0, this);
                }
                if (guiAntLocation != null && antImg != null) {
                    int x = guiAntLocation.x;
                    int y = guiAntLocation.y;
                    g.drawImage(antImg, x, y, this);
                }
            }
    
            public void setGuiAntLocation(Point guiAntLocation) {
                this.guiAntLocation = guiAntLocation;
            }
    
            public Point getGuiAntLocation() {
                return guiAntLocation;
            }
    
            @Override
            public Dimension getPreferredSize() {
                if (isPreferredSizeSet() || getGridImg() == null) {
                    return super.getPreferredSize();
                }
                return new Dimension(getGridImg().getWidth(), getGridImg().getHeight());
            }
    
            public BufferedImage getGridImg() {
                return gridImg;
            }
    
            public void setGridImg(BufferedImage gridImg) {
                this.gridImg = gridImg;
            }
    
            public void setAntImg(BufferedImage antImg) {
                this.antImg = antImg;
            }
        }
    }