AWTUtilities.setWindowOpaque

Estou testando os seguintes métodos dentro de um JFrame:

private void configTransparencia() { boolean supported = AWTUtilities.isTranslucencySupported(AWTUtilities.Translucency.TRANSLUCENT); boolean capable = AWTUtilities.isTranslucencyCapable(graphicsConfiguration); if(supported && capable) { AWTUtilities.setWindowOpaque(this, false); } else { AWTUtilities.setWindowOpacity(this, 0); } }

private void createBufferStrategy() { try { this.createBufferStrategy(2, new BufferCapabilities(new ImageCapabilities(true), new ImageCapabilities(true), FlipContents.UNDEFINED)); System.out.println("FlipContents active"); } catch (AWTException e){ // flip is unavailable, create the best you have this.createBufferStrategy(2); System.err.println("Warning: FlipContents not available, using best BufferStrategy available"); System.err.println("System error message: "+e.getMessage()); } }
O detalhe é que quando eu pego o Graphics do BufferStrategy e desenho nele, o desenho fica invisível junto com a janela!

Como eu posso deixar uma janela invisível e desenhar conteúdo nela usando o BufferStrategy, que não está presente no JPanel e outros componentes?

A minha idéia com isso é colocar esse meu pequeno relógio num canto da tela apenas com o mostrador (circular) aparecendo…

Eu sei que esse tipo de coisa já existe, já vem no Vista como Widget, etc… mas eu adoro fuçar nessas coisas!

Por enquanto a parte da transparência está comentada até que eu domine a técnica…

Refatoração à parte, essa é a minha "CRASSE" gigante, porque sendo isso apenas um relógio eu não quis montar uma arquitetura, embora eu tenha criado uma arquitetura que uso para animações e jogos!

O relógio funciona, quem tiver coragem cole o código no Eclipse e execute!

:lol:

[code]import java.awt.AWTException;
import java.awt.AlphaComposite;
import java.awt.BufferCapabilities;
import java.awt.Color;
import java.awt.Composite;
import java.awt.DisplayMode;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.ImageCapabilities;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.BufferCapabilities.FlipContents;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import javax.swing.JFrame;

public final class MiniRelogio extends JFrame implements Runnable, KeyListener, MouseListener {

private static final MiniRelogio instance = new MiniRelogio();
private static final long serialVersionUID = 1L;

public static void main(String... args) {
	getInstance().start();
}

private GraphicsDevice graphicsDevice;
private DisplayMode displayMode;
private GraphicsConfiguration graphicsConfiguration;
private int tamanho;
private volatile boolean running;
private Relogio relogio;

private MiniRelogio() {
	super("MiniRelogio");
	graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
	graphicsConfiguration = graphicsDevice.getDefaultConfiguration();
	displayMode = graphicsDevice.getDisplayMode();
	tamanho = (int)(0.15 * displayMode.getHeight());
	configJanela();
	relogio = new Relogio();
}

private void configJanela() {
	this.setUndecorated(true);
	this.pack();
	Insets it = this.getInsets();
	this.setSize(tamanho+it.left+it.right, tamanho+it.top+it.bottom);
	this.setResizable(false);
	this.setIgnoreRepaint(true);

// configTransparencia();
addListeners();
createBufferStrategy();
posicione();
}

// private void configTransparencia() {
// boolean supported = AWTUtilities.isTranslucencySupported(AWTUtilities.Translucency.TRANSLUCENT);
// boolean capable = AWTUtilities.isTranslucencyCapable(graphicsConfiguration);
// if(supported && capable) {
// AWTUtilities.setWindowOpaque(this, false);
// } else {
// AWTUtilities.setWindowOpacity(this, 0);
// }
// }

private void addListeners() {
	this.addKeyListener(this);
	this.addMouseListener(this);
	this.setFocusable(true);
	this.addFocusListener(new FocusAdapter(){
		public void focusLost(FocusEvent e) {
			MiniRelogio.this.requestFocus();
		}
	});
	this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
	this.addWindowListener(new WindowAdapter(){
		public void windowClosing(WindowEvent e) {
			MiniRelogio.this.stop();
		}
	});
}

private void createBufferStrategy() {
	try {
		this.createBufferStrategy(2, new BufferCapabilities(new ImageCapabilities(true), new ImageCapabilities(true), FlipContents.UNDEFINED));
		System.out.println("FlipContents active");
	} catch (AWTException e){
		// flip is unavailable, create the best you have
		this.createBufferStrategy(2);
		System.err.println("Warning: FlipContents not available, using best BufferStrategy available");
		System.err.println("System error message: "+e.getMessage());
	}
}

private void posicione() {
	int padding = (int)(0.015 * displayMode.getHeight());
	int posX = displayMode.getWidth() - tamanho - padding;
	int posY = padding;
	this.setLocation(posX, posY);
}

private void start() {
	Thread t = new Thread(this);
	t.setPriority(Thread.MAX_PRIORITY);
	t.start();
}

private void stop() {
	running = false;
}

public void run() {
	running = true;
	this.setVisible(true);
	while(running) {
		long time = System.nanoTime();
		this.getBufferStrategy().show();
		paint();
		update();
		pause(time);
	}
	this.dispose();
	System.exit(0);
}

private void paint() {
	Graphics2D g2 = (Graphics2D)this.getBufferStrategy().getDrawGraphics();
	g2.setRenderingHints(DefaultRenderingHints.getInstance());
	clearScreen(g2);
	relogio.paint(g2);
	g2.dispose();
}

private void clearScreen(Graphics2D g2) {
	g2.setColor(CompColor.BACKGROUND.getColor());
	g2.fillRect(0, 0, tamanho, tamanho);
}

private void update() {
	relogio.update();
}

private void pause(long time) {
	double fps = 60;
	long minPause = 5;
	long pauseTime = (long)(1000.0/fps - (double)(System.nanoTime()-time)/1000000.0);
	pauseTime = pauseTime > minPause ? pauseTime : minPause;
	try {
		Thread.sleep(pauseTime);
	} catch (InterruptedException e) {}
}

private double getPosX(double raio, double angle) {
	// raio * cos angulo
	return raio * Math.cos(Math.toRadians(angle));
}

private double getPosY(double raio, double angle) {
	// raio * sin angulo
	return raio * Math.sin(Math.toRadians(angle));
}

public void keyPressed(KeyEvent e) {
	switch(e.getKeyCode()) {
		case KeyEvent.VK_ESCAPE:
			this.stop();
			break;
	}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}

public static MiniRelogio getInstance() {
	return instance;
}

private static class DefaultRenderingHints extends RenderingHints {

	private static final DefaultRenderingHints instance = new DefaultRenderingHints();
	
	private DefaultRenderingHints() {
		super(null);
		this.put(KEY_ALPHA_INTERPOLATION,	VALUE_ALPHA_INTERPOLATION_QUALITY);
		this.put(KEY_ANTIALIASING,			VALUE_ANTIALIAS_ON);
		this.put(KEY_COLOR_RENDERING,		VALUE_COLOR_RENDER_QUALITY);
		this.put(KEY_DITHERING,				VALUE_DITHER_DISABLE);
		this.put(KEY_FRACTIONALMETRICS,		VALUE_FRACTIONALMETRICS_ON);
		this.put(KEY_INTERPOLATION,			VALUE_INTERPOLATION_BILINEAR);
		this.put(KEY_RENDERING,				VALUE_RENDER_QUALITY);
		this.put(KEY_STROKE_CONTROL,		VALUE_STROKE_NORMALIZE);
		this.put(KEY_TEXT_ANTIALIASING,		VALUE_TEXT_ANTIALIAS_ON);
	}

	private static DefaultRenderingHints getInstance() {
		return instance;
	}

}

private class Relogio {
	
	int posInterna;
	private Integer[] raiosInternos;
	private Integer[] raiosExternos;
	private int distRaios;
	private double aumentaAnguloDe;
	private BufferedImage mostrador;
	private TimeAngles timeAngles;
	private AlphaComposite alphaFundoMostrador;
	private AlphaComposite alphaHoras;
	private AlphaComposite alphaMinutos;
	private AlphaComposite alphaSegundos;
	private Font font;
	
	private Relogio() {
		posInterna = (int)((double)tamanho / 2.0);
		distRaios = (int)((double)tamanho / 40.0);
		preparaAlphas();
		preparaRaios();
		preparaMostrador();
		aumentaAnguloDe = 12;
		timeAngles = new TimeAngles(new GregorianCalendar());
		font = new Font("Courier New", Font.BOLD, (int)(0.05*(double)tamanho));
	}
	
	private void preparaAlphas() {
		alphaFundoMostrador = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.20F);
		alphaHoras = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1F);
		alphaMinutos = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7F);
		alphaSegundos = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4F);
	}

	private void preparaRaios() {
		List<Integer> raios = new ArrayList<Integer>();
		int raioMostrador = (int)((double)tamanho/2.0 - (double)distRaios * 2.0);
		int raio = raioMostrador;
		do {
			raios.add(raio);
			raio -= distRaios;
		} while(raio > 0);
		raiosInternos = raios.toArray(new Integer[]{});
		
		int maiorRaio = (int)Math.pow(2 * (Math.pow((double)tamanho/2.0, 2.0)), 0.5);
		raios = new ArrayList<Integer>();
		raio = raioMostrador + distRaios;
		do {
			raios.add(raio);
			raio += distRaios;
		} while(raio <= maiorRaio);
		raiosExternos = raios.toArray(new Integer[]{});
	}

	private void preparaMostrador() {
		mostrador = graphicsConfiguration.createCompatibleImage(tamanho, tamanho, Transparency.TRANSLUCENT);
		Graphics2D g2 = mostrador.createGraphics();
		g2.setRenderingHints(DefaultRenderingHints.getInstance());
		g2.setColor(CompColor.FOREGROUND.getColor());
		desenhaCirculos(g2);
		desenhaRaios(g2);
		desenhaTracos(g2);
		desenhaNumeros(g2);
		g2.drawRect(0, 0, tamanho-1, tamanho-1);
		g2.dispose();
	}

	private void desenhaCirculos(Graphics2D g2) {
		Composite comp = g2.getComposite();
		g2.setComposite(alphaFundoMostrador);
		int posicao;
		int diametro;
		for(int raio : raiosInternos) {
			posicao = (int)((double)tamanho/2.0-(double)raio);
			diametro = raio*2;
			g2.drawOval(posicao, posicao, diametro, diametro);
		}
		for(int raio : raiosExternos) {
			posicao = (int)((double)tamanho/2.0-(double)raio);
			diametro = raio*2;
			g2.drawOval(posicao, posicao, diametro, diametro);
		}
		g2.setComposite(comp);
		posicao = (int)((double)tamanho/2.0-(double)raiosInternos[0]);
		diametro = raiosInternos[0]*2;
		g2.drawOval(posicao, posicao, diametro, diametro);
	}
	
	private void desenhaRaios(Graphics2D g2) {
		Composite comp = g2.getComposite();
		g2.setComposite(alphaFundoMostrador);
		int raio = raiosInternos[0];
		for(int angle=0; angle<360; angle+=6) {
			int posXExterna = (int)((double)posInterna + getPosX(raio, angle));
			int posYExterna = (int)((double)posInterna + getPosY(raio, angle));
			g2.drawLine(posInterna, posInterna, posXExterna, posYExterna);
		}
		int raioMenor = raiosInternos[0];
		int raioMaior = raiosExternos[raiosExternos.length-1];
		for(int angle=0; angle<360; angle+=3) {
			int posXMenor = (int)((double)posInterna + getPosX(raioMenor, angle));
			int posYMenor = (int)((double)posInterna + getPosY(raioMenor, angle));
			int posXMaior = (int)((double)posInterna + getPosX(raioMaior, angle));
			int posYMaior = (int)((double)posInterna + getPosY(raioMaior, angle));
			g2.drawLine(posXMenor, posYMenor, posXMaior, posYMaior);
		}
		g2.setComposite(comp);
	}

	private void desenhaTracos(Graphics2D g2) {
		int raioMaior = raiosExternos[0];
		int raioMenor;
		for(int angle=0; angle<360; angle+=6) {
			raioMenor = 1;
			if(angle % 90 == 0) {
				raioMenor = 3;
			} else if (angle % 30 == 0) {
				raioMenor = 2;
			}
			int posXMenor = (int)((double)posInterna + getPosX(raiosInternos[raioMenor], angle));
			int posYMenor = (int)((double)posInterna + getPosY(raiosInternos[raioMenor], angle));
			int posXMaior = (int)((double)posInterna + getPosX(raioMaior, angle));
			int posYMaior = (int)((double)posInterna + getPosY(raioMaior, angle));
			g2.drawLine(posXMenor, posYMenor, posXMaior, posYMaior);
		}
	}
	
	private void desenhaNumeros(Graphics2D g2) {
		g2.setColor(CompColor.FOREGROUND.getColor());
		g2.setFont(font);
		FontMetrics fm = g2.getFontMetrics();
		double height = fm.getAscent();
		int numero = 3;
		for(int angulo=0; angulo<360; angulo+=30) {
			double width = fm.stringWidth(String.valueOf(numero));
			int posX = (int)((double)posInterna + getPosX(raiosInternos[6], angulo) - width / 2.0);
			int posY = (int)((double)posInterna + getPosY(raiosInternos[6], angulo) + height / 2.0);
			
			g2.drawString(String.valueOf(numero), posX, posY);
			
			numero = (numero + 1) % 13;
			if(numero == 0) numero++;
		}
	}
	
	public void paint(Graphics2D g2) {
		g2.drawImage(mostrador, 0, 0, null);
		g2.setColor(CompColor.FOREGROUND.getColor());
		desenhaPonteiros(g2);
	}
	
	private void desenhaPonteiros(Graphics2D g2) {
		int raio = 5;
		this.desenhaPonteiro(g2, timeAngles.getSecondAngle(), raio, alphaSegundos);
		this.desenhaPonteiro(g2, timeAngles.getMinuteAngle(), raio + 4, alphaMinutos);
		this.desenhaPonteiro(g2, timeAngles.getHourAngle(), raio + 8, alphaHoras);
	}
	
	private void desenhaPonteiro(Graphics2D g2, double angle, int raio, AlphaComposite alpha) {
		Composite comp = g2.getComposite();
		g2.setComposite(alpha);

		// Desenhando ponteiro
		double posXInterna = (double)posInterna + getPosX(raiosInternos[raio+2], angle);
		double posYInterna = (double)posInterna + getPosY(raiosInternos[raio+2], angle);
		g2.drawLine((int)posInterna, (int)posInterna, (int)posXInterna, (int)posYInterna);
		
		// Desenhando triângulo
		double posXExterna = (double)posInterna + getPosX(raiosInternos[raio], angle);
		double posYExterna = (double)posInterna + getPosY(raiosInternos[raio], angle);
		double posXInterna1 = (double)posInterna + getPosX(raiosInternos[raio+4], (angle-aumentaAnguloDe/2.0));
		double posYInterna1 =(double)posInterna +  getPosY(raiosInternos[raio+4], (angle-aumentaAnguloDe/2.0));
		double posXInterna2 = (double)posInterna + getPosX(raiosInternos[raio+4], (angle+aumentaAnguloDe/2.0));
		double posYInterna2 = (double)posInterna + getPosY(raiosInternos[raio+4], (angle+aumentaAnguloDe/2.0));
		g2.fillPolygon(new int[]{(int)posXExterna, (int)posXInterna1, (int)posXInterna2, (int)posXExterna}, new int[]{(int)posYExterna, (int)posYInterna1, (int)posYInterna2, (int)posYExterna}, 3);
		
		g2.setComposite(comp);
	}

	public void update() {
		timeAngles = new TimeAngles(new GregorianCalendar());
	}

}

