Desenvolvendo uma calculadora com swing

Boa noite pessoal,
:wink:
Antes de mais nada gostaria de agradecer ao guj, tenho aprendido muito nesse fórum. Parabéns a todos! :stuck_out_tongue:

Bem, estudo Java através de alguns livros, como o USE A CABEÇA e o Java, Como programar DEITEL. Aprendi muito até agora…

Na última semana me desafiei a programar uma calculadora em java, utilizando o SWING. Consegui montar toda a interface gráfica, gostaria que vocês avaliassem meu código, procurassem por falhas e pontos a melhorar. Assim como também me ajudassem a terminar minha calculadora de forma eficiente. Juro que era mais fácil quando estudava vb… :lol:

Bem, segue o código abaixo:

Aplicacao.java

public class Aplicacao {
	
	public static void main(String[]args){
		Calc calculadora=new Calc();
		calculadora.setVisible(true);
	}

}

Calc.java

[code]
import java.awt.BorderLayout;

import javax.swing.JFrame;

public class Calc extends JFrame{

private Visor visor;
private Teclado teclado;

public Calc(){	//construtor do frame
	super("Calculadora Simples");
	this.setSize(200,200);
	this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
	this.setResizable(false);
	
	//Acresentando os componentes na calculadora
	visor=new Visor();	//criando um visor
	this.add(visor,BorderLayout.NORTH);
	teclado=new Teclado();	//criando um teclado
	this.add(teclado,BorderLayout.CENTER);
	
	
}

}[/code]

Teclado.java

[code]
import java.awt.GridLayout;

import javax.swing.JPanel;

public class Teclado extends JPanel{

private static final String[] TECLAS={
	"7","8","9","/",
	"4","5","6","*",
	"1","2","3","-",
	"0",".","=","+"
};
private static Botao[] botoes=new Botao[TECLAS.length];


public Teclado(){	//construtor do teclado numérico
	this.setLayout(new GridLayout(4,4));
	
	//adicionando os botões no teclado
	for(int i=0;i<TECLAS.length;i++){
		botoes[i]=new Botao(TECLAS[i]);
		this.add(botoes[i]);
	}
	
	
}

}[/code]


Botao.java

[code]
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;

public class Botao extends JButton {

public Botao(String tc){		//construtor de botão
	super(tc);
	super.addActionListener(new HandlerBotao());
	
}



//classe interna para tratamento de eventos do teclado
private class HandlerBotao implements ActionListener{

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		
	}
}

}[/code]

Visor.java

[code]
import javax.swing.JTextField;

public class Visor extends JTextField{

public Visor(){		//construtor do visor
	this.setEditable(false);
	this.setHorizontalAlignment(RIGHT);
}

}[/code]

Processador.java

[code]
public class Processador {

private static double num1;
private static double num2;
private static double resultado;

}[/code]

A minha idéia foi de programar cada componente da calculadora individualmente, e deixar todas as fórmulas e códigos próprios de uma calculadora na classe Processador… O problema é que acabei travando aqui… Gostaria que vocês avaliassem meu trabalho até então e me dessem dicas para que dentro da orientação a objetos eu continue meu desafio.

Desde já, muito obrigado. :smiley:


Tiago José

Vamos por partes:
No caso da classe Processador acho que vc deve criar o métodos de processarSoma, processarSubtracao, processarDivisao e processarMultiplicacao.
e tambem deve criar interfaces do tipo:

public interface ProcessadorSoma{
  public double processarSoma(double num1, double num2);
}

Isso para cada operação!

Em seguida coloque a classe Processador para implementar todas essas interfaces, e no código quando vc for usar deverá usar a interface especifica para a operação que deseja algo como:

ProcessadorSoma ps = new Processador ();
double resultado = ps.processarSoma(1,1);

Eis o polimorfismo… 8)

Você não precisa criar uma nova classe para o Botão. Só para o Handler do botão. Se quiser também que os botões sejam acionados pelas teclas, leia esse tópico:
http://www.guj.com.br/posts/list/140986.java

[quote=Carlos_ds_jar]Vamos por partes:
No caso da classe Processador acho que vc deve criar o métodos de processarSoma, processarSubtracao, processarDivisao e processarMultiplicacao.
e tambem deve criar interfaces do tipo:

public interface ProcessadorSoma{
  public double processarSoma(double num1, double num2);
}

Isso para cada operação!

Em seguida coloque a classe Processador para implementar todas essas interfaces, e no código quando vc for usar deverá usar a interface especifica para a operação que deseja algo como:

ProcessadorSoma ps = new Processador ();
double resultado = ps.processarSoma(1,1);

Eis o polimorfismo… 8) [/quote]

Obrigado Carlos,

Agora, pensando nos métodos dos processadores, seria mais adequado os definirmos como métodos estáticos? Sendo estáticos ou não, sei que funciona, mas pensando em padrões de desenvolvimento, qual seria mais adequado para esse projeto? :?:

Em 99% dos casos, é melhor não usar métodos estáticos.

Em 99% dos casos, é melhor não usar métodos estáticos.
[/quote]

Boa noite amigos,

Continuando o projetinho da calculadora… Vejam bem:

Eu tenho um objeto Botão e um objeto Visor principalmente. Quando eu clico no Botão, o número correspondente deve aparecer no visor… Tudo bem! Agora tendo que os dois objetos são independentes, como utilizar o método setText de Visor? Será que aqui entraria o 1% de uso dos métodos estáticos. Penso que uma alternativa para esse problema seria criar um método estático em visor que retorna uma instância do objeto previamente criada… Estou certo? :?:

Obrigado :smiley:

Não, não está.

Passe o visor como parâmetro:

[code]public NumeroActionListener extends ActionListener
{
private int numero;
private JTextField visor;

//Recebemos o número que será escrito
//E o visor que receberá o número.
public NumeroActionListener(int numero, JTextField visor) {
    this.visor = visor;
    this.numero = numero;
}    

public void actionPeformed(ActionEvent evt) {
    if (txtVisor.getText().equals("0"))
       txtVisor.setText(Integer.toString(numero));
    else
       txtVisor.setText(txtVisor.getText() + Integer.toString(numero));
}

}[/code]

Depois é só usar assim:

[code]
JTextField txtVisor = new JTextField();

//Note que todos os actionListeners compartilham o mesmo visor.
JButton btnUm = new JButton();
btnUm.addActionListener(new NumeroActionListener(1, txtVisor));

JButton btnDois = new JButton();
btnDois.addActionListener(new NumeroActionListener(2, txtVisor));

JButton btnTres = new JButton();
btnTres.addActionListener(new NumeroActionListener(3, txtVisor));
btnTres.addActionListener(3, txtVisor);[/code]

Variáveis estáticas não devem ser criadas como forma de passagem de parâmetros (como você imaginou). Elas não devem ser criadas só para compartilhar objetos. Elas não devem ser criadas como formas de variáveis globais.

Obirgado Vini…

Mas ainda não entendi porque definitivamente não posso usar métodos estáticos… Seria porque o código fica mais procedural que orientado a objetos? Em qual momento de fato o seu uso é aceito?

Uma das situações para métodos estáticos são os métodos fábrica.

Por exemplo, considere a seguinte classe para vetores matemáticos em 2D:

[code]public class Vector2D {
private float x;
private float y;

public Vector2D(float x, float y) {
this.x = x;
this.y = y;
}
//Aqui viriam métodos para somar dois vetores, calcular o tamanho, etc.
}[/code]

Agora suponha que você queira outro construtor, para criar um vetor baseado num ângulo e num tamanho. Mas esses dois atributos também são float. Como você faz?

Como o construtor com 2 floats já foi usado para outra coisa, você usa um método estático:

[code]public class Vector2D {
private float x;
private float y;

public Vector2D(float x, float y) {
this.x = x;
this.y = y;
}

public static Vector2D createBySizeAndAngle(float size, float angle) {
return new Vector2D(Math.cos(angle) * size, Math.sin(angle) * size);
}
}[/code]

E isso permite que seu usuário faça:

Vector2D v1 = new Vector2D(10, 20); //Valores de x e y Vector2D v2 = Vector2D.createBySizeAndAngle(10, Math.toRadians(45)); //Tamanho 10, inclinado em 45º

Além de tornar o código mais procedural, métodos estáticos tem outros problemas, como ter pior desempenho do que os não estáticos em aplicativos multi-thread, não poderem ser sobrepostos (lembre-se, polimorfismo é um atributo de objetos, não de classes).

Quanto a propriedades estáticas. O problema é que elas nunca saem de escopo e são difíceis de sincronizar em ambientes multi-thread. Por isso, elas são as grandes responsáveis por vazamentos de memória, como ocorreu com o colega nesse tópico e por inconsistências de dados.