Sunday, March 15, 2015

Continuação: Calculadora com interface gráfica!

Continuando com a atividade de anteontem, hoje implementei os métodos para as funções da calculadora, bem como o funcionamento dos botões. Alguns problemas ainda podem ser vistos por causa da transformação entre string e double da calculadora, por isso vou listar alguns detalhes que poderiam ser melhorados:
  • A função +/- inclui o sinal do negativo à direita do número. Poderia usar a excessão que usei na função getResult para resolver a estética, mas então seria impossível usar o número com as outras funções (pois a conversão de string para double supõe aquela posição do sinal negativo). Então esse detalhe foi ignorado para permitir a funcionalidade da calculadora.
  • Quando se aperta o botão ".", o visor mostra os números de forma errada. Ainda é um mistério para mim o porquê da chamada display.append("."); colocar o ponto antes dos números. Funcionalmente, no entanto, está tudo perfeito, e o resultado sempre é imprimido de maneira correta.
  • Contas com inteiros sempre contém casas decimais, por causa da conversão para double. Isso pode ser consertado facilmente, mas não achei necessário para o exercício.
Para que os leitores possam rodar o código com mais facilidade, postarei todo o projeto. As partes modificadas desde sexta-feira são dentro da função actionPerformed, mais todas as funções à partir da clear.