private class TimeAngles {
	
	private double hour;
	private double minute;
	private double second;
	private double millisecond;
	
	public TimeAngles(Calendar calendar) {
		hour = calendar.get(Calendar.HOUR_OF_DAY);
		minute = calendar.get(Calendar.MINUTE);
		second = calendar.get(Calendar.SECOND);
		millisecond = calendar.get(Calendar.MILLISECOND);
	}
	
	public double getMillisecondAngle() {
		double time = millisecond/1000;
		return getAngle(time);
	}
	
	public double getSecondAngle() {
		double time = (second + millisecond/1000)/60;
		return getAngle(time);
	}
	
	public double getMinuteAngle() {
		double time = (minute + second/60)/60;
		return getAngle(time);
	}
	
	public double getHourAngle() {
		double time = (hour + minute/60 + second/3600 + millisecond/3600000)/12;
		return getAngle(time);
	}
	
	private double getAngle(double time) {
		return (time * 360) - 90;
	}
	
}

private enum CompColor {
	
	BACKGROUND(
			CompColor.mixColor(
					new Color[]{
							new Color(0x00FF00),	// verde
							new Color(0x808080),	// cinza
							new Color(0xFFFFFF)},	// branco
					new float[]{
							0.30F * 0.25F,
							0.30F * 0.75F,
							0.70F})),
							
