Enero 16, 2018, 04:11:23 am

Autor Tema: Tutorial de uso de apis de windows para crear un entorno grafico  (Leído 41942 veces)

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

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Voy a empezar este tutorial, y si les gusta y quieren seguirlo lo continuo.


Antes que nada quiero aclarar que no voy a usar achivos de recursos para crear las ventanas o menus, voy a usar solo funciones. Si llego a usar recursos sera solo para cosas como agregarle un icono al programa.

Ahora, ¿Por que usar las apis de windows?, les voy a decir algunas de sus ventajas:
 -El ejecutable sale mas liviano (en tamaño).
 -No necesitan instalar ninguna libreria especial para el compilador.
 -Si las saben manejar sabran mas sobre como maneja windows las ventanas.
 -Al usar apis su programa sera muy probablemente mas ligero para la RAM y la CPU.

Para seguir este tutorial lo unico que van a necesitar es un compilador de c++ y windows como SO. Yo recomiendo que usen el Code::Blocks como IDE y MinGW como compilador (viene por defecto) porque es el que voy a usar yo durante el tutorial.


EMPECEMOS !!!

Primero vamos a crear un proyecto de tipo "Win32 GUI Project", para eso hay que ir a File->New->Project...->Win32 GUI Project, y seguimos los pasos que nos va pidiendo el asistente.
Para los que no usen Code::Block busquen en su IDE como empezar un proyecto de este tipo, y si no saben que hacer simplemente creen un proyecto en blanco, copien el codigo que les dejo a continuacion y modifiquen el tipo dee proyecto por "Win32 GUI Project".

Al hacer esto nos va a salir el siguiente codigo:
Código: You are not allowed to view links. Register or Login
#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  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 */

    /* 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 */
           "Code::Blocks Template Windows App",       /* 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)
{
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

Parece muy complicado al principio, pero la verdad es que no lo es. Y lo mejor de todo es que la mayoria de las cosas no hace falta entenderlas.

El ejecutar ese codigo nos tendria que salir esta ventana:

Voy a explicar lo mas importante:

Código: You are not allowed to view links. Register or Login
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);Aqui se define la funcion WindowProcedure (podemos cambiarle el nombre, pero yo no lo haria), con la cual vamos a manejar nuestra ventana, eso lo veremos luego.

Código: You are not allowed to view links. Register or Login
char szClassName[ ] = "CodeBlocksWindowsApp";Se guarda el nombre que va a tener la clase de nuestra ventana, pueden ponerle lo que quieran, el usuario probablemente nunca se entere de este nombre.

Código: You are not allowed to view links. Register or Login
int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
Esta es la funcion equivalente al main en nuestros programas habituales. De los argumentos el unico que nos podria interesar por ahora es lpszArgument, en el que se guarda la linea de comandos con la que se ejecuto nuestro programa. Luego explico el resto.

Código: You are not allowed to view links. Register or Login
   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 */
Se define primero la variable en la que se va a guardar el handle de la ventana, luego la variable que va a tener los mensajes de nuestra aplicacion y por ultimo la clase de nuestra ventana. (Todo esto es poco importante, ocupense de esto mas tarde si tienen ganas).

Código: You are not allowed to view links. Register or Login
   /* 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;
Aqui se carga la clase de nuestra ventana. Por ahora vamos a dejar todo asi, pero luego les voy a explicar que podemos modificar con esto (y como se hace) (cosas como el color de fondo de la ventana y su icono).

Código: You are not allowed to view links. Register or Login
   if (!RegisterClassEx (&wincl))
        return 0;
Se registra la clase (solo hace falta saber que esto es necesario para que el programa funcione).

Código: You are not allowed to view links. Register or Login
   hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Code::Blocks Template Windows App",       /* 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 */
           );
Aqui se crea la ventana y se guarda su handle (manejador) en hwnd. Lo que podria resaltar aqui es que "Code::Blocks Template Windows App" sera el titulo de la ventana y 544/375 seran su largo y su ancho.

Código: You are not allowed to view links. Register or Login
ShowWindow (hwnd, nCmdShow);Esto sirve para mostrar la ventana (ya fue creada, pero aun no podemos verla).

Código: You are not allowed to view links. Register or Login
   /* 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;
Aqui se manejan los mensajes, ya no nos preocupamos por nada aqui.

Código: You are not allowed to view links. Register or Login
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Esta es la funcion que definimos arriba, con la cual manejamos los eventos de la ventana. Ahora solo nos ocupamos del evento WM_DESTROY, que es cuando se cierra la ventana.




Bueno, hasta aqui llega la primera parte del tutorial. Tal vez les paresca algo complicada, pero creo que las siguientes partes del tutorial (si las hago) van a ser mas sencillas.
Si van a seguir el tutorial por favor comenten o algo, para que asi yo pueda saber si tiene sentido o no.

 :cura:
« Última modificación: Enero 06, 2011, 09:29:03 am por .xAk. »
You are not allowed to view links. Register or Login
por ejemplo, se habla de emprender la You are not allowed to view links. Register or Login con el "fusil de carne" y se insta a una mujer a introducir You are not allowed to view links. Register or Login en su You are not allowed to view links. Register or Login

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #1 en: Enero 08, 2010, 06:08:24 am »
En esta nueva parte del tutorial voy a mostrar como se añaden menus a las ventanas y como se manejan sus eventos. Para saber si las cosas salieron o no como queriamos vamos a utilizar la funcion MessageBox, la cual no sirve para modificar el diseño de nustra ventana, asi que voy a explicarla en esta introduccion.

MessageBox (atiendan las mayusculas) tambien forma parte de las apis de windows y sirve para mostrar un mensaje en la pantalla. Su prototipo es este:
Código: You are not allowed to view links. Register or Login
int MessageBox(      
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType
);

Y un ejemplo de su uso seria este:
Código: You are not allowed to view links. Register or Login
MessageBox(NULL, "Mi mensage", "El titulo", MB_OK);En donde puse NULL va el handle de la ventana que llama a la funcion, pero si nos da flojera podemos ponerle NULL (ó 0) y ya.
En donde puse "Mi mensage" va el mensaje que queremos que nos muestre.
En "El titulo" va el titulo que queremos ponerle a la ventana que nos va a salir
Y en MB_OK definimos el icono que va a tener (normal, error, exclamacion, ayuda, etc) y los botones que queremos que nos aparescan (Si, No, Acceptar, Cancelar, etc). Ahora solo vamos a usar MB_OK, para que la ventana no tenga ningun icono y solo nos de el boton de acceptar.

Esto me recuerda que si necesitan mas informacion sobre alguna funcion que usemos aqui pueden buscarla en google y entrar el el msdn (normalmente el primer link). En este caso les va a salir un link a You are not allowed to view links. Register or Login.

Por ultimo, si no les interesan los menus y quieren ir directo a como se agregan botones y esas cosas (que de hecho es mas facil) salten al siguiente capitulo.

Empecemos:
Parte 2: Agregar menús a nuestras ventanas


Para empezar vamos a definir al principio del archivo algunas constantes, que nos serviran despues para manejar los eventos del menu. En este ejemplo voy a usar estas 2:
Código: You are not allowed to view links. Register or Login
const int MN_MENSAJE=1025;
const int MN_SALIR=1026;
Aqui de nuevo pueden usar los nombres que quieran, pero deben acordarse de ellos.

Ahora, para crear nuestro menu vamos a usar esto:
Código: You are not allowed to view links. Register or Login
           HMENU menu1 = CreateMenu();
            HMENU menu2 = CreateMenu();
            AppendMenu(menu2, MF_STRING, MN_MENSAJE, "&Mensaje");
            AppendMenu(menu2, MF_STRING, MN_SALIR, "&Salir");
            AppendMenu(menu1, MF_STRING | MF_POPUP, (UINT)menu2, "&MiMenu");
            SetMenu (hwnd, menu1);

Ahora parte por parte:

Código: You are not allowed to view links. Register or Login
           HMENU menu1 = CreateMenu();
            HMENU menu2 = CreateMenu();
Se crean los menus y guardamos sus handles en las variables menu1 y menu2

Código: You are not allowed to view links. Register or Login
           AppendMenu(menu2, MF_STRING, MN_MENSAJE, "&Mensaje");
            AppendMenu(menu2, MF_STRING, MN_SALIR, "&Salir");
Al menu 2 le agregamos estos 2 items: &Mensaje y &Salir. El "&" al principio sirve para que la letra que le sigue este subrayada (por alguna razon a mi no me sale asi, pero es como deberia ser).
Voy a explicar ahora item por item:
menu2 es el menu al que vamos a agregar los items.
MF_STRING indica que queremos ingresar una cadena de texto (tambien podemos poner separadores, por ejemplo)
MN_MENSAJE y MN_SALIR son las constantes que declaramos al principio.
Y &Mensaje y "&Salir" son los textos de los 2 nuevos items.

Código: You are not allowed to view links. Register or Login
AppendMenu(menu1, MF_STRING | MF_POPUP, (UINT)menu2, "&MiMenu");Ahora lo que hacemos es agregarle a menu1 un pop-up al menu2, ya lo entenderan cuando ejecuten el programa

Código: You are not allowed to view links. Register or Login
SetMenu (hwnd, menu1);Esto añade el menu1 a la ventana de handle hwnd (en este caso la nuestra).

Ahora, ¿donde ponemos todo esto?. Yo lo voy a poner en el evento WM_CREATE de la ventana, pero despues voy a explicar otro lugar.
Este seria el codigo: (pongo en rojo las partes nuevas) (uso el quote en vez de code para que se vea el color)
Citar
#include <windows.h>

const int MN_MENSAJE=1025;
const int MN_SALIR=1026;

//poner el nombre que quieran
/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  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 */

    /* 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 */
           "Code::Blocks Template Windows App",       /* 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)
{
    switch (message)                  /* handle the messages */
    {
       case WM_CREATE:
            HMENU menu1 = CreateMenu();
            HMENU menu2 = CreateMenu();
            AppendMenu(menu2, MF_STRING, MN_MENSAJE, "&Mensaje");
            AppendMenu(menu2, MF_STRING, MN_SALIR, "&Salir");
            AppendMenu(menu1, MF_STRING | MF_POPUP, (UINT)menu2, "&MiMenu");
            SetMenu (hwnd, menu1);
            break;

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

La otra opcion seria crear los menus antes que la ventana, sin usar al final SetMenu (hwnd, menu1); (si no tenemos ventana no podemos aderir un menu a la ventana) y luego poner menu1 como decimo (n° 10) parametro de la funcion CreateWindowEx. (No es necesario que se compliquen con esto, si les da flojera no lo prueben siquiera y ya).

Todo esto quedaria asi:


Ahora nos encargamos de los eventos. El evento que vamos a usar es WM_COMMAND, y para saber que item del menu fue clickeado vamos a usar wParam. Lo hacemos de esta manera:
Código: You are not allowed to view links. Register or Login
       case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case MN_MENSAJE:
                    MessageBox(hwnd, "Mensaje de prueba", "Titulo del mensaje", MB_OK);
                    break;
                case MN_SALIR:
                    PostQuitMessage(0);
                    break;
            }
            break;
