Calculadora en Win API no imprime el resultado

Iniciado por Alien-Z, 11 Septiembre 2011, 18:33 PM

0 Miembros y 1 Visitante están viendo este tema.

Alien-Z

Buenas, en mis avances con la API de windows he conseguido hacer una calculadora muy básica con interfaz, sin embargo no me imprime el resultado, asi que después de varios días dándole vueltas y de habérselo planteado a un par de conocidos que no han encontrado el fallo lo posteo aqui:

Código (cpp) [Seleccionar]
#include <windows.h>
#include <stdio.h>
#include <string.h>

//ID´s
enum {ID_LABEL, ID_EDIT, ID_BOTONIGUAL, ID_BOTONSUMAR, ID_BOTONRESTAR, ID_BOTONMULTIPLICAR, ID_BOTONDIVIDIR, ID_BOTONCOMA, ID_BOTONSIGNO, ID_BOTONCERO, ID_BOTON1, ID_BOTON2, ID_BOTON3, ID_BOTON4, ID_BOTON5, ID_BOTON6, ID_BOTON7, ID_BOTON8, ID_BOTON9};


//Prototipos
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

void imprimirEdit (int i);                                                  //Funcion que concatena los numeros al hacer clic en los botones
double calcular (double primer_num, double segundo_num, int operacion);     //Funcion que realiza las operaciones

HINSTANCE estancia;
HWND label;
HWND edit;
//Botones->Numeros
HWND boton1;
HWND boton2;
HWND boton3;
HWND boton4;
HWND boton5;
HWND boton6;
HWND boton7;
HWND boton8;
HWND boton9;
HWND boton0;
HWND botonComa;
HWND botonSigno;
//Botones->Operadores
HWND botonIgual;
HWND botonSumar;
HWND botonRestar;
HWND botonMultiplicar;
HWND botonDividir;