	FOREGROUND(
			CompColor.mixColor(
					new Color[]{
							new Color(0x00FF00),	// verde
							new Color(0x808080),	// cinza
							new Color(0x000000)},	// preto
					new float[]{
							0.60F * 0.25F,
							0.60F * 0.75F,
							0.40F}));
	
	private Color color;
	
	private CompColor(Color color) {
		this.color = color;
	}

	private static Color mixColor(Color[] colors, float[] weights) {
		if(!validArgs(colors, weights)) {
			try {
				throw new Exception("Argumentos inválidos");
			} catch (Exception e) {
				e.printStackTrace();
				System.exit(0);
			}
		}
		float[] comps = new float[4];
		for(int i=0; i<colors.length; i++) {
			Color color = colors[i];
			float weight = weights[i];
			
			comps[0] += (float)color.getRed() * weight;
			comps[1] += (float)color.getGreen() * weight;
			comps[2] += (float)color.getBlue() * weight;
			comps[3] += (float)color.getAlpha() * weight;
		}
		for(int i=0; i><comps.length; i++) {
			if(comps[i] >< 0) {
				comps[i] = 0;
			} else if(comps[i] > 0xFF) {
				comps[i] = 0xFF;
			}
		}
		return new Color((int)comps[0], (int)comps[1], (int)comps[2], (int)comps[3]);
	}
	