Esto hace lo siguiente: En el caso de que ocurra un evento de tipo WM_COMMAND miramos si ese evento fue el hacer click sobre alguno de los items de nuestro menu, asi que revisamos wParam para ver si se hizo un click en alguno de nuestros items y si es asi en cual.
Si se hizo click en el item conMN_MENSAJE como identificador tiramos un mensaje con MessageBox
Si se hizo click en el item conMN_SALIRE como identificador le damos al programa un mensaje de salir (para que salga del programa).

El codigo completo se veria asi: (de nuevo en rojo lo nuevo)
Citar
#include <windows.h>

const int MN_MENSAJE=1025;
const int MN_SALIR=1026;
//poner el nombre que quieran
/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  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 */

    /* 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 */
           "Code::Blocks Template Windows App",       /* 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)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            HMENU menu1 = CreateMenu();
            HMENU menu2 = CreateMenu();
            AppendMenu(menu2, MF_STRING, MN_MENSAJE, "&Mensaje");
            AppendMenu(menu2, MF_STRING, MN_SALIR, "&Salir");
            AppendMenu(menu1, MF_STRING | MF_POPUP, (UINT)menu2, "&MiMenu");
            SetMenu (hwnd, menu1);
            break;
       case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case MN_MENSAJE:
                    MessageBox(hwnd, "Mensaje de prueba", "Titulo del mensaje", MB_OK);
                    break;
                case MN_SALIR:
                    PostQuitMessage(0);
                    break;
            }
            break;

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

El mensaje, al hacer click en mensaje nos deberia salir asi:


Aqui termina la segunda parte. Al principio esta parte iba a ser sobre botones y "txtbox" por ser mucho mas sencillo, pero queria terminar ya con esto primero. En fin, el plan es mostrar como se hace esto en la proxima parte del tutorial.

 :cura:

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #2 en: Enero 08, 2010, 01:11:05 pm »
Me di cuenta que no di un ejemplo de un menu decente, y me olvide de algunas explicaciones, asi que aqui va:

Vamos a usar este menu como ejemplo:
Código: You are not allowed to view links. Register or Login
const int MN_MENSAJE=1025;
const int MN_SALIR=1026;
const int MN_I1=1027;
const int MN_I2=1028;
const int MN_I3=1029;

HMENU menu1 = CreateMenu();
HMENU menu2 = CreateMenu();
HMENU menu3 = CreateMenu();
AppendMenu(menu2, MF_STRING, MN_MENSAJE, "&Mensaje");
AppendMenu(menu2, MF_STRING | MF_POPUP, (UINT)menu3, "&Items 1, 2 y 3");

AppendMenu(menu3, MF_STRING, MN_I1, "Item1");
AppendMenu(menu3, MF_STRING, MN_I2, "Item2");
AppendMenu(menu3, MF_STRING, MN_I3, "Item3");

AppendMenu(menu2, MF_SEPARATOR, 0, NULL);
AppendMenu(menu2, MF_STRING, MN_SALIR, "&Salir");
AppendMenu(menu1, MF_STRING | MF_POPUP, (UINT)menu2, "&MiMenu");
SetMenu (hwnd, menu1);

Lo primero nuevo que vemos es esto:
Código: You are not allowed to view links. Register or Login
AppendMenu(menu2, MF_SEPARATOR, 0, NULL);Sirve para crear una linea que separa los items del menu (sobre todo una linea antes del item "Salir" es muy comun en los programas).
Veran que no usamos ninguna constante para manejar sus eventos luego, cualquier item del cual no vamos a manejar los eventos le podemos poner 0 como tercer parametro.
Ademas este item no tiene texto, asi que simplemente ponemos NULL.

El menu queda asi:


Bueno eso fue todo el add-on de la segunda parte de este tutorial.

 :cura:

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #3 en: Enero 20, 2010, 01:19:07 pm »
Al fin puedo usar internet en mi propia computadora !!! (solo esta noche), asi que voy a aprovechar para continuar con el tutorial.

Antes que nada algo de informacion poco importante: En el capitulo anterior mostre 2 maneras de añadir el menu a nuestra ventana. Hay otra forma y es que antes de crear la ventana asignar a la variable lpszMenuName de la clase de nuestra ventana el handle del menu. Yo nunca probe hacerlo de esta manera, asi que no quiero asegurar que funcione.

Bueno, en esta parte del tutorial quiero mostrar como agregar botones a la ventana y como manejar el evento en que se presiona el boton, y tambien empezar a explicar los "txtbox".

Para empezar vamos a usar como base el codigo fuente de la parte 1 del tutorial, para que este no se aga muy largo (la otra opcion seria usar el de la parte 2, e ir alargandolo en cada parte)

Parte 3: Agregar botones y cuadros de texto


Antes que nada necesitamos una variable global de tipo HINSTANCE con la informacion de nuestro instance. La definimos al principio:
Código: You are not allowed to view links. Register or Login
HINSTANCE miinstance;Y le asignamos lo que obtuvimos como primer parametro con WinMain:
Código: You are not allowed to view links. Register or Login
miinstance=hThisInstance;Queda asi:
Citar
#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

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

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 */
    miinstance=hThisInstance;
...

La funcion que vamos a usar para agregar botones y cuadros de texto a la ventana es CreateWindowEx, y vamos a agregar los items en el evento WM_CREATE de la ventana.
Les musestro un ejemplo y luego explico:
Código: You are not allowed to view links. Register or Login
HWND hwndButton1 = CreateWindowEx(0,"BUTTON", "Nuestro boton", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 100, 100, 100, 20, hwnd, 0, miinstance, NULL);
            break;