/*  Make the class name into a global variable  */
char szClassName[ ] = "CodeBlocksWindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nCmdShow)
{
   HWND hwnd;               /* This is the handle for our window */
   MSG messages;            /* Here messages to the application are saved */
   WNDCLASSEX wincl;        /* Data structure for the windowclass */

   estancia = hThisInstance;

   /* The Window structure */
   wincl.hInstance = hThisInstance;
   wincl.lpszClassName = szClassName;
   wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
   wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
   wincl.cbSize = sizeof (WNDCLASSEX);

   /* Use default icon and mouse-pointer */
   wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
   wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
   wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
   wincl.lpszMenuName = NULL;                 /* No menu */
   wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
   wincl.cbWndExtra = 0;                      /* structure or the window instance */
   /* Use Windows's default colour as the background of the window */
   wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

   /* Register the window class, and if it fails quit the program */
   if (!RegisterClassEx (&wincl))
       return 0;

   /* The class is registered, let's create the program*/
   hwnd = CreateWindowEx (
          0,                   /* Extended possibilites for variation */
          szClassName,         /* Classname */
          "Calculadora",       /* Title Text */
          WS_OVERLAPPEDWINDOW, /* default window */
          CW_USEDEFAULT,       /* Windows decides the position */
          CW_USEDEFAULT,       /* where the window ends up on the screen */
          544,                 /* The programs width */
          375,                 /* and height in pixels */
          HWND_DESKTOP,        /* The window is a child-window to desktop */
          NULL,                /* No menu */
          hThisInstance,       /* Program Instance handler */
          NULL                 /* No Window Creation data */
          );

   /* Make the window visible on the screen */
   ShowWindow (hwnd, nCmdShow);

   /* Run the message loop. It will run until GetMessage() returns 0 */
   while (GetMessage (&messages, NULL, 0, 0))
   {
       /* Translate virtual-key messages into character messages */
       TranslateMessage(&messages);
       /* Send message to WindowProcedure */
       DispatchMessage(&messages);
   }

   /* The program return-value is 0 - The value that PostQuitMessage() gave */
   return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   //Variables
   char cadenaEditMain [35];
   static int operacion;
   static double primer_num, segundo_num, resultado;

   PAINTSTRUCT ps;
   HDC hdc;


   switch (message)
   {
       case WM_CREATE:
       {
           label = CreateWindow ("Static","Texto", WS_CHILD | WS_VISIBLE, 20, 20, 175, 25, hwnd, 0, estancia, 0);
           edit = CreateWindowEx (WS_EX_CLIENTEDGE, "edit", 0, ES_RIGHT | ES_NUMBER | WS_BORDER | WS_CHILD | WS_VISIBLE, 20, 50, 175, 25, hwnd, (HMENU)ID_EDIT, estancia, 0);

           boton1 = CreateWindow ("Button", "1", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 20, 90, 40, 25, hwnd, (HMENU) ID_BOTON1, estancia, 0);
           boton2 = CreateWindow ("Button", "2", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 65, 90, 40, 25, hwnd, (HMENU) ID_BOTON2, estancia, 0);
           boton3 = CreateWindow ("Button", "3", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 90, 40, 25, hwnd, (HMENU) ID_BOTON3, estancia, 0);
           boton4 = CreateWindow ("Button", "4", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 20, 120, 40, 25, hwnd, (HMENU) ID_BOTON4, estancia, 0);
           boton5 = CreateWindow ("Button", "5", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 65, 120, 40, 25, hwnd, (HMENU) ID_BOTON5, estancia, 0);
           boton6 = CreateWindow ("Button", "6", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 120, 40, 25, hwnd, (HMENU) ID_BOTON6, estancia, 0);
           boton7 = CreateWindow ("Button", "7", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 20, 150, 40, 25, hwnd, (HMENU) ID_BOTON7, estancia, 0);
           boton8 = CreateWindow ("Button", "8", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 65, 150, 40, 25, hwnd, (HMENU) ID_BOTON8, estancia, 0);
           boton9 = CreateWindow ("Button", "9", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 150, 40, 25, hwnd, (HMENU) ID_BOTON9, estancia, 0);
           boton0 = CreateWindow ("Button", "0", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 20, 180, 40, 25, hwnd, (HMENU) ID_BOTONCERO, estancia, 0);
           botonComa = CreateWindow ("Button", ",", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 65, 180, 40, 25, hwnd, (HMENU) ID_BOTONCOMA, estancia, 0);
           botonSigno = CreateWindow ("Button", "+/-", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 180, 40, 25, hwnd, (HMENU) ID_BOTONSIGNO, estancia, 0);
           botonSumar = CreateWindow ("Button", "+", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 165, 90, 40, 25, hwnd, (HMENU) ID_BOTONSUMAR, estancia, 0);
           botonRestar = CreateWindow ("Button", "-", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 165, 120, 40, 25, hwnd, (HMENU) ID_BOTONRESTAR, estancia, 0);
           botonMultiplicar = CreateWindow ("Button", "*", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 165, 150, 40, 25, hwnd, (HMENU) ID_BOTONMULTIPLICAR, estancia, 0);
           botonDividir = CreateWindow ("Button", "/", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 165, 180, 40, 25, hwnd, (HMENU) ID_BOTONDIVIDIR, estancia, 0);
           botonIgual = CreateWindow ("Button", "=", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 20, 220, 40, 25, hwnd, (HMENU) ID_BOTONIGUAL, estancia, 0);
       }

       case WM_PAINT:
       {
           hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
       }

       case WM_COMMAND:
       {
           switch (wParam)
           {
               case ID_BOTON1:                  //Al presionar el boton 1 se llama a la funcion "imprimirEdit" y se le envia el valor "1" que es lo que queremos que se concatene a lo que ya haya en el edit
               {
                   imprimirEdit (1);
                   break;
               }
               case ID_BOTON2:
               {
                   imprimirEdit (2);
                   break;
               }
               case ID_BOTON3:
               {
                   imprimirEdit (3);
                   break;
               }
               case ID_BOTON4:
               {
                   imprimirEdit(4);
                   break;
               }
               case ID_BOTON5:
               {
                   imprimirEdit(5);
                   break;
               }
               case ID_BOTON6:
               {
                   imprimirEdit(6);
                   break;
               }
               case ID_BOTON7:
               {
                   imprimirEdit(7);
                   break;
               }
               case ID_BOTON8:
               {
                   imprimirEdit(8);
                   break;
               }
               case ID_BOTON9:
               {
                   imprimirEdit(9);
                   break;
               }
               case ID_BOTONCERO:
               {
                   imprimirEdit(0);
                   break;
               }
               case ID_BOTONCOMA:
               {
                   break;
               }
               case ID_BOTONSUMAR:
               {
                   operacion = 1;                                    //Cambia el valor de "operacion" para indicar que se va a sumar
                   GetWindowText (edit, cadenaEditMain, 34);         //Obtiene el numero ingresado en el edit
                   primer_num = atof (cadenaEditMain);               //Transforma la cadena obtenida en un double y lo guarda en "primer_num"
                   SetWindowText (edit, "");                         //Limpia el edit
                   break;
               }
               case ID_BOTONRESTAR:
               {
                   operacion = 2;                                    //Cambia el valor de "operacion" para indicar que se va a restar
                   GetWindowText (edit, cadenaEditMain, 34);
                   primer_num = atof (cadenaEditMain);
                   SetWindowText (edit, "");
                   break;
               }
               case ID_BOTONMULTIPLICAR:
               {
                   operacion = 3;                                    //Cambia el valor de "operacion" para indicar que se va a multiplicar
                   GetWindowText (edit, cadenaEditMain, 34);
                   primer_num = atof (cadenaEditMain);
                   SetWindowText (edit, "");
                   break;
               }
               case ID_BOTONDIVIDIR:
               {
                   operacion = 4;                                    //Cambia el valor de "operacion" para indicar que se va a dividir
                   GetWindowText (edit, cadenaEditMain, 34);
                   primer_num = atof (cadenaEditMain);
                   SetWindowText (edit, "");
                   break;
               }
               case ID_BOTONIGUAL:
               {
                   GetWindowText (edit, cadenaEditMain, 34);         //Obtiene el numero ingresado en el edit
                   segundo_num = atof (cadenaEditMain);              //Transforma la cadena obtenida en un double y lo guarda en "segundo_num"
                   resultado = calcular (primer_num, segundo_num, operacion); //El resultado se obtiene apartir de la funcion "calcular", a esta funcion se le envian las variables "primer_num", "segundo_num" y "operacion"
                   sprintf (cadenaEditMain, "%f", resultado);        //Se transforma el double obtenido en una cadena y se guarda en "cadenaEditMain"
                   SetWindowText (edit, cadenaEditMain);             //Se imprime en el edit la cadena donde se encuentra el resultado
                   break;
               }

               break;
           }
           break;
       }

       case WM_DESTROY:
           PostQuitMessage (0);
           break;
       default:
           return DefWindowProc (hwnd, message, wParam, lParam);
   }

   return 0;
}

void imprimirEdit (int i)                        //Funcion que concatena los numeros al hacer clic en los botones
{
   char cadenaEdit [35];                        //Variable donde se guardara lo que hay en el edit (no es la misma variable que cadenaEditMain)
   char numero [2];                             //Variable donde se guardara el numero de la tecla presionada
   sprintf (numero, "%i", i);                   //Se transforma el numero (i) del tipo entero a una cadena

   GetWindowText (edit, cadenaEdit, 34);        //Se obtiene lo que hay en el edit y se guarda en "CadenaEdit"
   strcat (cadenaEdit, numero);                 //Se une lo que hay en "CadenaEdit" y lo que hay en "numero" (es decir, se une lo que habia en el edit y el numero de la tecla presionada) y se queda guardada la nueva cifra en "cadenaEdit"
   SetWindowText (edit, cadenaEdit);            //Se imprime el nuevo numero en el edit
}

double calcular (double primer_num, double segundo_num, int operacion)   //Funcion que realiza las operaciones
{
   double resultado;                                                    //Variable donde se guardara el resultado (sera lo que se retorne)

   switch (operacion)                                                   //Ver lo que hay en la variable "operacion"
   {
       case 1:                                                          //En caso de que sea "1" se suma el primer numero al segundo
       {
           resultado = primer_num + segundo_num;
           break;
       }
       case 2:                                                          //En caso de que sea "2" se resta el primer numero al segundo
       {
           resultado = primer_num - segundo_num;
           break;
       }
       case 3:                                                          //En caso de que sea "3" se multiplica el primer numero por el segundo
       {
           resultado = primer_num * segundo_num;
           break;
       }
       case 4:                                                          //En caso de que sea "4" se divide el primer numero entre el segundo
       {
           resultado = primer_num / segundo_num;
           break;
       }
       default:                                                         //Si no se realiza ninguna operacion se imprime en el edit un mensaje, con esto sabriamos si ha habido algun error
       {
           SetWindowText (edit, "No se ha realizado ninguna operacion.");
           break;
       }
   }

   return resultado;                                                    //Devuelve el resultado
}


