有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

带计时器/延迟的JPanel上的swing java绘图

我正在尝试制作一个小的马赛克程序,在整个JPanel中随机绘制正方形。我想让它每0,2秒画一个正方形(不是一次画完),但到目前为止,我只能用while循环一次画完。我尝试过ActionListener和Timer,但我发现,我无法将相同的图形g传递给ActionListener。然后我试着用线。睡眠(200),但随后应用程序冻结。现在我已经试过了。currentTimeMillis();但它和线程一样。。。搜索了整个互联网,但没有找到任何有效的

主要内容:

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

}


共 (4) 个答案

  1. # 1 楼答案

    你可以使用定时器方法,因为这是唯一不冻结应用程序的方法。当定时器触发时,您可以调用repaint或某些等效方法,然后在paint方法中根据需要绘制

  2. # 2 楼答案

    I have tried with ActionListener and Timer, but i found out, that i cant pass the same Graphics g to ActionListener.

    当然不是,Graphics对象是暂时的。相反,请执行以下任一操作:

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

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

    然后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;
            }
        }   
    }
    
  4. # 4 楼答案

    ^{}类与重写paintComponent方法结合使用。您不希望在EDT中执行长时间运行的任务,因为这将导致GUI冻结

    范例-

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