Lo primero que hacemos es definir una variable de tipo HWND en la que se va a guardar el handle del boton.
Con el primer parametro podemos hacer algunas modificaciones de diseño, pero no voy e explicar eso ahora (You are not allowed to view links. Register or Login). Yo a veces le pongo WS_EX_CLIENTEDGE, prueben si quieren.
Con el segundo paramentro le decimos a windows que tipo de item queremos, en este caso uno de tipo "BUTTON".
En el tercero ponemos el texto que va a tener el boton al principio (podemos cambiarlo mas adelante).
En el cuarto ponemos algunas caracteristicas que va a tener el boton, en este caso que sea "hijo" de nuestra ventana (WS_CHILD), que sea visible (WS_VISIBLE) y que al presionar TAB se detenga el cursor tambien en este item (WS_TABSTOP)
En el quinto, sexto, septimo y octavo ponemos las coordenadas (en x e y) y el largo y ancho del boton.
En el noveno ponemos el handle de nuestra ventana.
En el decimo una constante para manejar los eventos del boton (como en la parte 2 del tutorial con los items del menu), pero nosotros vamos a manejarlos con el handle para no complicarnos.
En el onceavo ponemos la variable global que definimos al principio.
Y en el ultimo ponemos 0.

Para agregar cuadros de texto es lo mismo, pero poniendo "EDIT" en vez de button:
Código: You are not allowed to view links. Register or Login
static HWND hwndEdit1 = CreateWindowEx(0,"Edit", "asd", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 100, 150, 100, 20, hwnd, 0, miinstance, NULL);
Y si usamos "STATIC" podemos poner textos en la ventana. Esto se ve relativamente feo si no ponemos COLOR_WINDOW en vez de COLOR_BACKGROUND como color de la ventana (esto voy a explicarlo mas adelante).

En fin, ya que estoy con lo del diseño, les voy a mostrar como cambiar el tipo de letra (pero son explicar mucho).
Primero creamos una fuente con la funcion CreateFont:
Código: You are not allowed to view links. Register or Login
static HFONT hFont = CreateFont(14, 0, 0, 0, 100, 0, 0, 0,0, 0, 0, 0, VARIABLE_PITCH | FF_SWISS, "Helv");En esa linea 14 es el tamaño y "Helv" es el tipo de letra. Eso es lo mas importante y lo unico que voy a explicar por ahora. You are not allowed to view links. Register or Login

Para asignar esa fuante a nuestros items vamos a usar la funcionSendMessage:
Código: You are not allowed to view links. Register or Login
           SendMessage(hwndButton1, WM_SETFONT, (WPARAM) hFont, true);
            SendMessage(hwndEdit1, WM_SETFONT, (WPARAM) hFont, true);
El primer parametro es el handle del item. El segundo una constante que le dice a windows que queremos cambiar la fuente (ya que con esta funcion tambien podemos cambiar otras cosas). El tercero es la variable obtenida de CreateFont y la ultima simplemente le ponemos true.

Nuestra funcion WindowProcedure ahora queda asi:
Citar
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
       case WM_CREATE:
            static HFONT hFont = CreateFont(14, 0, 0, 0, 100, 0, 0, 0,0, 0, 0, 0, VARIABLE_PITCH | FF_SWISS, "Helv");
            static HWND hwndButton1 = CreateWindowEx(0,"BUTTON", "Nuestro boton", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 100, 100, 100, 20, hwnd, 0, miinstance, NULL);
            static HWND hwndEdit1 = CreateWindowEx(0,"Edit", "asd", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 100, 150, 100, 20, hwnd, 0, miinstance, NULL);
            SendMessage(hwndButton1, WM_SETFONT, (WPARAM) hFont, true);
            SendMessage(hwndEdit1, WM_SETFONT, (WPARAM) hFont, true);
            break;

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

Antes de cambiar la fuente queda asi:


Y despues asi:



Ahora vamos a ver como manejar los eventos. Como ya dije, hay otra manera de hacerlo, pero a mi me gusta mas esta:
Código: You are not allowed to view links. Register or Login
       case WM_COMMAND:
            if((HWND)lParam==hwndButton1)
            {
                MessageBox(NULL, "Se ha precionado el boton", "xD", MB_OK | MB_ICONEXCLAMATION);
            }
            else if((HWND)lParam==hwndEdit1)
            {
                MessageBox(NULL, "Se ha seleccionado el cuadro de texto", "xD", MB_OK | MB_ICONEXCLAMATION);
            }
            break;
Creo que esto no hace falta explicarlo. Lo que si: Si al seleccionar el cuadro de texto te aparece un msgbox entonces el cuadro de texto pierde el foco, por lo que no se puede escribir en el. En la mayoria de los casos no se hace nada en este evento, y en codigos fuentes posteriores no lo voy a hacer.

Para cambiar el texto del cuadro de textos, y para obtenerlo vamos a utilizar SendMessage y GetWindowText.
Como siempre, pongo un ejemplo y luego explico:
Citar
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static char texto[256];
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            static HFONT hFont = CreateFont(14, 0, 0, 0, 100, 0, 0, 0,0, 0, 0, 0, VARIABLE_PITCH | FF_SWISS, "Helv");
            static HWND hwndButton1 = CreateWindowEx(0,"BUTTON", "Nuestro boton", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 100, 100, 100, 20, hwnd, 0, miinstance, NULL);
            static HWND hwndEdit1 = CreateWindowEx(0,"Edit", "asd", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 100, 150, 100, 20, hwnd, 0, miinstance, NULL);
            SendMessage(hwndButton1, WM_SETFONT, (WPARAM) hFont, true);
            SendMessage(hwndEdit1, WM_SETFONT, (WPARAM) hFont, true);
            break;
       case WM_COMMAND:
            if((HWND)lParam==hwndButton1)
            {
                GetWindowText(hwndEdit1, texto, 255);
                MessageBox(NULL, texto, "xD", MB_OK | MB_ICONEXCLAMATION);
                SendMessage(hwndEdit1, WM_SETTEXT, false, (long int) "texto nuevo");
            }
            break;

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Antes que nada defini un vectror en el que vamos a guardar el texto leido del cuadro de texto. Luego use la funcion GetWindowText para obtener el texto del cuadro de texto y guardarlo en la variable texto.
Como primer parametro de GetWindowText hay que poner el handle del item del cual queremos leer el texto. Como segundo parametro el lugar en el que queremos almacenar los datos obtenidos. Y por ultimo la cantidad de caracteres MAXIMA a almacenar.
En cuanto a la funcion SendMessage (ya la usamos antes, recuerdan ?) le damos como primer parametro el handle del item al que queremos agregar texto, como segundo la constante WM_SETTEXT que le dice a windows que queremos cambiar el texto. Como tercer parametro le ponemos false, y como cuarto un puntero hacia el texto que queremos poner (Al ingresar ese texto como constante tambien le estamos dando a la funcion este puntero), a esto anteponemos (long int) para que el compilador no nos tire ningun warning.

