Problemas com paintComponent e Runnable

5 respostas
J

Estava criando um metodo para verificar colisões. Eu desenho retangulos na tela e os movimento. Se eles se chocarem então uma mensagem deve ser impressa! Mas esta acontecendo uma coisa que eu nunca vi e não sei o porque disto!

Abaixo tem uma imagem de como eles aparecem inicialmente:

[img]http://i01.hyperfotos.com.br/img/2009/07/30/19/850978.jpg[/img]

Abaixo mostra uma imagem de como fica a imagem na tela quando eu movimento eles na tela:

[img]http://i01.hyperfotos.com.br/img/2009/07/30/19/850976.jpg[/img]

Fica assim um tempo depois os rastros desaparecem!!! E quando eu movimento de novo os rastros reaparecem!!!!

Segue a classe que desenha eles:

class MovimentaRetangulo extends JPanel implements Runnable {
	
	Rectangle a;
	Rectangle b;
	
	public MovimentaRetangulo(){
		a = new Rectangle(15,15,60,30);
		b = new Rectangle(300,230,60,30);
	}
	
	public void paintComponent(Graphics g){
	  //g.setColor(Color.red);
	  g.fillRect(a.x,a.y,60,30);
	  //g.setColor(Color.blue);
	  g.drawRect(b.x,b.y,60,30);
	  super.repaint();
	  
	}
	
	public void movRecA(int direcao){
		if(direcao == 0){
			a.x = a.x - 4;
		}
		if(direcao == 1){
			a.x = a.x + 4;
		}
		if(direcao == 2 ){
			a.y = a.y - 4;
		}
		if(direcao == 3){
			a.y = a.y + 4;
		}
		
	}
     
    public void movRecB(int direcao){
		if(direcao == 0){
			b.x = b.x - 4;
		}
		if(direcao == 1){
			b.x = b.x + 4;
		}
		if(direcao == 2 ){
			b.y = b.y + 4;
		}
		if(direcao == 3){
			b.y = b.y - 4;
		}
		
	}
	
	public void run(){
		if((b.x <= (a.x+a.width)) && (a.x <= (b.x+b.width)) && (b.y <= (a.y+a.height)) && (a.y <= (b.y+b.height)) )
			System.out.println("Houve colisão!!!");
		//if( a.intersects(b) )
		//	System.out.println("Houve colisão!!!");	
	} 


}

Já experimentei retirar o implements Runnable, mas da no mesmo, fiz isso achando que o Thread tava deixando o programa lento.

Mais uma coisinha, o método run não esta sendo acessado!!! Porque quando as imagens se sobrepõem a mensagem não é impressa, ai pensei que a formula que dedusi estava errada, então coloquei o metodo intersects do java para garantir mas quando as imagens se sobrepõem nem a msg do intersects é exibida! Então chego a conclusão de que o metodo run não esta sendo acessado

Segue o metodo main aonde anexo a Jpanel num Jframe e crio o Thread:

class Main {
	
    public static void main(String[] args) {
		
		MovimentaRetangulo mov = new MovimentaRetangulo();
		TrataTeclado teclado = new TrataTeclado(mov);
    	        Thread thread = new Thread(mov);
    	        JanelaPrincipal janela = new JanelaPrincipal(mov, teclado);
    			
		thread.start();
	}	
}

E a classe JanelaPrincipal:

public class JanelaPrincipal extends JFrame  {

    public JanelaPrincipal(MovimentaRetangulo mov, TrataTeclado teclado){
    
   	     super.setSize(new Dimension(2000, 2000));
		 super.setLocation(0,0);
		 super.setFocusable(true);
		 super.requestFocus();
		 super.setVisible(true);

		 super.add(mov);
		 super.addKeyListener(teclado);	
	}
}

Também experimentei tirar o metodo repaint e coloca-lo dentro do movRecA e movRecB mas os rastros continuam aparecendo e depois de um tempo eles desaparecem e apaenas ficam os retangulos....

Obrigado pela ajuda!

5 Respostas

J

será que esse problema de atualização seria um problema de hardware da minha maquina?

hugown

Toda vez antes de desenhar os retangulos desenhe um retangulo do tamanho do seu frame da cor natural, creio que dará certo.

[]'s

M

Sim, você vai precisar de uma Thread para se resposabilizar por isso. Existe uma regra básica para animações:

  1. Atualiza
  2. Repinta
  3. Dorme

Esses são os passos do loop que ocorrerá em sua Thread. Em outras palavras, seu método ficará algo como:

