Ir para o conteúdo

Calculadora simples

unit uMain;

interface

uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls, GIFImg, ExtCtrls, jpeg;

type
    TfMain = class(TForm)
           imgBack: TImage;
           lcdMem, lcdTotal, lcdOp, lcd, bMp, bMr, bMc, bOff, bSqr, bSqrt, bSign,
           bAC, bDiv, bMulti, bMinus, bPlus, bTotal, bDot, b0, b1, b2, b3, b4,
           b5, b6, b7, b8, b9, lblSimpleCalc, lblSimpleCalcShadow: TLabel;

           procedure KeyClick(Sender: TObject);
           procedure FormCreate(Sender: TObject);
           procedure AC;
           procedure FormKeyPress(Sender: TObject; var Key: Char);
    private
    { Private declarations }
           procedure WMNCHitTest(var Msg: TWMNCHitTest) ; message WM_NCHitTest;
    public
    { Public declarations }
    end;

var
   fMain: TfMain;
   mem:extended=0;


implementation

{$R *.dfm}

procedure TfMain.WMNCHitTest(var Msg: TWMNCHitTest) ;
// Permite arrastar a janela sem que ela tenha uma camption board
// Faz isso caso o rato esteja nos primeiros 200 pixeis de altura ou nos últimos
// 30, indicando ao windows que o rato ainda está na barra de Caption
var
   P: TPoint; // Variável que irá recolher a localização do rato
begin
     inherited;
     if Msg.Result = htClient then begin
                                        GetCursorPos(P); // Guarda em P a localização do rato
                                        // Testa a localização do rato e aje em conformidade
                                        if (P.Y<fmain.Top+200) or (P.Y>fmain.Top+fMain.Height-30) then Msg.Result := htCaption;
                                   end;
end;

procedure TfMain.AC;
// Limpa todos os dados inseridos, excepto a memória
begin
     lcd.Caption:='0';
     lcdOp.Caption:='';
     lcdTotal.Caption:='';
end;

procedure TfMain.FormCreate(Sender: TObject);
begin
     AC; // Limpa o "LCD" para começar
end;

procedure TfMain.FormKeyPress(Sender: TObject; var Key: Char);
// Testa as teclas pressionadas na form fMain. Caso seja uma das teclas conhecidas, chama o botão correspondente
begin
     case key of
          #27:if (lcd.Caption='0') and (lcdOp.Caption='') and (lcdTotal.Caption='') then application.Terminate  // Se o ecrã estiver limpo, a tecla ESC chama o botão OFF
                                                                                    else KeyClick(bAc);         // Se existirem dados, limpa-os
          #13:KeyClick(bTotal);              // A tecla ENTER chama o botão =
          '+':KeyClick(bPlus);               // Chama o botão +
          '-':KeyClick(bMinus);              // Chama o botão -
          '*','x','X':KeyClick(bMulti);      // Chama o botão x
          '/':KeyClick(bDiv);                // Chama o botão ÷
          '.':KeyClick(bDot);                // Chama o botão .
          ' ':KeyClick(bSign);               // Chama o botão ±
          'R','r':KeyClick(bSqrt);           // Chama o botão √
          'Q','q':KeyClick(bSqr);            // Chama o botão x²
          'A','a':KeyClick(bMp);             // Chama o Botão M+
          'V','v':KeyClick(bMr);             // Chama o botão Mr
          'C','c':KeyClick(bMc);             // Chama o botão Mc
     else if CharInSet(Key,['0'..'9']) then KeyClick(FindComponent('b'+Key));
     end;
end;

procedure TfMain.KeyClick(Sender: TObject);
// Executa uma acção, concoante a tecla carregada
var
   Disp:string;   // Guarda temporariamente o valor do LCD
   Sign:Boolean;  // Guarda temporariamente o valor do sinal do valor em LCD