	private static boolean validArgs(Color[] colors, float[] weights) {
		if(colors == null || !(colors.length>0) || weights == null || !(weights.length>0) || colors.length != weights.length) {
			return false;
		}
		float sum = 0;
		for(float weight : weights) {
			if(weight <= 0 || weight >= 1) {
				return false;
			}
			sum += weight;
		}
		if(sum != 1.0F) {
			return false;
		}
		return true;
	}

	public Color getColor() {
		return color;
	}
	
}

}[/code]

Bom, segue também o código completo da versão desse relógio de display analógico em J2ME (para dispositivos móveis / celulares).

Que eu acabei de adaptar!

:wink:

[code]import java.util.Calendar;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public final class MiniRelogio extends MIDlet {

private Screen screen;
private int frontColor;
private int backColor;

protected void destroyApp(boolean restart) throws MIDletStateChangeException {
	if(!restart) {
		this.notifyDestroyed();
	} else {
		this.startApp();
	}
}

protected void pauseApp() {
	this.notifyPaused();
}

protected void startApp() throws MIDletStateChangeException {
	prepareScreenColors();
	screen = new Screen();
	Display.getDisplay(this).setCurrent(screen);
	screen.start();
}

private void finalize() {
	Display.getDisplay(this).setCurrent(null);
	try {
		destroyApp(screen.isRestart());
	} catch (MIDletStateChangeException e) {
		System.exit(0);
	}
}

private void prepareScreenColors() {
	backColor = mixColors(
			new int[]{
					0x00FF00,	// verde
					0x808080,	// cinza
					0xFFFFFF},	// branco
			new float[]{
					0.30F * 0.25F,
					0.30F * 0.75F,
					0.70F});
	frontColor = mixColors(
			new int[]{
					0x00FF00,	// verde
					0x808080,	// cinza
					0x000000},	// preto
			new float[]{
					0.60F * 0.25F,
					0.60F * 0.75F,
					0.40F});
}

private double getPosX(double raio, double angle) {
	// raio * cos angulo
	return raio * Math.cos(Math.toRadians(angle));
}

private double getPosY(double raio, double angle) {
	// raio * sin angulo
	return raio * Math.sin(Math.toRadians(angle));
}

private int getPseudoAlphaColor(int color, float alpha) {
	float alphaBack = 1F - alpha;
	return mixColors(
			new int[]{backColor, color},
			new float[]{alphaBack, alpha});
}

private int mixColors(int[] colors, float[] weights) {
	float[] comps = new float[3];
	for(int i=0; i<colors.length; i++) {
		int[] color = getColorComps(colors[i]);
		float weight = weights[i];
		
		comps[0] += (float)color[0] * weight;
		comps[1] += (float)color[1] * weight;
		comps[2] += (float)color[2] * weight;
	}
	for(int i=0; i><comps.length; i++) {
		if(comps[i] >< 0) {
			comps[i] = 0;
		} else if(comps[i] > 0xFF) {
			comps[i] = 0xFF;
		}
	}
	return Integer.parseInt(
			leftPadding(Integer.toHexString((int)comps[0]), '0', 2) +
			leftPadding(Integer.toHexString((int)comps[1]), '0', 2) +
			leftPadding(Integer.toHexString((int)comps[2]), '0', 2),
			16);
}

int[] getColorComps(int color) {
	String sColor = leftPadding(Integer.toHexString(color), '0', 6);
	return new int[] {
			Integer.parseInt(sColor.substring(0, 2), 16),
			Integer.parseInt(sColor.substring(2, 4), 16),
			Integer.parseInt(sColor.substring(4, 6), 16),
	};
}

private String leftPadding(String text, char c, int size) {
	while(text.length() < size) {
		text = c + text;
	}
	return text;
}

private class Screen extends GameCanvas implements Runnable, CommandListener {

	private volatile boolean running;
	private volatile boolean restart;
	private Relogio relogio;
	
	protected Screen() {
		super(true);
		this.setCommandListener(this);
		addCommands();
		relogio = new Relogio(new int[]{getWidth(), getHeight()});
	}
	
	private void addCommands() {
		this.addCommand(new Command("Sair", Command.EXIT, 1));
	}

	public void commandAction(Command command, Displayable displayable) {
		if(displayable!=this)return;
		if(command.getCommandType() == Command.EXIT) {
			stop();
		}
	}
	
	private void start() {
		Thread t = new Thread(this);
		t.setPriority(Thread.MAX_PRIORITY);
		t.start();
	}
	
	private void stop() {
		running = false;
	}

	public void run() {
		running = true;
		while(running) {
			long time = System.currentTimeMillis();
			this.flushGraphics();
			paint();
			update();
			pause(time);
		}
		finalize();
	}
	
	private void paint() {
		Graphics g = this.getGraphics();
		clearScreen(g);
		relogio.paint(g);
	}

	private void clearScreen(Graphics g) {
		g.setColor(backColor);
		g.fillRect(0, 0, getWidth(), getHeight());
	}

	private void update() {
		relogio.update();
	}

	private void pause(long time) {
		double fps = 30;
		long minPause = 5;
		long pauseTime = (long)(1000.0/fps - (double)(System.currentTimeMillis()-time));
		pauseTime = pauseTime > minPause ? pauseTime : minPause;
		try {
			Thread.sleep(pauseTime);
		} catch (InterruptedException e) {}
	}

	public boolean isRestart() {
		return restart;
	}

}
	
private class Relogio {
	
	private final int LARGURA = 0;
	private final int ALTURA = 1;
	private final int ANCHOR = Graphics.TOP | Graphics.LEFT;
	
	private int[] tamanho;
	private int menorRaio;
	private int posX;
	private int posY;
	private int[] raiosInternos;
	private int[] raiosExternos;
	private int distRaios;
	private double aumentaAnguloDe;
	private TimeAngles timeAngles;
	private int corFundoMostrador;
	private int corNumeros;
	private int corHoras;
	private int corMinutos;
	private int corSegundos;
	private Font font;
	
	private Relogio(int[] tamanho) {
		this.tamanho = tamanho;
		menorRaio = (int)((double)Math.min(tamanho[LARGURA], tamanho[ALTURA])/2.0);
		posX = (int)((double)tamanho[LARGURA] / 2.0);
		posY = (int)((double)tamanho[ALTURA] / 2.0);
		distRaios = (int)((double)menorRaio / 20.0);
		preparaCores();
		preparaRaios();
		aumentaAnguloDe = 12;
		timeAngles = new TimeAngles(Calendar.getInstance());
		font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
	}
	
	private void preparaCores() {
		corFundoMostrador = getPseudoAlphaColor(frontColor, 0.20F);
		corNumeros = getPseudoAlphaColor(frontColor, 0.5F);
		corHoras = getPseudoAlphaColor(frontColor, 1F);
		corMinutos = getPseudoAlphaColor(frontColor, 0.7F);
		corSegundos = getPseudoAlphaColor(frontColor, 0.4F);
	}

	private void preparaRaios() {
		int raioMostrador = (int)((double)menorRaio - (double)distRaios * 2.0);
		int tamanhoVetor = 0;
		for(int raio=raioMostrador; raio>0; raio-=distRaios) {
			tamanhoVetor++;
		}
		raiosInternos = new int[tamanhoVetor];
		for(int raio=raioMostrador, i=0; raio>0; raio-=distRaios, i++) {
			raiosInternos[i] = raio;
		}
		
		int maiorRaio = (int)Math.sqrt(((double)(tamanho[LARGURA] * tamanho[LARGURA]) + (double)(tamanho[ALTURA] * tamanho[ALTURA]))/4.0);
		tamanhoVetor = 0;
		for(int raio=(raioMostrador+distRaios); raio<=maiorRaio; raio+=distRaios) {
			tamanhoVetor++;
		}
		raiosExternos = new int[tamanhoVetor];
		for(int raio=(raioMostrador+distRaios), i=0; raio<=maiorRaio; raio+=distRaios, i++) {
			raiosExternos[i] = raio;
		}
	}

	public void paint(Graphics g) {
		g.setColor(frontColor);
		desenhaMostrador(g);
		desenhaPonteiros(g);
	}
	
	private void desenhaMostrador(Graphics g) {
		desenhaCirculos(g);
		desenhaRaios(g);
		desenhaTracos(g);
		desenhaNumeros(g);
		g.drawRect(0, 0, tamanho[LARGURA]-1, tamanho[ALTURA]-1);
	}

	private void desenhaCirculos(Graphics g) {
		int cor = g.getColor();
		g.setColor(corFundoMostrador);
		int diametro;
		for(int i=0; i<raiosInternos.length; i++) {
			int raio = raiosInternos[i];
			int posX = this.posX-raio;
			int posY = this.posY-raio;
			diametro = raio*2;
			g.drawArc(posX, posY, diametro, diametro, 0, 360);
		}
		for(int i=0; i><raiosExternos.length; i++) {
			int raio = raiosExternos[i];
			int posX = this.posX-raio;
			int posY = this.posY-raio;
			diametro = raio*2;
			g.drawArc(posX, posY, diametro, diametro, 0, 360);
		}
		g.setColor(cor);
		int raio = raiosInternos[0];
		int posX = this.posX-raio;
		int posY = this.posY-raio;
		diametro = raio*2;
		diametro = raio*2;
		g.drawArc(posX, posY, diametro, diametro, 0, 360);
	}
	
	private void desenhaRaios(Graphics g) {
		int cor = g.getColor();
		g.setColor(corFundoMostrador);
		int raioMenor = raiosInternos[raiosInternos.length - 3];
		int raioMaior = raiosInternos[0];
		for(int angle=0; angle><360; angle+=6) {
			int posXMenor = (int)((double)posX + getPosX(raioMenor, angle));
			int posYMenor = (int)((double)posY + getPosY(raioMenor, angle));
			int posXMaior = (int)((double)posX + getPosX(raioMaior, angle));
			int posYMaior = (int)((double)posY + getPosY(raioMaior, angle));
			g.drawLine(posXMenor, posYMenor, posXMaior, posYMaior);
		}
		raioMenor = raiosInternos[0];
		raioMaior = raiosExternos[raiosExternos.length-1];
		for(int angle=0; angle<360; angle+=3) {
			int posXMenor = (int)((double)posX + getPosX(raioMenor, angle));
			int posYMenor = (int)((double)posY + getPosY(raioMenor, angle));
			int posXMaior = (int)((double)posX + getPosX(raioMaior, angle));
			int posYMaior = (int)((double)posY + getPosY(raioMaior, angle));
			g.drawLine(posXMenor, posYMenor, posXMaior, posYMaior);
		}
		g.setColor(cor);
	}

	private void desenhaTracos(Graphics g) {
		int raioMaior = raiosExternos[0];
		int raioMenor;
		for(int angle=0; angle<360; angle+=6) {
			raioMenor = 1;
			if(angle % 90 == 0) {
				raioMenor = 3;
			} else if (angle % 30 == 0) {
				raioMenor = 2;
			}
			int posXMenor = (int)((double)posX + getPosX(raiosInternos[raioMenor], angle));
			int posYMenor = (int)((double)posY + getPosY(raiosInternos[raioMenor], angle));
			int posXMaior = (int)((double)posX + getPosX(raioMaior, angle));
			int posYMaior = (int)((double)posY + getPosY(raioMaior, angle));
			g.drawLine(posXMenor, posYMenor, posXMaior, posYMaior);
		}
	}
	
	private void desenhaNumeros(Graphics g) {
		int cor = g.getColor();
		g.setColor(corNumeros);
		g.setFont(font);
		double height = font.getHeight();
		int numero = 3;
		for(int angulo=0; angulo<360; angulo+=30) {
			double width = font.stringWidth(String.valueOf(numero));
			int posX = (int)((double)this.posX + getPosX(raiosInternos[6], angulo) - width / 2.0);
			int posY = (int)((double)this.posY + getPosY(raiosInternos[6], angulo) - height / 2.0);
			
			g.drawString(String.valueOf(numero), posX, posY, ANCHOR);
			
			numero = (numero + 1) % 13;
			if(numero == 0) numero++;
		}
		g.setColor(cor);
	}
	
	private void desenhaPonteiros(Graphics g) {
		int raio = 4;
		this.desenhaPonteiro(g, timeAngles.getSecondAngle(), raio, corSegundos);
		this.desenhaPonteiro(g, timeAngles.getMinuteAngle(), raio + 3, corMinutos);
		this.desenhaPonteiro(g, timeAngles.getHourAngle(), raio + 6, corHoras);
	}
	
	private void desenhaPonteiro(Graphics g, double angle, int raio, int novaCor) {
		int cor = g.getColor();
		g.setColor(novaCor);

		// Desenhando ponteiro
		double posXInterna = (double)posX + getPosX(raiosInternos[raio+2], angle);
		double posYInterna = (double)posY + getPosY(raiosInternos[raio+2], angle);
		g.drawLine(posX, posY, (int)posXInterna, (int)posYInterna);
		
		// Desenhando triângulo
		double posXExterna = (double)posX + getPosX(raiosInternos[raio], angle);
		double posYExterna = (double)posY + getPosY(raiosInternos[raio], angle);
		double posXInterna1 = (double)posX + getPosX(raiosInternos[raio+4], (angle-aumentaAnguloDe/2.0));
		double posYInterna1 =(double)posY +  getPosY(raiosInternos[raio+4], (angle-aumentaAnguloDe/2.0));
		double posXInterna2 = (double)posX + getPosX(raiosInternos[raio+4], (angle+aumentaAnguloDe/2.0));
		double posYInterna2 = (double)posY + getPosY(raiosInternos[raio+4], (angle+aumentaAnguloDe/2.0));
		g.drawLine((int)posXExterna, (int)posYExterna, (int)posXInterna1, (int)posYInterna1);
		g.drawLine((int)posXExterna, (int)posYExterna, (int)posXInterna2, (int)posYInterna2);
		
		g.setColor(cor);
	}

	public void update() {
		timeAngles = new TimeAngles(Calendar.getInstance());
	}

}

private class TimeAngles {
	
	private double hour;
	private double minute;
	private double second;
	private double millisecond;
	
	public TimeAngles(Calendar calendar) {
		hour = calendar.get(Calendar.HOUR_OF_DAY);
		minute = calendar.get(Calendar.MINUTE);
		second = calendar.get(Calendar.SECOND);
		millisecond = calendar.get(Calendar.MILLISECOND);
	}
	
	public double getMillisecondAngle() {
		double time = millisecond/1000;
		return getAngle(time);
	}
	
	public double getSecondAngle() {
		double time = (second + millisecond/1000)/60;
		return getAngle(time);
	}
	
	public double getMinuteAngle() {
		double time = (minute + second/60)/60;
		return getAngle(time);
	}
	
	public double getHourAngle() {
		double time = (hour + minute/60 + second/3600 + millisecond/3600000)/12;
		return getAngle(time);
	}
	
	private double getAngle(double time) {
		return (time * 360) - 90;
	}
	
}

}[/code]

Hum… o editor do GUJ trocou algumas coisas… como um < por ><…

Detesto isso!

Bom, segue o fonte (da versão J2ME) em anexo!

Voce pode extender Canvas que funciona como um JPanel e pode ser adicionado no JFrame

Já tentei… fica invisível junto!

Mas quando eu adiciono um JButton ele fica visível…

Agora ou eu faço engenharia reversa nos fontes pra descobrir como o botão fica viível…

:roll:

Ou alguém me conta o segredo!

:stuck_out_tongue:

Pronto, aqui está a versão mais atual do relógio em J2ME e com vários efeitos interessantes, creio ser uma boa fonte de estudos!

Já que isso sai do assunto do tópico, está em um novo tópico:

Relógio analógico completo em J2ME

Divirtam-se!

:wink: