Java2D Relogio Analogico [RESOLVIDO]

Boa noite galera!

Desde que comecei a mexer graficos em java venho tendo problemas… ainda bem que esta sendo so um hobby…
Tentei adaptar um codigo do amigo entanglement que encontrei em um topico sobre um assunto parecido com o meu, vejam como ficou:

[code]package teste;

import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import javax.swing.WindowConstants;
import javax.swing.JFrame;

public class RelogioAnalogico extends javax.swing.JPanel {

/**
* Auto-generated main method to display this 
* JPanel inside a new JFrame.
*/
private int tamanho;
private int segundo;
public static void main(String[] args) {
	JFrame frame = new JFrame();
	frame.setSize(450, 450);
	frame.getContentPane().add(new RelogioAnalogico(400));
	frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	frame.setVisible(true);
}

private void normalize (Graphics2D g2d, Dimension dim) {
    g2d.translate(dim.width / 2, dim.height / 2);
    g2d.scale((dim.width - 2) / 2, -(dim.height - 2) / 2);
}

public RelogioAnalogico(int tamanho){
	this.tamanho=tamanho;
	Runnable runnable = new Runnable() {
		public void run() {
			while(true){
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				segundo++;
				if (segundo>59){
					segundo=0;
				}
				repaint();
			}
		}
	};
	Thread thread = new Thread(runnable);
	thread.start();
}
public void paintComponent(Graphics g){
	
	Graphics2D g2d = (Graphics2D) g.create();
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	
    g2d.drawArc(0, 0, this.tamanho, this.tamanho, 0, 360);
    
    normalize (g2d, new Dimension(this.tamanho,this.tamanho));
    g2d.setStroke(new BasicStroke(0.01f));
    
    double theta = (2 * Math.PI * 1/60) * segundo;
    g2d.draw (new Line2D.Double(0, 0, Math.sin(theta), Math.cos(theta)));
    g2d.dispose();        
}

}
[/code]

O problema é que toda vez que desenho uma nova reta, a antiga nao deixa de existir, nao esta havendo uma atualizacao da tela, quando redimensiono a janela, ai atualiza.
Outra coisa, nao sabia que usava tanta matematica assim para fazer um circulo raiado oO… ate boiei quando vi os calculos, faz um tempinho que nao uso esses calculos. Alguem se habilita a me explicar como funciona? ^^ Preciso saber como funciona pois preciso que o ponteiro seja mais curto, no momento ele comeca do centro e vai ate a borda do circulo, preciso de uma margem entre o fim do ponteiro a borda, ate porque usarei mais ponteiros de tamanhos diferentes.

Obrigado pessoal!

Se alguem conhecer alguns tutoriais e apostilas sobre graficos em java, agradeco muito pois estou me interessando nessa area…

Então cara, voce tem que apagar o ponteiro desenhado na interação anterior…

Ficaria algo como:

[code] public void paintComponent(Graphics g) {

    Graphics2D g2d = (Graphics2D) g.create();

    
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.drawArc(0, 0, this.tamanho, this.tamanho, 0, 360);
    normalize(g2d, new Dimension(this.tamanho, this.tamanho));

    double theta = (2 * Math.PI * 1 / 60) * segundo;
    double theta2 = (2 * Math.PI * 1 / 60) * (segundo -1); 

    g2d.setColor(Color.WHITE)); //tem que ser a cor do background do frame! Acho que o default é branco, qualquer coisa é só mudar.
    g2d.setStroke(new BasicStroke(0.02f));
    g2d.draw(new Line2D.Double(0, 0, Math.sin(theta2), Math.cos(theta2))); //apaga o item anterior
    
    g2d.setColor(Color.red);
    g2d.setStroke(new BasicStroke(0.01f));
    g2d.draw(new Line2D.Double(0, 0, Math.sin(theta), Math.cos(theta))); //desenha o ponteiro

    g2d.dispose();

}

[/code]

A respeito das fórmulas eu fico te devendo…mas nada que uma consulta a uma apostila de Geometria não resolva! :smiley:

public void paintComponent(Graphics g){
super.paintComponent(g);//Coloque apenas essa linha aqui		
		Graphics2D g2d = (Graphics2D) g.create();

[quote=Mark_Ameba][code]
public void paintComponent(Graphics g){
super.paintComponent(g);//Coloque apenas essa linha aqui
Graphics2D g2d = (Graphics2D) g.create();

[/code][/quote]

É… tinha visto isso em outro exemplo de j2d, valeu mark…

Cesar, isso nem sempre vai funcionar, na verdade você desenha outro ponteiro mas com a cor de fundo do frame, mas se o fundo for uma imagem nao da certo. Estou usando uma imagem de um relogio por traz… ai acaba nao funcionando alem de que depois de um tempo vc vai ter um monte de ponteiros renderizados, so nao vamos ver… mas valeu a intencao, quando nao estava achando a solucao, pensei em fazer assim tambem.

Outro problema (acho que esta mais relacionado com os calculos) é ancorar o ponteiro mais pro meio. O centro de rotacao do ponteiro nao pode ser exatamente o centro do relogio, tem que sobrar uma beiradinha do ponteiro depois do eixo ( no caso dos segundos)

Ah, sei, em vez de usar 0, 0, Math.sin(theta), Math.cos(theta)), você pode usar algo como:

double x = Math.sin (theta);
double y = Math.cos (theta);

g2d.draw(new  Line2D.Double(-0.05*x, -0.05*y, x, y));

se for 5% do tamanho do ponteiro, por exemplo. (Você provavelmente vai ter de acertar a largura do segmento de reta, não use 0.01f como mostrei, mas um valor um pouco maior. Você pode até acertar a ponta para que ela fique arredondada, por exemplo. Isso pode ser feito usando-se, por exemplo, new BasicStroke (0.05f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); em vez de simplesmente usar new BasicStroke (0.01f);

Bom pessoal, consegui completar o relógio, qualquer erro me perdoem pois nunca mexi graficos em java, estou comecando agora e como so consegui gracas aos amigos, vou postar o resultado.

[code]package teste;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.swing.WindowConstants;
import javax.swing.JFrame;

public class RelogioAnalogico extends javax.swing.JPanel {

/**
 * Auto-generated main method to display this 
 * JPanel inside a new JFrame.
 */
private int tamanho;
private int segundo;
private int minuto;
private int hora;
private Color cSegundo;
private Color cMinuto;
private Color cHora;

private int tamanhoPino;
private BufferedImage fundo;
private BufferedImage pinoRelogio;

public static void main(String[] args) {
	JFrame frame = new JFrame();
	frame.setSize(750, 750);
	frame.getContentPane().add(new RelogioAnalogico(700,Color.red,Color.gray,Color.black,2));		
	frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	frame.setVisible(true);
}

private void normalizeSegundos (Graphics2D g2d, Dimension dim) {
	g2d.translate(dim.width / 2, dim.height/2);
	g2d.scale((((dim.width)/2)-(this.tamanho/7)), -(((dim.height)/2)-(this.tamanho/7)));
}
private void normalizeMinutos (Graphics2D g2d, Dimension dim) {
	g2d.translate(dim.width / 2, dim.height/2);
	g2d.scale((((dim.width)/2)-(this.tamanho/5)), -(((dim.height)/2)-(this.tamanho/5)));
}
private void normalizeHoras (Graphics2D g2d, Dimension dim) {
	g2d.translate(dim.width / 2, dim.height/2);
	g2d.scale((((dim.width)/2)-(this.tamanho/3.5)), -(((dim.height)/2)-(this.tamanho/3.5)));
}
/**
 * Skin==1 > Preto
 * Skin==2 > Branco
 * Skin==3 > Madeira
 * @param tamanho
 * @param cSegundo
 * @param cMinuto
 * @param cHora
 * @param skin
 */
public RelogioAnalogico(int tamanho, Color cSegundo,Color cMinuto, Color cHora, int skin){
	try{		
		
		this.tamanho=tamanho;	
		tamanhoPino = this.tamanho/25;

		this.cSegundo=cSegundo;
		this.cMinuto=cMinuto;
		this.cHora=cHora;

		if (skin == 1){
			fundo = ImageIO.read(getClass().getClassLoader().getResource("img/relogio_preto.png"));
		}
		else if (skin == 2){
			fundo = ImageIO.read(getClass().getClassLoader().getResource("img/relogio_branco.png"));
		}
		else if (skin == 3){
			fundo = ImageIO.read(getClass().getClassLoader().getResource("img/relogio_madeira.png"));
		}

		pinoRelogio = ImageIO.read(getClass().getClassLoader().getResource("img/pino_relogio.png"));

		String strHora = new SimpleDateFormat("hhmmss").format(new Date());
		
		/**
		 * Os numeros de minuto e horas sao exageradamente maiores para se obter um movimento uniforme desses ponteiros, senao, o ponteiro
		 * do minuto ia dar um pulo como o do segundo, e na verdade entre cada um dos 60 minutos existe mais 60 movimentos (60*60=3600). O mesmo
		 * ocorre com as horas, se a cada hora tem 60 minutos e cada minuto tem 60 segundos, (((60*60)*12)=43200) em cada hora o 
		 * ponteiro se move 3600 vezes, a cada 12 horas se move 43200 vezes. Ja pensou o ponteiro da hora pulando do "1" para o "2"
		 * de uma so vez? oO.. seria bem esquesito...
		 */
		segundo = Integer.parseInt(strHora.substring(4,6));
		minuto = (60*Integer.parseInt(strHora.substring(2,4)));
		hora = (3600*Integer.parseInt(strHora.substring(0,2)))+minuto;
		if (hora>43199){
			hora = minuto;
		}
		Runnable runnable = new Runnable() {
			public void run() {
				while(true){

					segundo++;
					minuto++;
					hora++;

					if (segundo>59){
						segundo=0;
					}
					if (minuto>3599){
						minuto=0;
					}
					if (hora>43199){
						hora=0;
					}						
					repaint();

					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		};
		Thread thread = new Thread(runnable);
		thread.start();
	}
	catch(Exception ex){
		ex.printStackTrace();
	}
}
public void paintComponent(Graphics g){		

	Graphics2D g2d = (Graphics2D) g.create();
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	super.paintComponent( g );

	/**
	 * Circulo do relogio
	 */
	//g2d.drawArc(0, 0, this.tamanho, this.tamanho, 0, 360);
	/**
	 * Imagem de fundo
	 */
	g2d.drawImage(fundo, 0, 0, this.tamanho, this.tamanho, null);    	    


	/**
	 * Ponteiro da hora
	 */

	g2d.setColor(this.cHora);
	double theta = (2 * Math.PI * 1/43200) * hora;
	normalizeHoras(g2d, new Dimension(this.tamanho,this.tamanho));    
	g2d.setStroke(new BasicStroke (0.07f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
	g2d.draw (new Line2D.Double(0, 0, Math.sin(theta), Math.cos(theta)));
	g2d.dispose();

	/**
	 * Ponteiro do minuto
	 */
	g2d = (Graphics2D) g.create();
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	g2d.setColor(this.cMinuto);
	theta = (2 * Math.PI * 1/3600) * minuto;
	normalizeMinutos(g2d, new Dimension(this.tamanho,this.tamanho));  
	g2d.setStroke(new BasicStroke (0.04f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
	g2d.draw (new Line2D.Double(0, 0, Math.sin(theta), Math.cos(theta)));
	g2d.dispose();

	/**
	 * Ponteiro do segundo
	 */
	g2d = (Graphics2D) g.create();
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	g2d.setColor(this.cSegundo);
	theta = (2 * Math.PI * 1/60) * segundo;
	double seno = Math.sin(theta);
	double cosseno = Math.cos(theta);
	normalizeSegundos(g2d, new Dimension(this.tamanho,this.tamanho));    
	g2d.setStroke(new BasicStroke (0.02f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
	g2d.draw (new Line2D.Double(-0.25*seno, -0.25*cosseno, seno, cosseno));
	g2d.dispose();  

	/**
	 * Pino
	 */
	g2d = (Graphics2D) g.create();
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	g2d.drawImage(pinoRelogio, (this.tamanho/2)-(tamanhoPino/2), (this.tamanho/2)-(tamanhoPino/2), tamanhoPino,tamanhoPino, null);   
	g2d.dispose();        
}

}
[/code]

Vlw gente :thumbup: :thumbup: :thumbup:

Surgiu um problema :shock: :shock: :shock:

Depois de deixar ele rodando umas horas percebi que ele comeca a atrazar mais ou menos um segundo por hora. A cada laco a thread dorme um segundo e depois faz o processo e atualiza o relogio, entao na verdade nao demora 1 segundo para atualizacao. Como resolver isso? Estou pensando em colocar para cada hora que passar eu pegar a hora do sistema novamente.

Entao ele demora 1000.000277778 milissegundos (1000 + (1000/3600000))

uma hora tem 3600000 milissegundos.

Eu acredito que essa diferença seja a soma de uma renca de pequenos ms que o codigo demora para repintar e atualizar a tela, voce poderia implementar algo que veja se passou 1 segundo inves de mandar a thread esperar um segundo, isso se chama ticks.
Voce guarda o momento e a cada loop pega o atual e ve se a diferença é 1 segundo, se for executa algo e muda o tick para o atual.
É como voce faria em um jogo 2D.

Sim, o problema parece ser este sim.
Foi mau mark mas nao entendi ainda, mostre-me a logica num pseudocodigo…

private long tick = 0;

public void run(){
tick = System.currentTimeInMillis();
while(true){
long thisTick = System.currentTimeInMillis();
if((thisTick - tick) > 1000){
//passou um segundo
tick = thisTick;//O Tick atual marca esse momento para continuar executando
} 
}
}

Tudo bem, até tinha uma nocao de que vc queria dizer isso so estava tentando imaginar onde ia parar o sleep, nao vou precisar do sleep para dormir a thread? Senao o while(true) mata… e se eu colocar o sleep nao consigo fazer como me mostrou…

Faça o seguinte:

Entenda a classe que pus aqui. Ela não tem sleep nem coisa nenhuma, só um javax.swing.Timer que é disparado cada MEIO segundo:

http://www.guj.com.br/posts/list/208780.java#1061757

Disparando um timer cada meio segundo (não a cada segundo inteiro), você não perde nenhum segundo.

E para você determinar horas, minutos e segundos, basta você pegar um new Date(), e pegar as horas, minutos e segundos do jeito que você preferir (normalmente você usa um java.util.Calendar).

Vou fazer o seguinte, a cada hora que se passar eu pego a hora do sistema para atualizar o relogio. Usando um timer nao seria como um sleep?

Se eu fosse voce eu usaria a solução com ticks, pois voce garantira que o ponteiro só ande se passou um segundo.
Fora que é um conceito interessante a se aprender, principalmente se voce quiser programar jogos e começar a se preocupar com fps, delay entre ações e etc…

Um timer, no Java, é implementado com uma thread que dispara os Runnables (se for o java.util.Timer) ou actions (se for o javax.swing.Timer) que estão agendadas para serem acionadas. Essa thread dorme, usando Thread.sleep, de acordo com o agendamento feito na hora que você configurou o timer.

Tudo bem, entao ficaria assim:

long ticker=0;
Timer timer = new Timer(1000 new ActionListener(){

public void actionPerformed(ActionEvent e){

long thisTicker = System.currentTimeInMillis();

if ((thisTicker - ticker)==1000{// Passou um segundo exato

						segundo++;
						minuto++;
						hora++;

						if (segundo>59){
							segundo=0;
						}
						if (minuto>3599){
							minuto=0;
						}
						if (hora>43199){
							hora=0;
						}		
}
else{
//Houve delay e teve dferenca nos milissegundos
//Pega a hora do sistema e atualiza as variaveis para resolver o delay
}				
						repaint();

}
)};
timer.start();

Usando o Timer agora, descartamos o while e fazemos o esquema de verificar se realmente se passou 1000 milissegundos, aconte que dentro de um segundo nao aconte um delay tao grande para aumentar um milissegundo, so se percebe horas rodando, entao o ticker anterior sempre sera igual ao capturado um segundo depois.

Eu nao entendi o lance de fazer o laco de meio segundo :?: :?

Tio, ainda não entendi o lance de você ficar incrementando horas, minutos e segundos.

Em vez disso, pegue um Calendar.getInstance(), e obtenha as horas, minutos e segundos atuais.

Se você pegar 2 vezes por segundo (ou seja, um timer de meio segundo), provavelmente você nunca vai pular um segundo inteiro, mesmo que o timer se atrase um pouco (como você já deve ter percebido, o Timer e o Thread.sleep não são lá muito precisos).

[quote=entanglement]Tio, ainda não entendi o lance de você ficar incrementando horas, minutos e segundos.
[/quote]

É que a ideia é nao ficar consultando o SO todo segundo e gerando instancias de Date() a torda e a direita se eu posso incrementa-la… alem da manipulacao de string…

Tudo bem, entendi o que vc quis dizer com o meio segundo.

Acho que assim eu pude aproveitar a idéia dos dois:

[code]package main;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.swing.WindowConstants;
import javax.swing.JFrame;

public class RelogioAnalogico extends javax.swing.JPanel {

/**
 * Auto-generated main method to display this 
 * JPanel inside a new JFrame.
 */
private int tamanho;
private int segundo;
private int minuto;
private int hora;
private Color cSegundo;
private Color cMinuto;
private Color cHora;

private int tamanhoPino;
private BufferedImage fundo;
private BufferedImage pinoRelogio;
public static void main(String[] args) {
	JFrame frame = new JFrame();
	frame.setSize(750, 750);
	frame.getContentPane().add(new RelogioAnalogico(700,Color.red,Color.gray,Color.black,2));		
	frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	frame.setVisible(true);
}

private void normalizeSegundos (Graphics2D g2d, Dimension dim) {
	g2d.translate(dim.width / 2, dim.height/2);
	g2d.scale((((dim.width)/2)-(this.tamanho/7)), -(((dim.height)/2)-(this.tamanho/7)));
}
private void normalizeMinutos (Graphics2D g2d, Dimension dim) {
	g2d.translate(dim.width / 2, dim.height/2);
	g2d.scale((((dim.width)/2)-(this.tamanho/5)), -(((dim.height)/2)-(this.tamanho/5)));
}
private void normalizeHoras (Graphics2D g2d, Dimension dim) {
	g2d.translate(dim.width / 2, dim.height/2);
	g2d.scale((((dim.width)/2)-(this.tamanho/3.5)), -(((dim.height)/2)-(this.tamanho/3.5)));
}
/**
 * Skin==1 > Preto
 * Skin==2 > Branco
 * Skin==3 > Madeira
 * @param tamanho
 * @param cSegundo
 * @param cMinuto
 * @param cHora
 * @param skin
 */
public RelogioAnalogico(int tamanho, Color cSegundo,Color cMinuto, Color cHora, int skin){
	try{		
		
		this.tamanho=tamanho;	
		tamanhoPino = this.tamanho/25;

		this.cSegundo=cSegundo;
		this.cMinuto=cMinuto;
		this.cHora=cHora;

		if (skin == 1){
			fundo = ImageIO.read(getClass().getClassLoader().getResource("img/relogio_preto.png"));
		}
		else if (skin == 2){
			fundo = ImageIO.read(getClass().getClassLoader().getResource("img/relogio_branco.png"));
		}
		else if (skin == 3){
			fundo = ImageIO.read(getClass().getClassLoader().getResource("img/relogio_madeira.png"));
		}

		pinoRelogio = ImageIO.read(getClass().getClassLoader().getResource("img/pino_relogio.png"));

		String strHora = new SimpleDateFormat("hhmmss").format(new Date());
		
		/**
		 * Os numeros de minuto e horas sao exageradamente maiores para se obter um movimento uniforme desses ponteiros, senao, o ponteiro
		 * do minuto ia dar um pulo como o do segundo, e na verdade entre cada um dos 60 minutos existe mais 60 movimentos (60*60=3600). O mesmo
		 * ocorre com as horas, se a cada hora tem 60 minutos e cada minuto tem 60 segundos, (((60*60)*12)=43200) em cada hora o 
		 * ponteiro se move 3600 vezes, a cada 12 horas se move 43200 vezes. Ja pensou o ponteiro da hora pulando do "1" para o "2"
		 * de uma so vez? oO.. seria bem esquesito...
		 */
		segundo = Integer.parseInt(strHora.substring(4,6));
		minuto = (60*Integer.parseInt(strHora.substring(2,4)));
		hora = (3600*Integer.parseInt(strHora.substring(0,2)))+minuto;
		if (hora>43199){
			hora = minuto;
		}
		Runnable runnable = new Runnable() {
			public void run() {
				long ticker = System.currentTimeMillis();
				while(true){
					
					segundo++;
					minuto++;
					hora++;

					if (segundo>59){
						segundo=0;
					}
					if (minuto>3599){
						minuto=0;
					}
					if (hora>43199){
						hora=0;
					}		
					
					/**
					 * Verificando se houve delay
					 */
					if(((System.currentTimeMillis() - ticker)%1000)!=0){
						System.out.println(((System.currentTimeMillis() - ticker)%1000));
						System.out.println("Atualizando com o SO");
						String strHora = new SimpleDateFormat("hhmmss").format(new Date());
						ticker = System.currentTimeMillis();
						/**
						 * Os numeros de minuto e horas sao exageradamente maiores para se obter um movimento uniforme desses ponteiros, senao, o ponteiro
						 * do minuto ia dar um pulo como o do segundo, e na verdade entre cada um dos 60 minutos existe mais 60 movimentos (60*60=3600). O mesmo
						 * ocorre com as horas, se a cada hora tem 60 minutos e cada minuto tem 60 segundos, (((60*60)*12)=43200) em cada hora o 
						 * ponteiro se move 3600 vezes, a cada 12 horas se move 43200 vezes. Ja pensou o ponteiro da hora pulando do "1" para o "2"
						 * de uma so vez? oO.. seria bem esquesito...
						 */
						segundo = Integer.parseInt(strHora.substring(4,6));
						minuto = (60*Integer.parseInt(strHora.substring(2,4)));
						hora = (3600*Integer.parseInt(strHora.substring(0,2)))+minuto;
						if (hora>43199){
							hora = minuto;
						}	
					}
					repaint();

					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		};
		Thread thread = new Thread(runnable);
		thread.start();
	}
	catch(Exception ex){
		ex.printStackTrace();
	}
}
public void paintComponent(Graphics g){		

	Graphics2D g2d = (Graphics2D) g.create();
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	super.paintComponent( g );

	/**
	 * Circulo do relogio
	 */
	//g2d.drawArc(0, 0, this.tamanho, this.tamanho, 0, 360);
	/**
	 * Imagem de fundo
	 */
	g2d.drawImage(fundo, 0, 0, this.tamanho, this.tamanho, null);    	    


	/**
	 * Ponteiro da hora
	 */

	g2d.setColor(this.cHora);
	double theta = (2 * Math.PI * 1/43200) * hora;
	normalizeHoras(g2d, new Dimension(this.tamanho,this.tamanho));    
	g2d.setStroke(new BasicStroke (0.07f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
	g2d.draw (new Line2D.Double(0, 0, Math.sin(theta), Math.cos(theta)));
	g2d.dispose();

	/**
	 * Ponteiro do minuto
	 */
	g2d = (Graphics2D) g.create();
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	g2d.setColor(this.cMinuto);
	theta = (2 * Math.PI * 1/3600) * minuto;
	normalizeMinutos(g2d, new Dimension(this.tamanho,this.tamanho));  
	g2d.setStroke(new BasicStroke (0.04f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
	g2d.draw (new Line2D.Double(0, 0, Math.sin(theta), Math.cos(theta)));
	g2d.dispose();

	/**
	 * Ponteiro do segundo
	 */
	g2d = (Graphics2D) g.create();
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	g2d.setColor(this.cSegundo);
	theta = (2 * Math.PI * 1/60) * segundo;
	double seno = Math.sin(theta);
	double cosseno = Math.cos(theta);
	normalizeSegundos(g2d, new Dimension(this.tamanho,this.tamanho));    
	g2d.setStroke(new BasicStroke (0.02f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
	g2d.draw (new Line2D.Double(-0.25*seno, -0.25*cosseno, seno, cosseno));
	g2d.dispose();  

	/**
	 * Pino
	 */
	g2d = (Graphics2D) g.create();
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	g2d.drawImage(pinoRelogio, (this.tamanho/2)-(tamanhoPino/2), (this.tamanho/2)-(tamanhoPino/2), tamanhoPino,tamanhoPino, null);   
	g2d.dispose();        
}

}
[/code]

Criar uma nova instância de GregorianCalendar a cada meio segundo? Não é isso que vai afogar sua aplicação.