public void run() {
    // essa não é a melhor técnica de loop, mas é a mais simples
    while (true) {
        atualiza(); // verifica se houve colisões
        repaint();
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {}
    }
}

E outra coisa: ao invés de sobreescrever o método paintComponent, sobreescreva o método paint().

J
marcobiscaro2112:
Sim, você vai precisar de uma Thread para se resposabilizar por isso. Existe uma regra básica para animações:

1. Atualiza
2. Repinta
3. Dorme

Esses são os passos do loop que ocorrerá em sua Thread. Em outras palavras, seu método ficará algo como:
public void run() {
    // essa não é a melhor técnica de loop, mas é a mais simples
    while (true) {
        atualiza(); // verifica se houve colisões
        repaint();
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {}
    }
}

E outra coisa: ao invés de sobreescrever o método paintComponent, sobreescreva o método paint().

vlw,,,
o problema com o paintComponente eu já resolvi! Havia esquecido de fazer dentro da sobreposição um super.paintComponent()!!!!!!!!!!

O problema ta com a thread, quando eu mando rodar o projeto ele não inicia de modo instantâneo, o sistema fica um pouco lento.... ai quando ele detecta a colisão ele imprime muitas mensagens na tela mesmo quando eu ja removi um retangulo que estava sobre o outro e ele fica imprimindo dizendo colisão ( imagino que deve ser porque ele faz milhares de verificações e no curto espaço de tempo que houve colisão ele fez muitas verificações e fica imprimindo todas essas verificações mesmo quando um retangulo não esta sobre o outro, deve ser porq o sistema fica lento )

public void run(){
	//	System.out.println("Houve colisão!!!");
		
		while(rodar==true){
		if((b.x <= (a.x+a.width)) && (a.x <= (b.x+b.width)) && (b.y <= (a.y+a.height)) && (a.y <= (b.y+b.height)) )
			System.out.println("Houve colisão!!!");	
		}			
	}

vou colocar um sleep e ver como fica

M

Após pensar um pouco melhor sobre o seu código, percebi que a atualização e repintagem só é feita quando uma tecla é pressionada (ou seja, quando o keyPressed é chamado). E como o KeyListener já é uma outra Thread diferente da Thread do swing, não foi preciso trabalhar com Runnable. Veja uma implementação (aqui rodou perfeitamente):

Classe JanelaPrincipal.java

import javax.swing.JFrame;

public class JanelaPrincipal extends JFrame {

	private static final long serialVersionUID = 1L;

	public JanelaPrincipal(MovimentaRetangulo mov) {
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		add(mov);
		pack();
		setLocationRelativeTo(null);
		setVisible(true);
	}
}

Classe MovimentaRetangulo.java

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JPanel;

public class MovimentaRetangulo extends JPanel {

	private static final long serialVersionUID = 1L;
	private Rectangle a;
	private Rectangle b;

	public MovimentaRetangulo() {
		setPreferredSize(new Dimension(800, 800));
		a = new Rectangle(15, 15, 60, 30);
		b = new Rectangle(300, 230, 60, 30);
		addKeyListener(new TrataTeclado());
		setFocusable(true);
		requestFocusInWindow();
	}

	public void paint(Graphics g) {
		super.paint(g);
		g.fillRect(a.x, a.y, a.width, a.height);
		g.drawRect(b.x, b.y, b.width, b.height);
	}

	public void movRecs(int i) {
		switch (i) {
		case KeyEvent.VK_UP:
			a.y -= 4;
			b.y += 4;
			break;
		case KeyEvent.VK_DOWN:
			a.y += 4;
			b.y -= 4;
			break;
		case KeyEvent.VK_LEFT:
			a.x -= 4;
			b.x += 4;
			break;
		case KeyEvent.VK_RIGHT:
			a.x += 4;
			b.x -= 4;
			break;
		default:
			break;
		}
	}

	private void atualiza() {
		if (a.intersects(b)) {
			System.out.println("Houve colisão!!!");
		}
	}

	private class TrataTeclado extends KeyAdapter {

		@Override
		public void keyPressed(KeyEvent e) {
			int i = e.getKeyCode();
			movRecs(i);
			repaint();
			atualiza();
		}

	}

}

Classe Main.java

public class Main {

	public static void main(String[] args) {
		MovimentaRetangulo mov = new MovimentaRetangulo();
		new JanelaPrincipal(mov);
	}
}

Procure estudar sobre multithreading, pois isso só não foi necessário nesse caso por causa do KeyListener… mas será muito útil.

Criado 30 de julho de 2009
Ultima resposta 31 de jul. de 2009
Respostas 5
Participantes 3