El codigo fuente completo ahora se veria asi:
Código: You are not allowed to view links. Register or Login
#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

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

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 */
    miinstance=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 */
           "Code::Blocks Template Windows App",       /* 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)
{
    static char texto[256];
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            static HFONT hFont = CreateFont(14, 0, 0, 0, 100, 0, 0, 0,0, 0, 0, 0, VARIABLE_PITCH | FF_SWISS, "Helv");
            static HWND hwndButton1 = CreateWindowEx(0,"BUTTON", "Nuestro boton", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 100, 100, 100, 20, hwnd, 0, miinstance, NULL);
            static HWND hwndEdit1 = CreateWindowEx(0,"Edit", "asd", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 100, 150, 100, 20, hwnd, 0, miinstance, NULL);
            SendMessage(hwndButton1, WM_SETFONT, (WPARAM) hFont, true);
            SendMessage(hwndEdit1, WM_SETFONT, (WPARAM) hFont, true);
            break;
        case WM_COMMAND:
            if((HWND)lParam==hwndButton1)
            {
                GetWindowText(hwndEdit1, texto, 255);
                MessageBox(NULL, texto, "xD", MB_OK | MB_ICONEXCLAMATION);
                SendMessage(hwndEdit1, WM_SETTEXT, false, (long int) "texto nuevo");
            }
            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

Y se ve asi:



Hasta aqui llego hoy, voy a ver cuando hago mas partes. La siguiente parte del tutorial va a ser o sobre hacer mas lindo el diseño o sobre algunos eventos importantes.

 :cura:

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #4 en: Enero 27, 2010, 08:52:27 am »
Esta va a ser la parte 4 del tutorial y voy a mostrar algunas maneras de hacer mas lindo el diseño.

De nuevo quiero empezar con algo de informacion poco importante. Otras ventajas de usar las apis son:
 -Para usar tu programa no sera necesario instalar nada previamente en la computadora, ni llevar ninguna dll extra en la carpeta del ejecutable.
 -El tiempo de compilacion del programa es mucho menor comparado con lo que se tarda al compilar un programa hecho con WXwidgets o SmartWin (Un programa promedio tarda unos 3 segundos con las apis de windows y 15 o mas con SmartWin).

Si alguna vez quieren cambiar alguna constante para ver como queda el programa pueden revisar cuales son las constantes en el archivo winuser.h, las constantes que van en los mismos lugares suelen empezar de la misma manera (COLOR_, WS_, WX_EX_, etc)

Parte 4: Hacer mas agradable el diseño de la ventana


Bien, primero vamos a ver como cambiar el fondo de la ventana, para esto tenemos que modificar el valor de la variable hbrBackground de la clase de nuestra ventana antes de crear la ventana. Podemos ponerle por ejemplo COLOR_WINDOW, que es el mismo color que el fondo del STATIC, pero tambien podemos ponerle cualquier color que elijamos mediante CreateSolidBrush y RGB. Seria de esta manera:
Código: You are not allowed to view links. Register or Login
wincl.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0,0,216));Esto daria a la ventana un color azul. Si queremos alguno otro color debemos modificar los 3 numeros por los valores rojo/verde/azul que queramos darle al color de fondo de nuestra ventana.

Acuerdense de modificar este valor antes de registrar la clase de la ventana:
Citar
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 */

    /* 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)CreateSolidBrush(RGB(0,0,216));

    /* 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 (
...
...
...




El titulo, el tamaño y la posicion de la ventana se pueden se cambiar modificando los parametros deCreateWindowEx al crear la ventana. Ahora voy a poner de titulo "El titulo de mi ventana", hacer que la ventana sea de 500x400 y se posicione en 200/250 (a partir de la esquina superior izquierda de nuestra pantalla). Si quieren que windows decida la posicion de la ventana pueden poner CW_USEDEFAULT en vez de las coordenadas, como hicimos hasta ahora. Con los cambios:
Citar
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "El titulo de mi ventana",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           200,       /* Windows decides the position */
           250,       /* where the window ends up on the screen */
           500,                 /* The programs width */
           400,                 /* 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 */
           );


Ahora viene algo interesante: Como agregar el icono.
Primero debemos crear un archivo de recursos (con extencion .rc) y agregarlo al proyecto, En ese archivo vamos a escribir:
Código: You are not allowed to view links. Register or Login
MIICONO ICON "icono.ico"Solo por haber hecho esto nuestro programa ya tendra un icono si lo vemos desde algun explorador de archivos, pero si ademas queremos que ese icono sea el que aparece en la ezquina izquierda arriba de la ventana debemos modificar algunas lineas del programa. Cambiamos esto:
Código: You are not allowed to view links. Register or Login
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
por esto:
Código: You are not allowed to view links. Register or Login
    wincl.hIcon = LoadIcon (miinstance, "MIICONO");
    wincl.hIconSm = LoadIcon (miinstance, "MIICONO");
Donde miinstance es una variable en la que guardamos nuestro instance (ya lo hicimos en la parte 3 del tutorial, si no se acuerdan pueden revisar).
Para que esto funcione deben tener un icono llamado icono.ico en la carpeta del proyecto.


Ya que estamos con esto les muestro tambien como agregar icononos e imagenes a nuestra ventana. Antes que nada vamos a cargar un bitmap con el archivo de recursos, que ahora se veria asi:
Citar
MIICONO ICON "icono.ico"
MIBITMAP BITMAP "bitmap.bmp"
De nuevo, es necesario que exista un bitmap (archivo de imagen con extencion .bmp) con el nombre birmap.bmp en la carpeta del proyecto.

Ahora vamos a cargar este icono y esta imagen a nuestra ventana mediante un STATIC, esto se haria asi:
Citar
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            static HWND hwndStatic1=CreateWindowEx(0,"STATIC","MIICONO",WS_CHILD | WS_VISIBLE | WS_TABSTOP | SS_ICON,
            450, 5, 0, 0, hwnd,  NULL, miinstance, NULL);
            static HWND hwndStatic2=CreateWindowEx(0,"STATIC","MIBITMAP",WS_CHILD | WS_VISIBLE | WS_TABSTOP | SS_BITMAP,
            0, 0, 0, 0, hwnd,  NULL, miinstance, NULL);

            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Tres cosas cambiaron con relacion a un static normal:
 1-En vez del texto que iba a tener pusimos el nombre del bitmap o el icono en el tercer parametro.
 2-Utilizamos las constantes SS_ICON para el icono y SS_BITMAP para el bitmap.
 3-Le pusimos 0,0 como tamaño. De esta manera el tamaño del static se ajusta al tamaño del icono o de la imagen.

Con esto mi ventana se ve asi:
Como veran no entro toda la imagen en la ventana, pero como es solo un ejemplo....


Veamos ahora como se da el foco a algun elemento, y como se usan las constantes WS_EX_. Para eso vamos a crear un cuadro de texto al cual darle el foco y de paso utilizar WS_EX_CLIENTEDGE (y tambien de paso voy a ponerle una fuente mas agradable).
Citar
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            static HFONT hFont = CreateFont(14, 0, 0, 0, 100, 0, 0, 0,0, 0, 0, 0,
            VARIABLE_PITCH | FF_SWISS, "Times New Toman");


            static HWND hwndStatic1=CreateWindowEx(0,"STATIC","MIICONO",WS_CHILD | WS_VISIBLE | WS_TABSTOP | SS_ICON,
            450, 5, 0, 0, hwnd,  NULL, miinstance, NULL);
            static HWND hwndStatic2=CreateWindowEx(0,"STATIC","MIBITMAP",WS_CHILD | WS_VISIBLE | WS_TABSTOP | SS_BITMAP,
            0, 0, 0, 0, hwnd,  NULL, miinstance, NULL);
            static HWND hwndEdit1=CreateWindowEx(WS_EX_CLIENTEDGE ,"EDIT","EditConFoco",WS_CHILD | WS_VISIBLE | WS_TABSTOP,
            190, 150, 100, 25, hwnd,  NULL, miinstance, NULL);
            SendMessage(hwndEdit1,WM_SETFONT,(WPARAM)hFont,TRUE);
            SetFocus(hwndEdit1);

            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Como veran le asigne el foco al cuadro de texto con la funcion SetFocus. Tambien le di un ligero "efecto 3D" con WX_EX_CLIENTEDGE. Hay muchos mas WX_EX_, pero no me voy a poner a explicar uno por uno, pueden ir probando buscando la lista de WX_EX_ en winuser.h (Estan todos juntos, es solo cosa de poner WX_EX_ en el buscador).
Recuerden que los items que se agregan primero a la ventana van mas al fondo, por eso si van a usar una imagen como fondo deben ingresarla antes de los demas items.
Ese codigo compilado y ejecutado se veria asi:


Esta va siendo la parte final de esta parte del tutorial. Antes de terminar quiero comentar sobre SetForegroundWindow, sirve para poner en primer plano una ventana, solo hay que darle un parametro y es el handle de la ventana.

 :cura:

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #5 en: Febrero 05, 2010, 09:35:21 am »
Esta seria la ultima parte del tutorial que tengo planeada hacer, solo voy a agregar mas partes si se me ocurren cosas nuevas o si aprendo algo nuevo que me paresca lo suficientemente importante como para agregarlo al tutorial.

¿Nunca se preguntaron por que al hacer click en la X la ventana se cierra?, ¿por que lo hace si no programamos eso?. En esta parte del tutorial voy a explicar por que pasan esas cosas y como modificar este comportamiento.

Parte 5: Algunos eventos importantes


Miremos este codigo de esta funcion de una ventana:
Código: You are not allowed to view links. Register or Login
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Lo que hace es revisar si el mensaje recibido es de tipo WM_DESTROY, y si ese es el caso postea un mensaje de tipo WM_QUIT (Eso hace la funcion PostQuitMessage). Nosotros tambien podemos enviar a la ventana los mensajes que querramos, con PostMessage, pero esa es otra historia.
En caso de que el mensaje recibido por nuestra funcion no sea WM_DESTROY (o otro mensaje que procesemos) se ejecuta este codigo:
Código: You are not allowed to view links. Register or Login
return DefWindowProc (hwnd, message, wParam, lParam);Esa porcion de codigo hace que el programa haga lo que haria por defecto con el mensaje recibido, es por eso que muchos eventos que nosotros no procesamos aun asi tienen un efecto.