1:  package calculator;  
2:  import java.awt.*;  
3:  import javax.swing.*;  
4:  import java.awt.event.*;  
5:   //@author Gabriel  
6:  public class Calculator extends JFrame implements ActionListener{  
7:    //Declarando variáveis  
8:    JPanel[] row = new JPanel[5];  
9:    JButton[] button = new JButton[19];  
10:  //colocando todas as strings em um único vetor  
11:    String[] buttonString = {"7","8","9","+",   
12:       "4","5","6","-",   
13:       "1","2","3","*",  
14:       ".","/","C","sqrt",  
15:       "+/-","=","0"};  
16:    //Definindo tamanho do display e botões  
17:    Dimension displayDimension = new Dimension(300, 35);  
18:    Dimension regularDimension = new Dimension(45, 40);  
19:    Dimension rColumnDimension = new Dimension(60, 40);  
20:    Dimension zeroButtonDimension = new Dimension(90, 40);  
21:    boolean[] function = new boolean[4]; //vetor para armazenar a função pedida pelo usuário  
22:    double[] temporary = {0,0}; //variáveis auxiliares para calcular resultados  
23:    JTextArea display = new JTextArea(1,20);  
24:    boolean decimal = false; //para garantir que a função "." não possa ser inserida mais de uma vez  
25:    public static void main(String[] args)  
26:    {  
27:      Calculator c = new Calculator();   
28:    }  
29:    Calculator()  
30:    {  
31:      //o tutorial não explica a necessidade dessa função super. No entanto, procurando na internet, parece que  
32:      //ela é responsável por invocar o construtor pai  
33:      //super("Calculator");  
34:      setDesign();  
35:      setSize(380,250);  
36:      setResizable(false); //se o windows não deixa ajustar o tamanho da calculadora, por que eu iria?  
37:      setDefaultCloseOperation(EXIT_ON_CLOSE);  
38:      //Como vou querer 5 linhas e 5 colunas  
39:      GridLayout grid = new GridLayout(5,5);  
40:      setLayout(grid);  
41:      //inicializando o vetor de funções  
42:      for(int i=0;i<4 br="" i="">        function[i] = false;  
43:      FlowLayout f1 = new FlowLayout(FlowLayout.CENTER); //utilizamos a função FlowLayout para posicionar as colunas e linhas  
44:      FlowLayout f2 = new FlowLayout(FlowLayout.CENTER,1,1); //1,1 são os espaçamentos horizontais e verticais em relação a f1  
45:      for(int i=0; i<5 br="" i="">        row[i] = new JPanel();  
46:      row[0].setLayout(f1);  
47:      for(int i = 1; i<5 br="" i="">        row[i].setLayout(f2);  
48:      //agora as linhas e colunas já podem ser usadas!  
49:      for(int i = 0; i < 19; i++) //coloca as características dos botões  
50:      {  
51:        button[i] = new JButton();  
52:        button[i].setText(buttonString[i]);  
53:        button[i].addActionListener((ActionListener) this); //será usado para implementação do funcionamento do botão no futuro  
54:      }  
55:      display.setEditable(false); //não seria bom permitir o usuário editar o display  
56:      display.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); //Por alguma razão desconhecida por mim, calculadoras geralmente tem o display escrevendo da direita para a esquerda  
57:      //definindo tamanhos!  
58:      display.setPreferredSize(displayDimension);  
59:      for(int i = 0; i < 14; i++)  
60:        button[i].setPreferredSize(regularDimension);  
61:      for(int i = 14; i < 18; i++)  
62:        button[i].setPreferredSize(rColumnDimension);  
63:      button[18].setPreferredSize(zeroButtonDimension);  
64:      //colocando o display e os botões nas linhas e colunas  
65:      row[0].add(display);  
66:      add(row[0]);  
67:      for(int i = 0; i < 4; i++)  
68:        row[1].add(button[i]);  
69:      row[1].add(button[14]);  
70:      add(row[1]);  
71:      for(int i = 4; i < 8; i++)  
72:        row[2].add(button[i]);  
73:      row[2].add(button[15]);  
74:      add(row[2]);  
75:      for(int i = 8; i < 12; i++)  
76:        row[3].add(button[i]);  
77:      row[3].add(button[16]);  
78:      add(row[3]);  
79:      row[4].add(button[18]);  
80:      for(int i = 12; i < 14; i++)  
81:        row[4].add(button[i]);  
82:      row[4].add(button[17]);  
83:      add(row[4]);  
84:      setVisible(true);  
85:    }  
86:    //necessário para possibilitar a compilação  
87:    public final void setDesign() {  
88:      try {  
89:        UIManager.setLookAndFeel(  
90:            "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");  
91:      } catch(Exception e) {   
92:      }  
93:    }  
94:   public void actionPerformed(ActionEvent ae)  
95:   {  
96:    if(ae.getSource() == button[0]) //7  
97:      display.append("7");  
98:    if(ae.getSource() == button[1]) //8  
99:      display.append("8");  
100:    if(ae.getSource() == button[2]) //9  
101:      display.append("9");  
102:    if(ae.getSource() == button[3]) //Soma  
103:    {  
104:      temporary[0] = Double.parseDouble(display.getText());  
105:      for(int i = 0; i < 4; i++) //Para evitar conflito quando multiplas teclas de função são apertadas  
106:        function[i] = false;  
107:      function[0] = true;  
108:      decimal = false;  
109:      display.setText("");  
110:    }  
111:    if(ae.getSource() == button[4]) //4  
112:      display.append("4");  
113:    if(ae.getSource() == button[5]) //5  
114:      display.append("5");  
115:    if(ae.getSource() == button[6]) //6  
116:      display.append("6");  
117:    if(ae.getSource() == button[7]) //Subtração  
118:    {  
119:      temporary[0] = Double.parseDouble(display.getText());  
120:      for(int i = 0; i < 4; i++)  
121:        function[i] = false;  
122:      function[1] = true;  
123:      decimal = false;  
124:      display.setText("");  
125:    }  
126:    if(ae.getSource() == button[8]) //1  
127:      display.append("1");  
128:    if(ae.getSource() == button[9]) //2  
129:      display.append("2");  
130:    if(ae.getSource() == button[10]) //3  
131:      display.append("3");  
132:    if(ae.getSource() == button[11]) //Multiplicação  
133:    {  
134:      temporary[0] = Double.parseDouble(display.getText());  
135:      for(int i = 0; i < 4; i++)  
136:        function[i] = false;  
137:      function[2] = true;  
138:      decimal = false;  
139:      display.setText("");  
140:    }  
141:    if(ae.getSource() == button[12]) //Decimal  
142:    {  
143:      if(!decimal)  
144:      {  
145:        decimal = true;  
146:        display.append(".");  
147:      }  
148:    }  
149:    if(ae.getSource() == button[13]) //Divisão  
150:    {  
151:      temporary[0] = Double.parseDouble(display.getText());  
152:      for(int i = 0; i < 4; i++)  
153:        function[i] = false;  
154:      function[3] = true;  
155:      decimal = false;  
156:      display.setText("");  
157:    }  
158:    if(ae.getSource() == button[14]) //C  
159:      clear();  
160:    if(ae.getSource() == button[15]) //Sqrt  
161:      getSqrt();  
162:    if(ae.getSource() == button[16]) //+/-  
163:      getPosNeg();  
164:    if(ae.getSource() == button[17]) //=  
165:      getResult();  
166:    if(ae.getSource() == button[18]) //0  
167:      display.append("0");  
168:  }  
169:    //Agora, para implementar o funcionamento dos botões, vou criar diversos métodos  
170:    //Para limpar a tela e resetar a calculadora  
171:    public void clear() {  
172:      try  
173:      {  
174:        display.setText(""); // Apaga o visor  
175:        for(int i = 0; i < 4; i++)  
176:          function[i] = false; // Reseta o estado de todas as funções  
177:        for(int i = 0; i < 2; i++)  
178:          temporary[i] = 0; // Apaga as variáveis auxiliares  
179:        decimal = false;  
180:      } catch(NullPointerException e) {   
181:      }  
182:    }  
183:    //Para calcular a raiz quadrada  
184:    public void getSqrt() {  
185:      try {  
186:        double value = Math.sqrt(Double.parseDouble(display.getText())); //Cria uma variável (double) e calcula a raiz do display usando a biblioteca math  
187:        display.setText(Double.toString(value)); //Modifica o valor do display  
188:      } catch(NumberFormatException e) {  
189:    }  
190:    }  
191:    //Para o botão +/-  
192:    public void getPosNeg() {  
193:      try {  
194:        double value = Double.parseDouble(display.getText()); //Cria a variável (por simplicidade)  
195:        value = value * (-1);//Não é necessário se preocupar com o zero por (-1)*0 = 0  
196:        display.setText(Double.toString(value));//Escreve o resultado  
197:      } catch(NumberFormatException e) {  
198:    }  
199:    }  
200:    public void getResult() {  
201:      double result = 0;  
202:      temporary[1] = Double.parseDouble(display.getText());  
203:      String temp0 = Double.toString(temporary[0]); //Duas variáveis necessárias para a conversão string -> double dos dois números  
204:      String temp1 = Double.toString(temporary[1]);  
205:      try {  
206:        if(temp0.contains("-")) { //Se o número é negativo  
207:          String[] temp00 = temp0.split("-", 2); //Divide a string em dois  
208:          temporary[0] = (Double.parseDouble(temp00[1]) * -1); //Transforma em double como negativo  
209:        }  
210:        if(temp1.contains("-")) { //Analogamente  
211:          String[] temp11 = temp1.split("-", 2);  
212:          temporary[1] = (Double.parseDouble(temp11[1]) * -1);  
213:        }  
214:      } catch(ArrayIndexOutOfBoundsException e) {  
215:      }  
216:      try {  
217:        if(function[2]) //Multiplicação  
218:          result = temporary[0] * temporary[1];  
219:        else if(function[3]) //Divisão  
220:          result = temporary[0] / temporary[1];  
221:        else if(function[0]) //Soma  
222:          result = temporary[0] + temporary[1];  
223:        else if(function[1]) //Subtração  
224:          result = temporary[0] - temporary[1];  
225:        if(result>=0) //Imprime resultado  
226:          display.setText(Double.toString(result));  
227:        else //evita um bug com o sinal negativo aparecendo depois do número  
228:        {  
229:          display.setText(Double.toString((-1)*result));  
230:          display.append("-");  
231:        }  
232:        for(int i = 0; i < 4; i++)  
233:          function[i] = false; //Reseta variáveis de função  
234:        decimal = false;  
235:      } catch(NumberFormatException e) {  
236:      }  
237:    }  
238:  }  


Cuidado apenas na hora de copiar e colar o código em um IDE, pois a formatação pode ter sido modificada pelo código html do blog. Vou incluir uma animação da calculadora funcionando para os menos interessados em programação.




Obrigado, até o próximo projeto!

1 comment:

  1. A apresentação do blog está ok. Poderia ser mais didático na apresentação do código. Exibir todo o código é dificil de ser entendido. Apresente as partes que mostrem informações interessantes e um esquema geral do programa. O código pode residir em um site externo.

    ReplyDelete