【问题标题】:java drawing on JPanel with timer/delayjava在JPanel上用定时器/延迟绘图
【发布时间】:2011-11-15 14:37:11
【问题描述】:

我正在尝试制作一个小的马赛克程序,它会在 JPanel 上随机绘制正方形。我想做到这一点,它每 0,2 秒 1 平方绘制一次(不是一次全部绘制),但到目前为止,我只能使用 while 循环一次绘制全部。我尝试过使用 ActionListener 和 Timer,但我发现我无法将相同的 Graphics g 传递给 ActionListener。然后我尝试了 Thread.Sleep(200) 但应用程序冻结了。现在我尝试了 System.currentTimeMillis();但它与 Threads 相同...在整个互联网上搜索但没有找到任何有效的方法。

主要:

import javax.swing.JApplet;


public class Main extends JApplet{
public void init(){
    setSize(500, 300);
    Mosaic mosaic = new Mosaic();

    setContentPane(mosaic);

}
}

应用:

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JPanel;

public class Mosaic extends JPanel{

private int width, height;
private int ruut; // square 
private int w = width / 2, h = height / 2; // middle of the app 

Random rand = new Random();
Color color;

public Mosaic(){
    this(500, 300, 10);     
}

public Mosaic(int width, int height, int ruut){
    this.width = width;
    this.height = height;
    this.ruut = ruut;       
    setBackground(Color.BLACK);     
}

public void paintComponent(Graphics g){
    super.paintComponent(g);    
    //draws random squares
    while (true) {
        moveNext(g);
        wait(200);
    }
}

//delay n millisec
public void wait(int n){
    long t0, t1;
    t0 = System.currentTimeMillis();

    do {
        t1 = System.currentTimeMillis();            
    } while ((t1 - t0) < n);
}   

//next square
public void moveNext(Graphics g){       

    int r = rand.nextInt(4);        

    switch (r) {
    case 1:
        h += ruut;
        wallTest();
        break;
    case 2:
        h -= ruut;
        wallTest();
        break;
    case 3:
        w -= ruut;
        wallTest();
        break;
    case 4:
        w -= ruut;
        wallTest();
        break;
    }

    color = new Color(0, rand.nextInt(255-50)+50, 0);
    g.setColor(color);
    g.fillRect(w, h, ruut, ruut);       
}

public void wallTest(){
    if (h > height){
        h = 0;
    }
    if (h < 0){
        h = height;
    }
    if (w > width){
        w = 0;
    }
    if (w < 0){
        w = width;
    }
}   

}

【问题讨论】:

    标签: java swing graphics applet


    【解决方案1】:

    您需要维护一个屏幕外缓冲区,并在计时器事件的控制下将图块绘制到该缓冲区中。

    然后paintComponent 只需将该缓冲区复制到屏幕上。

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.util.Random;
    
    import javax.swing.JPanel;
    import javax.swing.Timer;
    
    public class Mosaic extends JPanel{
    
        private int width, height;
        private int ruut; // square 
        private int w = width / 2, h = height / 2; // middle of the app 
        private BufferedImage buffer;
    
        Random rand = new Random();
        Color color;
    
        public Mosaic(){
            this(500, 300, 10);     
        }
    
        public Mosaic(int width, int height, int ruut){
            this.width = width;
            this.height = height;
            this.ruut = ruut;
            this.buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            setBackground(Color.BLACK); 
            setPreferredSize(new Dimension(width, height));
            setDoubleBuffered(false);
            new Timer(200, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    moveNext(buffer.getGraphics());
                }
            }).start();
        }
    
        public void paintComponent(Graphics g){
            super.paintComponent(g);
            g.drawImage(buffer, 0, 0, this);
        }
    
        //next square
        public void moveNext(Graphics g){       
    
            int r = rand.nextInt(4);        
    
            switch (r) {
            case 1:
                h += ruut;
                wallTest();
                break;
            case 2:
                h -= ruut;
                wallTest();
                break;
            case 3:
                w -= ruut;
                wallTest();
                break;
            case 4:
                w -= ruut;
                wallTest();
                break;
            }
    
            color = new Color(0, rand.nextInt(255-50)+50, 0);
            g.setColor(color);
            g.fillRect(w, h, ruut, ruut);
            repaint();
        }
    
        public void wallTest(){
            if (h > height){
                h = 0;
            }
            if (h < 0){
                h = height;
            }
            if (w > width){
                w = 0;
            }
            if (w < 0){
                w = width;
            }
        }   
    }
    

    【讨论】:

    • 非常感谢,我还没有阅读有关缓冲区的内容,但现在我知道它很有用,并且会研究一下 :)
    • 如果使用BufferedImage,则无需覆盖paintComponent(Graphics)。图像可以显示在JLabel 中。如果图像被用作面板的背景,这将不起作用,但在这种情况下似乎并非如此。
    【解决方案2】:

    javax.swing.Timer 类与覆盖paintComponent 方法结合使用。您希望在 EDT 中执行长时间运行的任务,因为这会导致 GUI 冻结。

    示例 -

    new javax.swing.Timer(DELAY_IN_MILLIS, new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e){
            // do stuff
            repaint();
        }
    });
    

    【讨论】:

    • 我如何将图形 g 传递给 actionPerformed() 而不会重绘();只是把过去的所有画都涂一遍,我的意思是从 0 格开始?
    • @Slavak,修改paintComponent方法中的Graphics对象。修改计时器后台线程中用于Graphics 对象的任何因素。
    • 您需要在调用paint 时再次绘制整个区域,但每次都会绘制不同的图形(根据您的实现)。可以优化并只绘制特定区域,但可能有点复杂。
    • @AKJ,是的..使用setClip或指定坐标的重载repaint方法。
    • 别忘了start()计时器
    【解决方案3】:

    我尝试过使用 ActionListener 和 Timer,但我发现我无法将相同的 Graphics g 传递给 ActionListener。

    当然不是,Graphics 对象是暂时的。取而代之的是:

    1. 向可展开列表添加一个矩形并调用repaint()(在循环中),一次绘制列表中的每个对象。
    2. BufferedImage 放入JLabel 并在BufferedImage 中添加“一次一个矩形”。

    【讨论】:

      【解决方案4】:

      您可以使用计时器方法,因为这是不冻结应用程序的唯一方法。您可以在计时器触发时调用 repaint 或其他等效方法,然后根据要求在 paint 方法中进行绘制。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多