我的这段代码,为什么在主函数当中调用fun()函数,就能够达到我想要的效果,能一步一步显示出执行过程。
而当点击按钮时,同样是调用fun()函数,为什么就没有显示出执行过程呢???
具体执行请运行代码。
我觉得应该是repaint()函数内部执行原理不太了解。或者是那个Thread.sleep(1000)的问题???
总之,我是个初学者,请大家指教。
代码如下:public class Test extends JFrame implements ActionListener { public static void main(String[] args)
{
Test t = new Test();
t.fun();
System.out.println("End of Main");
} int    x, y;
Button but;

public Test() {
setBounds(400, 100, 350, 200);
this.setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
but = new Button("OK");
but.setSize(40, 40);
add(but);
but.addActionListener(this);
x = y = 50;
setVisible(true);
}
public void paint(Graphics g) {
System.out.println("call paint()");
super.paint(g);
g.fillOval(x, y, 9, 9);
}
public void fun() {
for (int i = 0; i < 5; i++) {
x += 20;
repaint();
try   { Thread.sleep(1000); }
catch (InterruptedException e) { e.printStackTrace(); }
}
}

public void actionPerformed(ActionEvent e) {
fun();
}
}

解决方案 »

  1.   

    你这个问题是典型的SWING线程同步模型的缘故,如果是事件触发的话,主界面没有来的及重绘界面导致的
      

  2.   

    简单一点理解就是Swing采用的是单线程模型,有个叫做事件分派线程,是和Swing组件进行交互的唯一的线程,像上面的绘制,处理按钮事件等都发生在这个线程;当点击按钮,处理按钮事件占用了Swing的事件分派线程工作,阻止它处理其它任务-像绘制,你以为应用死掉了,但实际上并不是这样,你等待一段时间后就会发现最后还是处理了绘制。你把repaint();
    改成下面的直接调用: Test.this.paint(Test.this.getGraphics());但在绘制完成前,是不会相应其他事件的。
      

  3.   


    为什么改成paint()就没有以前的毛病了呢???
    改成这样后,在执行按钮事件时,不响应其他事件,这个有其他的解决办法吗??望指点,谢谢!
      

  4.   

    上面说了啊,你可以理解为把绘制工作从事件分派线程拿出来了;使用线程机制。不过编写多线程Swing程序,也是个很头疼的问题,想深入的话,自己慢慢去学习。示例:import java.awt.Button;
    import java.awt.Component;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.geom.Ellipse2D;import javax.swing.JFrame;public class Test extends JFrame implements ActionListener {    public static void main(String[] args)
        {
            new Test();
        }    
        Button but;
        Oval ovalShap ;
        
        public Test() {
         ovalShap = new Oval();
            setBounds(400, 100, 350, 200);
            this.setLayout(null);
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            but = new Button("OK");
            but.setSize(40, 40);
            add(but);
            but.addActionListener(this);
            setVisible(true);
            fun();
        }
        public void paint(Graphics g) {
            super.paint(g);
            ((Graphics2D)g).fill(ovalShap.getShape());
        } public void fun() {
    ovalShap = new Oval();
    new Thread(new OvalRunnable(ovalShap, this)).start();
    }
        
        public void actionPerformed(ActionEvent e) {
         fun();
        }
    }class Oval{
    double x = 50, y = 50;

    public void move(){
    x += 20;
    }

    public Ellipse2D getShape(){
    return new Ellipse2D.Double(x, y, 9, 9);
    }
    }class OvalRunnable implements Runnable{
    Oval ovalShap ;
    Component comp;

    public OvalRunnable(Oval ovalShap, Component comp){
    this.ovalShap = ovalShap;
    this.comp = comp;
    }

    public void run() {
    for (int i = 0; i < 5; i++) {
    ovalShap.move();
    comp.repaint();
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }
      

  5.   

    public class Test extends JFrame implements ActionListener {    public static void main(String[] args)
        {
            Test t = new Test();
            t.fun();
            System.out.println("End of Main");
            for (int i=0; i<100; i++) { //主线程循环测试,看看主线程是否影响Swing线程
                System.out.println("main" + i);
                try {Thread.sleep(1000);} catch (Exception e) {}
            }
        }    int    x, y;
        Button but;
        
        public Test() {
            setBounds(400, 100, 350, 200);
            this.setLayout(null);
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            but = new Button("OK");
            but.setSize(40, 40);
            add(but);
            but.addActionListener(this);
            x = y = 50;
            setVisible(true);
        }
        public void paint(Graphics g) {
            System.out.println("call paint()");
            super.paint(g);
            g.fillOval(x, y, 9, 9);
        }
        public void fun() {
            for (int i = 0; i < 5; i++) {
                x += 20;
                repaint();
                try   { Thread.sleep(1000); }
                catch (InterruptedException e) { e.printStackTrace(); }
            }
        }
        
        public void actionPerformed(ActionEvent e) {
            new Thread() { //用线程来执行,看看该线程是否影响Swing线程
                public void run() {
                    fun();
                }
            }.start();
        }
    }
    原因2L已经说了
    repaint是发送一条消息到消息队列中,消息处理线程会处理该消息,它的内部会调用paint方法,而消息处理必须处理一条消息结束以后才会取下一条消息进行处理,这样,它在处理按钮事件消息的时候,就没法及时处理repaint消息,而当它处理完按钮事件以后再处理repaint消息的时候,因为repaint事件很短促,所有肉眼看不到中间的变化,只能看到最后一个repaint,所以也就看不见执行过程
    而直接调用paint方法,并不需要发送消息,也就是说当前线程自己处理paint方法,所有没有发生延时,可以看到执行过程
    所以,可以改用一个别的线程来执行run方法,这样按钮事件就可以立即返回,也就是按钮事件不用做sleep处理,很快就结束了,这样消息处理线程就可以有空处理线程发送的repaint消息,而线程是每sleep1秒才发送一个repaint消息,这样消息处理线程处理repaint消息中间就有事件间隙,所以可以看到每一次repaint的效果,也就是可能看到执行过程