begin
     Disp:=lcd.Caption;  // Guarda em Disp o valor do LCD
     if Sender=bOff then application.Terminate;  // Se a tecla for a OFF, termina o programa
     if Sender=bAC then if Disp<>'0' then Disp:='0'  // Se a tecla for AC e houver um valor no LCD, limpa-o
                                     else AC;        // Se a tecla for AC e o valor em LCD for 0, limpa todos os dados
     if Sender=bSign then if Disp[1]='-' then Delete(Disp,1,1)  // Se a tecla for ±, remove o sinal negativo caso exista...
                                         else Disp:='-'+Disp;   // ... ou insere-o caso não exista
     if Sender=bSqrt then Disp:=FloatToStrF(Sqrt(StrToFloat(Disp)),ffGeneral,9,2);  // Se a tecla for √, troca o valor de LCD pelo da sua raíz quadrada
     if Sender=bSqr then Disp:=FloatToStrF(Sqr(StrToFloat(Disp)),ffGeneral,9,2);  // Se a tecla for x², troca o valor de LCD pelo do seu quadrado
     if Sender=bMp then Mem:=Mem+StrToFloat(lcdTotal.Caption);  // Se a tecla for M+, adiciona o valor de LCD Total ao existente na memória
     if Sender=bMr then Disp:=FloatToStrF(Mem,ffGeneral,9,2);  // Se a tecla for Mr, atribui ao LCD o valor presentemente em memória
     if Sender=bMc then Mem:=0;  // Se a tecla for Mc, limpa a memória
     lcdMem.Visible:=Mem<>0;  // Liga ou desliga o ícone M caso o valor da memória seja diferente de 0

     if (CharInSet((Sender as TLabel).Caption[1],['+','-','x','÷','='])) and ((Sender as TLabel).Caption<>'x²')  // Se a tecla for uma operação ou o sinal = ...
        then begin
                  if lcdTotal.Caption<>'' then case lcdOp.Caption[1] of  // Testa a última operação antes desta, e efectua-a
                                                    '+':lcdTotal.Caption:=FloatToStrF(StrToFloat(lcdTotal.Caption)+StrToFloat(Disp),ffGeneral,7,2);  // Efectua a operação Soma
                                                    '-':lcdTotal.Caption:=FloatToStrF(StrToFloat(lcdTotal.Caption)-StrToFloat(Disp),ffGeneral,7,2);  // Efectua a operação Subtracção
                                                    'x':lcdTotal.Caption:=FloatToStrF(StrToFloat(lcdTotal.Caption)*StrToFloat(Disp),ffGeneral,7,2);  // Efectua a operação Multiplicação
                                                    '÷':if lcd.Caption<>'0' then lcdTotal.Caption:=FloatToStrF(StrToFloat(lcdTotal.Caption)/StrToFloat(Disp),ffGeneral,7,2);  // Efectua a operação Divisão
                                                    '=':if disp<>'0' then lcdTotal.Caption:=Disp;  // Se a última operação foi = (mostrar resultado), e caso não haja um valor novo no LCD, assume o total da última operação como parcela
                                               end
                                          else lcdTotal.Caption:=Disp;  // Se lcdTotal for '' então este é o primeiro valor da operação
                  lcdOp.Caption:=(Sender as TLabel).Caption[1];  // Mostra qual a operação a executar
                  Disp:='0';  // Limpa o LCD de entrada
             end;
     if (Sender as TLabel).Caption[1]='.' then Disp:=Disp+DecimalSeparator;  // Se a tecla for um ponto decimal
     if CharInSet((Sender as TLabel).Caption[1],['0'..'9']) then begin  // Se a tecla for um algarismo
                                                                      Sign:=Disp[1]='-';  // Memoriza se é um valor negativo
                                                                      if Sign then Delete(Disp,1,1);  // Apaga o sinal caso haja (valor negativo)
                                                                      if Disp='0' then Disp:=(Sender as TLabel).Caption[1]  // Se o LCD tiver o valor 0, subsitui pelo valor da tecla pressionada
                                                                                  else Disp:=Disp+(Sender as TLabel).Caption[1];  // Adiciona ao LCD o valor da tecla
                                                                      if Sign then Disp:='-'+Disp;  // Repõe o sinal negativo ao valor, caso fosse esse o sinal inicial
                                                                 end;
     lcd.Caption:=Disp;  // Mostra no LCD o valor encontrado pela operação efectuada
end;
end.