Un buen ejemplo son los mensajes de tipo WM_SYSCOMMAND, que recibe nuestra ventana si el usuario la intento de minimizar, maximizar, cerrar, cabiar su tamaño, etc.. Les voy a mostrar ahora un ejemplo de como hacer que la ventana no se pueda maximizar:
Citar
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_SYSCOMMAND:
            switch(wParam)
            {
                case SC_MAXIMIZE:
                    return 0;
                    //break;
                default:
                    return DefWindowProc (hwnd, message, wParam, lParam);
                    //break;
            }
            break;

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
En este caso hice que si wParam me dice que el usuario quiere maximizar la ventana el programa no procese el mensaje como lo haria por defecto. Si hacemos esto debemos recordar que si wParam no me dice que el usuario quere maximizar la ventana el programa debe procesar el mensaje como lo haria por defecto, y lo hacemos con estas lineas:
Citar
            switch(wParam)
            {
                case SC_MAXIMIZE:
                    return 0;
                    //break;
                default:
                    return DefWindowProc (hwnd, message, wParam, lParam);
                    //break;

            }

Si queremos que el programa ademas de hacer algo en especial por este tipo de eventos tambien queremos que haga lo que haria por defecto tambien tenemos que agregar esto return DefWindowProc (hwnd, message, wParam, lParam); al final. Les muestro un ejemplo en el cual el programa avisa con MessageBox que el usuario quiere minimizar la ventana y luego la minimiza:
Código: You are not allowed to view links. Register or Login
        case WM_SYSCOMMAND:
            switch(wParam)
            {
                case SC_MINIMIZE:
                    MessageBox(NULL, "Minimizando ventana...", "titulo", MB_OK);
                    return DefWindowProc (hwnd, message, wParam, lParam);
                default:
                    return DefWindowProc (hwnd, message, wParam, lParam);
                    //break;
            }
            break;

Los valores posibles de wParam con el mensaje WM_SYSCOMMAND son: (sacado directamente de winuser.h)
Código: You are not allowed to view links. Register or Login
#define SC_SIZE 0xF000
#define SC_MOVE 0xF010
#define SC_MINIMIZE 0xF020
#define SC_ICON 0xf020
#define SC_MAXIMIZE 0xF030
#define SC_ZOOM 0xF030
#define SC_NEXTWINDOW 0xF040
#define SC_PREVWINDOW 0xF050
#define SC_CLOSE 0xF060
#define SC_VSCROLL 0xF070
#define SC_HSCROLL 0xF080
#define SC_MOUSEMENU 0xF090
#define SC_KEYMENU 0xF100
#define SC_ARRANGE 0xF110
#define SC_RESTORE 0xF120
#define SC_TASKLIST 0xF130
#define SC_SCREENSAVE 0xF140
#define SC_HOTKEY 0xF150
#define SC_DEFAULT 0xF160
#define SC_MONITORPOWER 0xF170
#define SC_CONTEXTHELP 0xF180
#define SC_SEPARATOR 0xF00F
Los que yo use hasta ahora son: SC_MINIMIZE, SC_MAXIMIZE y SC_CLOSE. Estos funcionan exactamente como explique antes, pero supongo que los demas tambien.


Otro evento util de conocer es el de pulsacion de tecla, aunque para que nuestra ventana reciba este tipo de mensaje la ventana misma debe estar seleccionada al precionar la tecla, y no un cuadro de texto o un boton en ella. Podemos seleccionar nuestra ventana mediante SetFocus(hwnd);.

El mensaje en caso de pulsacion de una tecla es de tipo WM_KEYDOWN, y en caso de que se suelte la tecla es de tipo WM_KEYUP. En ambos casos wParam contiene la informacion sobre cual fue la tecla presionana o soltada.
Para poder entender esto mejor les dejo un ejemplo, en el cual un MessageBox avisa que tecla fue soltada luego de ser presionada:
Código: You are not allowed to view links. Register or Login
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_KEYUP:
            char tecla[64];
            sprintf(tecla, "Se preciono (y solto) la tecla numero %i.", wParam);
            MessageBox(NULL, tecla, "---", MB_OK);
            break;
...
...
...



Hasta aqui llego hoy, me da la impresion de que esta parte fue algo corta, pero no se me ocurre nada mas que explicar por ahora (si se me ocurre voy a agregar al tutorial). Si siguieron el tutorial hasta aqui ya van a poder entender bien el tutorial sobre como minimizar la ventana al lado del reloj, pueden considerarlo como la siguiente parte (temporal?) del tutorial (no me refiero a la funcion que hice para facilitar todo, sino el promer tutorial que hice sobre eso).

Voy a buscar algun buen ejemplo de uso de estas apis entre los programas que hice y postearlo, para entender mejor (supongo que es mas facil imaginarse como hacer un programa de este tipo si se examino un ejemplo antes).

 :cura:

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #6 en: Febrero 10, 2010, 05:31:06 am »
Les traigo el codigo de ejemplo sobre el cual hable en el post anterior.
Es un programa que hace que al presionar una tecla automaticamente se presione otra, pero lo importente es que hice la interface GUI mediante las api's de windows.

El programa al ejecutarse se ve asi:

Hay que hacer click en "Tecla1" o "Tecla2" para elegir que tecla hay que presionar para que la otra se presione automaticamente y cual sera esta otra tecla.
Como ven, el programa tiene un icono en el systray (la barra del reloj) y al minimizarse ese es el unico rastro que deja el programa (osea se minimiza al lado del reloj).

Yo le suelo poner estass teclas, que me vienen bien para jugar DotA, ya que no es conveniente mover mi mano al otro lado del teclado cuando cada milesima de segundo es necesaria.



Ahora vamos con el codigo en si. Esta en dos partes: el main.c y el archivo de recursos. Ademas es necesario tener un icono con el nombre "CandyBar.ico" en la carpeta del proyecto.

main.c
Código: (main.c) You are not allowed to view links. Register or Login
#include <windows.h>

#define SYSTR WM_USER+1


char *teclas[]=
{
    "",//0
    "click izquierdo",
    "click derecho",
    "",
    "click central",
    "",//5
    "",
    "",
    "retroceso",
    "tab",
    "",//10
    "",
    "clear",
    "enter",
    "",
    "",//15
    "shift",
    "control",
    "alt",
    "pausa",
    "mayus",//20
    "",
    "",
    "",
    "",
    "",//25
    "",
    "escape",
    "",
    "",
    "",//30
    "",
    "espacio",
    "pagina ant",
    "pagina sig",//??
    "fin",//35
    "inicio",
    "izquierda",
    "arriba",
    "derecha",
    "abajo",//40
    "",
    "imprimir",
    "",
    "",
    "insertar",//45
    "suprimir",
    "ayuda",
    "0",
    "1",
    "2",//50
    "3",
    "4",
    "5",
    "6",
    "7",//55
    "8",
    "9",
    "",
    "",
    "",//60
    "",
    "",
    "",
    "",
    "A",//65
    "B",
    "C",
    "D",
    "E",
    "F",//70
    "G",
    "H",
    "I",
    "J",
    "K",//75
    "L",
    "M",
    "N",
    "O",
    "P",//80
    "Q",
    "R",
    "S",
    "T",
    "U",//85
    "V",
    "W",
    "X",
    "Y",
    "Z",//90
    "windows",
    "",
    "propiedades",
    "",
    "",//95
    "numpad_0",
    "numpad_1",
    "numpad_2",
    "numpad_3",
    "numpad_4",//100
    "numpad_5",
    "numpad_6",
    "numpad_7",
    "numpad_8",
    "numpad_9",//105
    "*",
    "+",
    "",
    "-",
    "",//110
    "/",
    "F1",
    "F2",
    "F3",
    "F4",//115
    "F5",
    "F6",
    "F7",
    "F8",
    "F9",//120
    "F10",
    "F11",
    "F12",
    "",
    "",//125
    "",
    "",
    "",
    "",
    "",//130
    "",
    "",
    "",
    "",
    "",//135
    "",
    "",
    "",
    "",
    "",//140
    "",
    "",
    "",
    "num bloq",
    ""
};

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
DWORD WINAPI hilo2(void*);

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

NOTIFYICONDATA nid;
HINSTANCE miinstance;
int modo;
short teclaa=0, teclab=0;
HANDLE hThread;
bool end=false;
bool cambiando=false;

