Ява рисунок на JPanel с таймером / задержкой - PullRequest
2 голосов
/ 15 ноября 2011

Я пытаюсь создать небольшую программу Mosaic, которая случайным образом рисует квадраты по всей JPanel.Я хочу сделать так, чтобы он рисовал каждые 0,2 с 1 квадрат (не все сразу), но пока я могу сделать только один, чтобы рисовать все сразу с помощью цикла while.Я пытался с ActionListener и Timer, но я обнаружил, что я не могу передать ту же графику g в ActionListener.Затем я попытался с Thread.Sleep (200), но затем приложение застыло.Теперь я попытался с System.currentTimeMillis ();но это так же, как с потоками ... Поиск по всему Интернету, но не нашел ничего, что работает.

Main:

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 ]

2 голосов
/ 15 ноября 2011

Вам необходимо поддерживать внеэкранный буфер и рисовать тайлы в этом буфере под контролем событий таймера.

Затем 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;
        }
    }   
}
2 голосов
/ 15 ноября 2011

Я пробовал использовать ActionListener и Timer, но я обнаружил, что не могу передать ту же графику g в ActionListener.

Конечно, нет, объект Graphics является временным. Вместо этого либо выполните одно из:

  1. Добавьте прямоугольник в расширяемый список и вызовите repaint() (в цикле), рисуя каждый объект в списке сразу.
  2. Поместите BufferedImage в JLabel и добавьте «прямоугольник за раз» к BufferedImage.
2 голосов
/ 15 ноября 2011

Используйте класс javax.swing.Timer в сочетании с переопределением метода paintComponent. Вы не хотите выполнять долгосрочные задачи в EDT, поскольку это приведет к зависанию графического интерфейса.

Пример -

new javax.swing.Timer(DELAY_IN_MILLIS, new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e){
        // do stuff
        repaint();
    }
});
1 голос
/ 15 ноября 2011

Вы можете использовать подход с таймером, так как это единственный способ не заморозить приложение. Вы можете вызвать repaint или другой эквивалентный метод при срабатывании таймера, а затем в методе рисования рисовать согласно требованиям.

...