repaint,paint在事件分配上的区别

来源:互联网 发布:屏幕解锁软件 编辑:程序博客网 时间:2024/05/01 05:56

首先看两段类似的程序

单线程的

/**
 * @(#)Bounce.java
 *
 *
 * 
@author livahu
 * 
@version 1.00 2006/10/16
 
*/

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;

public class Bounce {

    
public Bounce() {
    }

    
    
public static void main(String[] args) {
        JFrame frame 
= new BounceFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(
true);
    }

}


class Ball {
    
private static final int XSIZE = 15;
    
private static final int YSIZE = 15;
    
private double x = 0;
    
private double y = 0;
    
private double dx = 1;
    
private double dy = 1;
        
    
public void move(Rectangle2D bounds) {
        x 
+= dx;
        y 
+= dy;
        
if (x < bounds.getMinX()) {
            x 
= bounds.getMinX();
            dx 
= -dx;
        }

        
        
if (x + XSIZE >= bounds.getMaxX()) {
            x 
= bounds.getMaxX() - XSIZE;
            dx 
= -dx;
        }

        
        
if (y < bounds.getMinY()) {
            y 
= bounds.getMinY();
            dy 
= -dy;
        }

        
        
if (y + YSIZE >= bounds.getMaxY()) {
            y 
= bounds.getMaxY() - YSIZE;
            dy 
= -dy;
        }

    }

    
    
public Ellipse2D getShape() {
        
return new  Ellipse2D.Double(x, y, XSIZE, YSIZE);
    }

}


class BallPanel extends JPanel {
    
private ArrayList<Ball> balls = new ArrayList<Ball>();
    
    
public void add(Ball b) {
        balls.add(b);
    }

    
    
public void remove(Ball b) {
        balls.remove(b);
    }

    
    
public void paintComponent(Graphics g) {
        
super.paintComponent(g);
        Graphics2D g2 
= (Graphics2D)g;
        
for (Ball b : balls) {
            g2.fill(b.getShape());
        }

    }

}