/*#define INPUT_KEYBOARD 0x00000001
typedef struct tagKEYBDINPUT {
  WORD wVk;
  WORD wScan;
  DWORD dwFlags;
  DWORD time;
  ULONG_PTR dwExtraInfo;
} KEYBDINPUT,*PKEYBDINPUT;
typedef struct tagINPUT {
  DWORD type;
  _ANONYMOUS_UNION union {
//MOUSEINPUT mi;
KEYBDINPUT ki;
//HARDWAREINPUT hi;
  } DUMMYUNIONNAME;
} INPUT,*PINPUT,*LPINPUT;

INPUT input;*/

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 */
    HICON hIcono;
    modo=nCmdShow;
    miinstance=hThisInstance;

    //input.type=INPUT_KEYBOARD;

    /* 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 (hThisInstance, "CANDYBAR");
    wincl.hIconSm = LoadIcon (hThisInstance, "CANDYBAR");
    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_WINDOW;
    //CreateSolidBrush(RGB(0,0,0));

    /* 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 */
           "CTecla2 --- By Avoidance25",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           GetSystemMetrics(SM_CXSCREEN)-215,       /* Windows decides the position */
           GetSystemMetrics(SM_CYSCREEN)-110,       /* where the window ends up on the screen */
           215,                 /* The programs width */
           80,                 /* 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 */
    hIcono = LoadIcon(hThisInstance, "CANDYBAR");

ZeroMemory(&nid, sizeof(NOTIFYICONDATA));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hIcon = hIcono;
nid.hWnd = hwnd;
nid.uCallbackMessage = SYSTR;
nid.uFlags = NIF_ICON|NIF_TIP|NIF_MESSAGE;
lstrcpy(nid.szTip, "CTecla2 --- Hecho por Avoidance25");
nid.uID = 0;
Shell_NotifyIcon(NIM_ADD, &nid);

DWORD  dwThreadID;
    hThread=CreateThread(NULL,0,hilo2,NULL,0,&dwThreadID);

    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)
{
    static int cual=0;
    static int estado=modo;
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            static HFONT hFont = CreateFont(14, 0, 0, 0, 100, 0, 0, 0,0, 0, 0, 0, VARIABLE_PITCH | FF_SWISS, "Helv");
            static HWND hwndStatic1 = CreateWindowEx(0,"STATIC", "  ---->", WS_CHILD|WS_VISIBLE, 85, 15, 30, 15, hwnd, 0, miinstance, NULL);
            static HWND hwndEdit1 = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT", "Tecla 1", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 10, 15, 75, 15, hwnd, 0, miinstance, NULL);
            static HWND hwndEdit2 = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT", "Tecla 2", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 115, 15, 75, 15, hwnd, 0, miinstance, NULL);
            SendMessage(hwndStatic1, WM_SETFONT, (WPARAM) hFont, true);
            SendMessage(hwndEdit1, WM_SETFONT, (WPARAM) hFont, true);
            SendMessage(hwndEdit2, WM_SETFONT, (WPARAM) hFont, true);
            SendMessage(hwndEdit1, WM_ENABLE, (WPARAM) false, true);
            SendMessage(hwndEdit2, WM_ENABLE, (WPARAM) false, true);
            break;
        case WM_SYSCOMMAND:
            switch(wParam)
            {
                case SC_MINIMIZE:
                    estado=SW_HIDE;
                    ShowWindow (hwnd, SW_HIDE);
                    return 0;
                    break;
                case SC_MAXIMIZE:
                    return 0;
            }
            break;
        case SYSTR:
            switch(lParam)
            {
                case WM_LBUTTONDOWN:
                    if(estado==modo)
                    {
                        estado=SW_HIDE;
                        ShowWindow (hwnd, estado);
                    }
                    else
                    {
                        estado=modo;
                        ShowWindow (hwnd, estado);
                        SetForegroundWindow(hwnd);
                    }
                    break;
            }
            break;
        case WM_COMMAND:
            if((HWND)lParam==hwndEdit1)
            {
                cual=1;
                cambiando=true;
                SendMessage(hwndEdit1, WM_ENABLE, (WPARAM) true, true);
                SendMessage(hwndEdit2, WM_ENABLE, (WPARAM) false, true);
                SetFocus(hwnd);
            }
            else if((HWND)lParam==hwndEdit2)
            {
                cual=2;
                cambiando=true;
                SendMessage(hwndEdit2, WM_ENABLE, (WPARAM) true, true);
                SendMessage(hwndEdit1, WM_ENABLE, (WPARAM) false, true);
                SetFocus(hwnd);
            }
            break;
        case WM_KEYDOWN:
            if(cual==1)
            {
                if(wParam==(UINT)teclab) break;
                SendMessage(hwndEdit1, WM_SETTEXT, false, (long int) teclas[wParam]);
                SendMessage(hwndEdit1, WM_ENABLE, (WPARAM) false, true);
                teclaa=wParam;
            }
            else if(cual==2)
            {
                if(wParam==(UINT)teclaa) break;
                SendMessage(hwndEdit2, WM_SETTEXT, false, (long int) teclas[wParam]);
                SendMessage(hwndEdit2, WM_ENABLE, (WPARAM) false, true);
                teclab=wParam;
            }
            cual=0;
            cambiando=false;
            break;
        case WM_DESTROY:
            end=true;
            Shell_NotifyIcon(NIM_DELETE, &nid);
            WaitForSingleObject(hThread,750);
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return DefWindowProc (hwnd, message, wParam, lParam);
}

DWORD WINAPI hilo2(void*)
{

    while((teclaa==0 || teclab==0) && !end) Sleep(25);
    while(!end)
    {
        while(cambiando)Sleep(25);

        if(GetAsyncKeyState(teclaa)/*==-32767*/)
        {
            keybd_event(teclab,MapVirtualKey(teclab,0),0,0);
            keybd_event(teclab,MapVirtualKey(teclab,0),KEYEVENTF_KEYUP,0);
            Sleep(80);
            GetAsyncKeyState(teclaa);
            GetAsyncKeyState(teclab);
            //keybd_event(teclab,0xb8,KEYEVENTF_KEYUP,0);
        }
        Sleep(20);
    }
    return 0;
}

Datos.rc
Código: (Datos.rc) You are not allowed to view links. Register or Login
#include <windows.h>


CANDYBAR ICON MOVEABLE PURE LOADONCALL DISCARDABLE "CandyBar.ico"


1 VERSIONINFO
FILEVERSION 0,0,0,0
PRODUCTVERSION 0,0,0,0
FILETYPE VFT_APP
{
  BLOCK "StringFileInfo"
{
BLOCK "3C0A04E4"
{
VALUE "CompanyName", "Avoidance25"
VALUE "FileVersion", ""
VALUE "FileDescription", "Developed by Avoidance25"
VALUE "InternalName", ""
VALUE "LegalCopyright", "toni_ebs@hotmail.de"
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "CTecla2.exe"
VALUE "ProductName", "CTecla2"
VALUE "ProductVersion", ""
}
}
  BLOCK "VarFileInfo"
{
VALUE "Translation", 0x3C0A, 1252
}
}


 :cura:

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #7 en: Febrero 27, 2010, 07:48:02 am »
El curso ya lo considero completo, porque creo que cubre las bases mas basicas, pero voy a agregar ahora un add-on sobre un tema que creo que es tambien bastante importante para el diseño. Este add-on va a tratar sobre el color de texto/fondo de los edit.

Voy a suponer que ya nos entendemos bien con los items de tipo Edit y que sabemos incluirlos en nuestro programa.

Add-On: Agregar colores a los edit's

 Vamos a basarnos en este codigo:
Código: You are not allowed to view links. Register or Login
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            static HFONT hFont = CreateFont(15, 0, 0, 0, 100, 0, 0, 0,0, 0, 0, 0, VARIABLE_PITCH | FF_SWISS, "Times New Toman");
            static HWND hwndEdit1=CreateWindowEx(WS_EX_CLIENTEDGE ,"EDIT","Edit1",WS_CHILD | WS_VISIBLE | WS_TABSTOP,
            10, 10, 100, 20, hwnd,  NULL, miinstance, NULL);
            static HWND hwndEdit2=CreateWindowEx(WS_EX_CLIENTEDGE ,"EDIT","Edit2",WS_CHILD | WS_VISIBLE | WS_TABSTOP,
            10, 50, 100, 20, hwnd,  NULL, miinstance, NULL);
            SendMessage(hwndEdit1,WM_SETFONT,(WPARAM)hFont,TRUE);
            SendMessage(hwndEdit2,WM_SETFONT,(WPARAM)hFont,TRUE);
            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}