El fallo está en que al darle al signo igual, en vez de imprimir el resultado, manda el segundo número introducido. Todas las funciones y procesos van comentados.

Gracias por adelantado, saludos.

EDITO: El code está corregido, le faltan cosas como borrar números, limpiar el edit o cambiar de signo, pero lo que lleva por ahora funciona bien.

Eternal Idol

El propio VC++ te indica el problema al compilar:
.cpp(248) : warning C4700: uninitialized local variable 'operacion' used
.cpp(248) : warning C4700: uninitialized local variable 'primer_num' used


Esas variables son LOCALES a la funcion WindowProcedure, es decir que su ambito es la ejecucion de la funcion, cada vez que se ejecute se inicializara con un valor indeterminado y este se perdera al terminar la funcion.

Podes agregarle static antes de las variables o sacarlas fuera de la funcion, asi su ambito se convierte en global.
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

Alien-Z

Cita de: Eternal Idol en 11 Septiembre 2011, 19:08 PM
El propio VC++ te indica el problema al compilar:
.cpp(248) : warning C4700: uninitialized local variable 'operacion' used
.cpp(248) : warning C4700: uninitialized local variable 'primer_num' used


Esas variables son LOCALES a la funcion WindowProcedure, es decir que su ambito es la ejecucion de la funcion, cada vez que se ejecute se inicializara con un valor indeterminado y este se perdera al terminar la funcion.

Podes agregarle static antes de las variables o sacarlas fuera de la funcion, asi su ambito se convierte en global.

Correcto, ya va a la perfección, en Code::Blocks no me avisa del fallo pero estás en lo cierto. Corrijo el code del primer post por si le sirve a alguien.

Gracias por tu tiempo. Saludos.

Eternal Idol

La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

Alien-Z

#4
Aprovecho el mismo tema para preguntar otra cosilla:

Como he comentado uso Code::Blocks para compilar, y dentro del proyecto (en la carpeta bin/debug) me deja el exe de la aplicación. El caso es que he pasado este exe a otro PC con Windows 7 (el PC con el que he compilado la aplicación lleva Windows XP), cuando le doy doble clic se ejecuta, pero faltan algunos botones y no realiza las operaciones.

Supongo que será algo sobre la compatibilidad pero el code solo lleva C++ con Win API con lo cual debería funcionar en cualquier SO de Microsoft. Otra cosa que se me ha ocurrido es que en el exe no vayan incluidas las librerías, entonces si en el otro PC no tengo dichas librerías no va a funcionar (¿cuál sería la solución en este caso?, la idea es que vaya bien en cualquier PC sin necesidad de instalar el compilador con las librerías).

Pero bueno solo son suposiciones mias, a ver si alguien puede aclararme a qué se debe que si me vaya en un Windows XP (el que he usado para compilar) y no en un Windows 7 (no lleva ningún IDE o compilador).

Gracias por adelantado. Saludos.

Eternal Idol

Yo lo probe en Windows 7 asi que no te sabria decir pero igual siempre tenes que usar la version de Release para distribuir.
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

Alien-Z

Cita de: Eternal Idol en 12 Septiembre 2011, 11:22 AM
Yo lo probe en Windows 7 asi que no te sabria decir pero igual siempre tenes que usar la version de Release para distribuir.

Vaya, me ha funcionado con la versión Release, aunque no entiendo por qué si en principio va el mismo code que en Debug.

Gracias de nuevo. Saludos.