class BounceFrame extends JFrame {
    
private BallPanel panel;
    
public static final int DEFAULT_WIDTH = 450;
    
public static final int DEFAULT_HEIGHT = 350;
    
public static final int STEPS = 1000;
    
public static final int DELAY = 3;
    
    
public BounceFrame() {
        setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        setTitle(
"Bounce");
        
        panel 
= new BallPanel();
        add(panel, BorderLayout.CENTER);
        JPanel buttonPanel 
= new JPanel();
        addButton(buttonPanel, 
"Start"
            
new ActionListener() {
                
public void actionPerformed(ActionEvent event) {
                    addBall();
                }

            }
);
        addButton(buttonPanel, 
"Close"
            
new ActionListener() {
                
public void actionPerformed(ActionEvent event) {
                    System.exit(
0);
                }

            }
);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    
    
public void addButton(Container c, String title, ActionListener listener) {
        JButton button 
= new JButton(title);
        c.add(button);
        button.addActionListener(listener);
    }

    
    
public void addBall() {
        
try {
            Ball ball 
= new Ball();
            panel.add(ball);
            
            
for (int i  = 1; i <= STEPS; i++{
                ball.move(panel.getBounds());
                panel.paint(panel.getGraphics());
            
//    panel.repaint(); 为什么不能使用repaint?使用repaint屏幕上没有任何球。repaint 和 paint有什么区别与关系
                Thread.sleep(DELAY);
            }

            panel.remove(ball);
        }
 catch(InterruptedException ex) {
            
        }

    }

}

 多线程的

 

/**
 * @(#)Bounce.java
 *
 *
 * 
@author livahu
 * 
@version 1.00 2006/10/16
 
*/

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;

public class BounceThread {

    
public BounceThread() {
    }

    
    
public static void main(String[] args) {
        JFrame frame 
= new BounceFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(
true);
    }

}


class BallRunnable implements Runnable {
    
private Ball ball;
    
private BallPanel panel;
    
public static final int STEPS = 1000;
    
public static final int DELAY = 5;
    
    
public BallRunnable(Ball aBall, BallPanel panel) {
        ball 
= aBall;
        
this.panel = panel;
    }

    
    
public void run() {
        
try {
            
for (int i = 1; i <= STEPS; i++{
                ball.move(panel.getBounds());
                panel.repaint();
//这里又可以用repaint
                Thread.sleep(DELAY);
            }

            panel.remove(ball);
            
        }
 catch(InterruptedException ex)  {
        }

    }

}

            

class Ball {
    
private static final int XSIZE = 15;
    
private static final int YSIZE = 15;
    
private double x = 0;
    
private double y = 0;
    
private double dx = 1;
    
private double dy = 1;
        
    
public void move(Rectangle2D bounds) {
        x 
+= dx;
        y 
+= dy;
        
if (x < bounds.getMinX()) {
            x 
= bounds.getMinX();
            dx 
= -dx;
        }

        
        
if (x + XSIZE >= bounds.getMaxX()) {
            x 
= bounds.getMaxX() - XSIZE;
            dx 
= -dx;
        }

        
        
if (y < bounds.getMinY()) {
            y 
= bounds.getMinY();
            dy 
= -dy;
        }

        
        
if (y + YSIZE >= bounds.getMaxY()) {
            y 
= bounds.getMaxY() - YSIZE;
            dy 
= -dy;
        }

    }

    
    
public Ellipse2D getShape() {
        
return new  Ellipse2D.Double(x, y, XSIZE, YSIZE);
    }

}


class BallPanel extends JPanel {
    
private ArrayList<Ball> balls = new ArrayList<Ball>();
    
    
public void add(Ball b) {
        balls.add(b);
    }

    
    
public void remove(Ball b) {
        balls.remove(b);
    }

    
    
public void paintComponent(Graphics g) {
        
super.paintComponent(g);
        Graphics2D g2 
= (Graphics2D)g;
        
for (Ball b : balls) {
            g2.fill(b.getShape());
        }

    }

}


class BounceFrame extends JFrame {
    
private BallPanel panel;
    
public static final int DEFAULT_WIDTH = 450;
    
public static final int DEFAULT_HEIGHT = 350;
    
public static final int STEPS = 1000;
    
public static final int DELAY = 3;
    
    
public BounceFrame() {
        setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        setTitle(
"Bounce");
        
        panel 
= new BallPanel();
        add(panel, BorderLayout.CENTER);
        JPanel buttonPanel 
= new JPanel();
        addButton(buttonPanel, 
"Start"
            
new ActionListener() {
                
public void actionPerformed(ActionEvent event) {
                    addBall();
                }

            }
);
        addButton(buttonPanel, 
"Close"
            
new ActionListener() {
                
public void actionPerformed(ActionEvent event) {
                    System.exit(
0);
                }

            }
);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    
    
public void addButton(Container c, String title, ActionListener listener) {
        JButton button 
= new JButton(title);
        c.add(button);
        button.addActionListener(listener);
    }

    
    
public void addBall() {
        Ball b 
= new Ball();
        panel.add(b);
        Runnable r 
= new BallRunnable(b, panel);
        Thread t 
= new Thread(r);
        t.start();
        
    }

}

从这两段程序,不难发现,本因调用repaint的单线程程序无法重绘图象,但在多线程里就没有一点问题。那repaint和paint在线程上有什么区别类?我想了很久,最后感谢zxyxc的帮助,让我知道了事件分配的一些细节。

是这样的:Java中事件的分配调度是由专门的线程完成的。当调用repaint方法时,实际上是发送一个重绘事件到事件队列,而后事件分配线程会调用paint方法来完成重绘。当在多线程时,一切正常,因为是调用的repaint方法的线程没有占据全部的CPU时间,所以事件分配线程可以执行,并调用paint完成重绘。
    而在单线程情况下,由于主线程完全占据了CPU,事件分配线程无法执行,自然也就没办法去分配通过调用repaint方法插入的重绘事件。取代的做法就是直接调用paint(),而不是等待事件分配线程去调用。