El texto de los edits tiene al menos dos colores: El color de letra y el color de fondo del texto, pero a parte de esto tambien existe el color de fondo del edit en si. Nosotros vamos a dejar el color de fondo del edit igual que el color de fondo del texto para que se vea mejor.

Para empezar con lo sencillo voy a mostrar primero como se cambia el color del texto, y para ello vamos a usar el evento WM_CTLCOLOREDIT:
Código: You are not allowed to view links. Register or Login
       case WM_CTLCOLOREDIT:
            SetTextColor((HDC)wParam, RGB(0,0,255));
            break;
Lo que hacemos es decir al programa que debe poner como color de texto a "RGB(0,0,255)" cuando se ponga a repartir los colores.
Deberia salir todo asi:


Pero no queremos que le de color a todos los edit, queremos que le de color solo al primero. Para eso en programa nos da como lParam el handle del edit que estamos modificando, asi que si queremos modificar solo el primer edit hacemos esto:
Código: You are not allowed to view links. Register or Login
       case WM_CTLCOLOREDIT:
            if(lParam==(LPARAM)hwndEdit1){
                SetTextColor((HDC)wParam, RGB(0,0,255));
            }
            break;
Que nos da este resultado:




Bien ahora el fondo, que es lo mismo pero con SetBkColor:
Código: You are not allowed to view links. Register or Login
       case WM_CTLCOLOREDIT:
            if(lParam==(LPARAM)hwndEdit1){
                SetBkColor((HDC)wParam, RGB(255,0,255));
                SetTextColor((HDC)wParam, RGB(0,0,255));
            }
            break;
Y nos sale asi:

Pero nosotros queremos asi:

(Esto se ve mejor cuando el edit es mas grando. En la primera foto se ve un espacio en blanco al rededor del cuadrado en el que esta el texto).

Para lograr esto creamos un pincel en el evento WM_CREATE:
Código: You are not allowed to view links. Register or Login
       case WM_CREATE:
            static HBRUSH pincel=CreateSolidBrush(RGB(255,0,255));
...
...
y hacemos que la funcion de la ventana retorne este pincel cuando ocurre el evento WM_CTLCOLOREDIT:
Código: You are not allowed to view links. Register or Login
       case WM_CTLCOLOREDIT:
            if(lParam==(LPARAM)hwndEdit1){
                SetBkColor((HDC)wParam, RGB(255,0,255));
                SetTextColor((HDC)wParam, RGB(0,0,255));
                return (LRESULT)pincel;
            }
            break;
Esto deberia cambiar el fondo del edit.
Luego hay que deshacerse del pincel en el evento WM_DESTROY:
Código: You are not allowed to view links. Register or Login
       case WM_DESTROY:
            DeleteObject(pincel);
...
...


Les pongo el codigo completo por si alguien se perdio:
Citar
#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

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

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 */
    miinstance=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 */
           "Code::Blocks Template Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           150,                 /* The programs width */
           125,                 /* 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)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            static HBRUSH pincel=CreateSolidBrush(RGB(255,0,255));
            static HFONT hFont = CreateFont(15, 0, 0, 0, 100, 0, 0, 0,0, 0, 0, 0, VARIABLE_PITCH | FF_SWISS, "Times New Toman");
            static HWND hwndEdit1=CreateWindowEx(WS_EX_CLIENTEDGE ,"EDIT","Edit1",WS_CHILD | WS_VISIBLE | WS_TABSTOP, 10, 10, 100, 20, hwnd,  NULL, miinstance, NULL);
            static HWND hwndEdit2=CreateWindowEx(WS_EX_CLIENTEDGE ,"EDIT","Edit2",WS_CHILD | WS_VISIBLE | WS_TABSTOP, 10, 50, 100, 20, hwnd,  NULL, miinstance, NULL);
            SendMessage(hwndEdit1,WM_SETFONT,(WPARAM)hFont,TRUE);
            SendMessage(hwndEdit2,WM_SETFONT,(WPARAM)hFont,TRUE);
            break;
        case WM_CTLCOLOREDIT:
            if(lParam==(LPARAM)hwndEdit1){
                SetBkColor((HDC)wParam, RGB(255,0,255));
                SetTextColor((HDC)wParam, RGB(0,0,255));
                return (LRESULT)pincel;
            }
            break;

        case WM_DESTROY:
            DeleteObject(pincel);
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

Hasta aqui llega este Add-On, espero que le puedan sacar provecho. A ver cuando hago otro....

 :cura:

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #8 en: Marzo 14, 2010, 07:48:53 am »
Antes que nada quiero avisar que probablemente voy a borrar todos los comentarios de este hilo que no formen parte del tutorial, para dejarlo limpio.

Este con add-on voy a explicar como hacer que el usuario escoja un archivo sin pedirle que ingrese la dirección de dicho archivo en un edit (txtbox, cuadro de texto, control edit.... para no complicarnos voy a llamarlo simplemente edit desde ahora).

La explicación que pienso hacer va a ser muy sencilla y voy a explicar solo lo mas importante, para no complicarnos y llegar mas rápido a resultados. Para profundizar pueden buscar You are not allowed to view links. Register or Login y You are not allowed to view links. Register or Login en la msdn.

Add-On: Buscar archivos


Vamos a basarnos en el código fuente de la primera parte del tutorial pero cambiando la función de la ventana por:
Código: You are not allowed to view links. Register or Login
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            static HFONT hFont = CreateFont(14, 0, 0, 0, 100, 0, 0, 0,0, 0, 0, 0, VARIABLE_PITCH | FF_SWISS, "Helv");
            static HWND hwndButton1 = CreateWindowEx(0,"BUTTON", "&Elegir Archivo", WS_CHILD|WS_VISIBLE|WS_TABSTOP, 100, 100, 100, 20, hwnd, 0, miinstance, NULL);
            static HWND hwndEdit1 = CreateWindowEx(0,"EDIT", "", WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_DISABLED, 0, 325, 544, 15, hwnd, 0, miinstance, NULL);
            SendMessage(hwndButton1, WM_SETFONT, (WPARAM) hFont, true);
            SendMessage(hwndEdit1, WM_SETFONT, (WPARAM) hFont, true);
            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

Lo cual deberia darnos esta ventana:



Ahora vamos a programar el evento WM_COMMAND para que nos salga la ventana para buscar el archivo cuando hagamos click sobre el boton. Voy a mostrar como y luego explicar:
Código: You are not allowed to view links. Register or Login
        case WM_COMMAND:
            if((HWND)lParam==hwndButton1)
            {
                char str_archivo[MAX_PATH];
                OPENFILENAME  ofn;

                ZeroMemory(&ofn, sizeof(ofn));
                ofn.lStructSize = sizeof(ofn);
                ofn.hwndOwner = hwnd;
                ofn.lpstrFile = str_archivo;
                *ofn.lpstrFile = 0;
                ofn.nMaxFile = MAX_PATH;
                ofn.lpstrFilter = "Codigos fuentes de c/c++\0*.c;*.cpp\0Archivos de texto\0*.TXT\0Cualquier archivo\0*.*\0";
                ofn.nFilterIndex = 1;
                ofn.lpstrInitialDir = "%homepath%";
                ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

                GetOpenFileName(&ofn) ?
                SendMessage(hwndEdit1, WM_SETTEXT, false, (long int) ofn.lpstrFile):  //Es lo mismo poner ofn.lpstrFile y str_archivo
                SendMessage(hwndEdit1, WM_SETTEXT, false, (long int) "Error al obtener el archivo");
            }
            break;
Lo primero que hacemos con este codigo es definir la variable str_archivo en la cual se va a guardar la direccion del archivo.
Luego definimos un objeto (se llama asi?) de la estructura OPENFILENAME, que necesitaremos luego para llamar a la funcion GetOpenFileName, que crea la ventana para buscar el archivo.

Ahora voy a explicar que datos debemos ingresar en nuestra estructura, pero solo aquellos datos absolutamente importantes o muy utiles para no hacerlo muy largo y complicado.

lStructSize: Aquí debemos ingresar el tamaño de la estrucura.
hwndOwner: Aquí debemos ingresar el handle de la ventana a la que pertenece la nueva ventana.
lpstrFile: Aquí va un puntero hacia un espacio en la memoria reservado en el cual se va a escribir el nombre del archivo.
nMaxFile: Aquí  va el tamaño máximo de la cadena en la que se guarda el nombre del archivo. Especificamos esto para evitar un buffer overflow.
lpstrFilter: Aquí va una cadena que especifica los tipos de archivos a buscar. Voy a explicar esto mejor despues.
nFilterIndex: Esto tambien lo explico luego.....
lpstrInitialDir: Directorio en el cual se empieza a buscar. Como ven se pueden incluir variables de entorno.
Flags: Aquí ponemos algunas banderas. En este caso ponemos OFN_PATHMUSTEXIST y OFN_FILEMUSTEXIST para asegurarnos que el archivo elegido existe.


En nFilterIndex debemos poner una cadena de esta manera:
Código: You are not allowed to view links. Register or Login
"Archivos de texto\0*.TXT\0"En este caso describimos los archivos a buscar como archivos de texto y buscamos los archivos con la extensión .txt.
Esta "cadena" en realidad son varios pares de cadenas, todas terminadas en \0, y la ultima terminada en \0\0. En este ultimo ejemplo solo tenemos un par de cadenas.

En el ejemplo de arriba usamos esto:
Código: You are not allowed to view links. Register or Login
"Codigos fuentes de c/c++\0*.c;*.cpp\0Archivos de texto\0*.TXT\0Cualquier archivo\0*.*\0"Aquí tenemos 3 pares de cadenas. El primer par busca archivos .c y .cpp. El segundo archivos .txt. Y el tercero busca archivos de todos los tipos.
En cada par tenemos primero una descripción para el usuario y luego el texto para decir a la computadora que tipo de extensión usar.

Nos debería salir así:


Con nFilterIndex Elegimos con que par de cadenas queremos empezar a buscar archivos, en este caso con "Codigos fuentes de c/c++\0*.c;*.cpp\0", el primer par de cadenas.



Luego de haber dado valores a las variables de nuestra estructura solo queda llamar a la funcion GetOpenFileName, pasandole como parámetro un puntero hacia nuestra estructura. Y en este caso también imprimiendo la dirección del archivo en nuestro edit, y la cadena "Error al obtener el archivo" en caso de que no se halla podido obtener la cadena.


Bien, este es el fin del add-on. Pueden postear sus dudas si quieren pero tarde o temprano voy a borrar todos los comentarios de este hilo que no sean parte del tutorial (debería buscar una solución para esto, xD. Tal vez ir borrando los mensajes gradualmente....).

 :cura:

Desconectado »NaSH

  • Yo vivo en CPH
  • ***
  • Mensajes: 876
  • Sexo: Masculino
  • --[[ ]]
    • Ver Perfil
    • http://img122.imageshack.us/img122/5388/windowsramutohv2rx9.jpg
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #9 en: Diciembre 09, 2010, 12:08:41 pm »
Impresionante, por qué razón no tiene ningún comentario ._.
Me estoy iniciando en C++, voy a tenerlo en cuenta para cuando avance un poco más

Hasta luego
« Última modificación: Diciembre 09, 2010, 12:38:55 pm por MatU_MalO »

Desconectado JaAViEr

  • ¡ Programming the world !
  • Colaborador
  • ****
  • Mensajes: 8218
  • http://ethereumchile.cl
    • Ver Perfil
    • Ethereum Chile
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #10 en: Diciembre 09, 2010, 12:12:55 pm »
Te servirá mucho Matu, yo lo leí & me a servido un monton !
Pasas tus codes de consola a entorno gráfico & queda mucho mejor ;D
¡MI TWITTER You are not allowed to view links. Register or Login!
You are not allowed to view links. Register or Login !

Desconectado Oskaury

  • Me das tu IP?
  • *
  • Mensajes: 89
  • Sexo: Masculino
  • Jesucristo es lo mejor!!!
    • Ver Perfil
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #11 en: Diciembre 29, 2010, 05:30:22 pm »
Yo tambien me estoy iniciando en C++, y creo que esto me servir'a un monton, buen post XD.
Definición de Hardware: Es lo que recibe los golpes cuando el software no funciona.

Desconectado tadeo14

  • Me das tu IP?
  • *
  • Mensajes: 40
  • Sexo: Masculino
  • todo el esfuerzo es inutil si no crees en ti mismo
    • Ver Perfil
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #12 en: Enero 06, 2011, 05:11:37 am »
hola!

que tal, me intereso mucho este tutorial, uso dev c++, intente tan solo copiar el codigo y me salio este error (el de la ventana sola no hubo problema).

no se porque me sale el error, espero su ayuda, me interesa mucho este tutorial ^^.

ventana.cpp: In function `LRESULT WindowProcedure(HWND__*, UINT, WPARAM, LPARAM)':
ventana.cpp:89: error: jump to case label
ventana.cpp:83: error:   crosses initialization of `HMENU__*menu2'
ventana.cpp:82: error:   crosses initialization of `HMENU__*menu1'
ventana.cpp:92: error: jump to case label
ventana.cpp:83: error:   crosses initialization of `HMENU__*menu2'
ventana.cpp:82: error:   crosses initialization of `HMENU__*menu1'

make.exe: *** [ventana.o] Error 1

Ejecución Terminada

saludos

tadeo

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #13 en: Enero 06, 2011, 06:15:48 am »
Si no recuerdo mal habian algunas pocas diferencias entre el MinGW de dev-cpp y el de Code::Blocks. Creo que habia que hacer:
Código: You are not allowed to view links. Register or Login
HMENU menu1;
menu1=CreateMenu();
en vez de:
Código: You are not allowed to view links. Register or Login
HMENU menu1 = CreateMenu();
Si no te soluciona el problema muestrame en que linea de codigo te tira el error.

 :cura:

Desconectado .xAk.

  • el engendro
  • Moderador
  • *****
  • Mensajes: 7307
  • Sexo: Masculino
  • F0r3v3R NeWbI3
    • Ver Perfil
Re: Tutorial de uso de apis de windows para crear un entorno grafico
« Respuesta #14 en: Enero 06, 2011, 06:55:33 am »
Dev C++ y Code::Blocks son ides, utilizan el mismo compilador por defecto, el de GNU. En el trato de código no hay diferencia. Si no se trata de macros propias añadidas desde nuestro entorno.

Existe la posibilidad que uno de los dos ides esté trabajando con otro compilador. Aunque no sería por defecto ;)

SaludOS
Is the truth out there?


xx
Nueva ventana (entorno grafico con APIS de windows)

Iniciado por soez

15 Respuestas
5508 Vistas
Último mensaje Julio 31, 2010, 08:40:38 am
por myguestp
xx
Crear un entorno gráfico

Iniciado por LinkStudios

1 Respuestas
1305 Vistas
Último mensaje Mayo 04, 2009, 03:03:04 pm
por Ni0
exclamation
Programa para facilitar la creación de un entorno gráfico con WinApi

Iniciado por Avoidance25

2 Respuestas
1325 Vistas
Último mensaje Mayo 01, 2010, 04:50:11 am
por Avoidance25
question
C++ y Entorno Grafico

Iniciado por jamp

4 Respuestas
1811 Vistas
Último mensaje Diciembre 06, 2009, 04:30:49 am
por .xAk.
resuelto
[Solucionado]Un par de dudas C++ (entorno grafico)

Iniciado por JaAViEr

2 Respuestas
1075 Vistas
Último mensaje Mayo 01, 2010, 12:49:34 pm
por JaAViEr
exclamation
Programa Inutil C++ Entorno Grafico

Iniciado por JaAViEr

3 Respuestas
2416 Vistas
Último mensaje Abril 21, 2010, 08:03:20 am
por Avoidance25
resuelto
Java desde 0?, entorno gráfico.

Iniciado por Ike Array

2 Respuestas
2148 Vistas
Último mensaje Diciembre 01, 2011, 09:39:46 pm
por Ike Array
xx
Problema con entorno grafico ¿jprogressbar?

Iniciado por Mark160

1 Respuestas
1190 Vistas
Último mensaje Febrero 22, 2011, 08:50:58 pm
por Kreusser
exclamation
Guia básica ettercap (entorno gráfico)

Iniciado por Aetsu

36 Respuestas
43239 Vistas
Último mensaje Agosto 08, 2014, 04:30:25 pm
por pishtako
exclamation
Programa C++ Entorno Grafico - Frame Based.

Iniciado por JaAViEr

4 Respuestas
2427 Vistas
Último mensaje Abril 22, 2010, 01:40:26 pm
por JaAViEr