Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
<strong>Programación</strong> <strong>en</strong> <strong>Windows</strong><br />
y <strong>MFCs</strong><br />
Tema 6<br />
Grupo 46<br />
TACC II<br />
Curso 2008/09<br />
1
Indice<br />
<strong>Programación</strong> bajo <strong>Windows</strong>.<br />
Introducción<br />
Introducción.<br />
Hola mundo!.<br />
El API de <strong>Windows</strong>.<br />
Introducción a las <strong>MFCs</strong> <strong>MFCs</strong>.<br />
Arquitectura Docum<strong>en</strong>to/Vista.<br />
Aspectos avanzados de las <strong>MFCs</strong>.<br />
Bibliografía. g<br />
2
<strong>Programación</strong> Bajo <strong>Windows</strong><br />
Proramación ori<strong>en</strong>tada a ev<strong>en</strong>tos ev<strong>en</strong>tos, <strong>en</strong> contraste con la programación<br />
para MS-DOS, que es secu<strong>en</strong>cial.<br />
Ev<strong>en</strong>to: Algo que sucede <strong>en</strong> el sistema (click de ratón ratón, movimi<strong>en</strong>to<br />
de ratón, pulsación de una tecla, etc.)<br />
<strong>Windows</strong> convierte estos ev<strong>en</strong>tos <strong>en</strong> m<strong>en</strong>sajes (añad<strong>en</strong> información<br />
a los ev<strong>en</strong>tos). P.ej.: cuando se hace click con el ratón, el m<strong>en</strong>saje<br />
incluye las coord<strong>en</strong>adas, la v<strong>en</strong>tana sobre la que se pulsó, etc.<br />
<strong>Windows</strong> pasa el m<strong>en</strong>saje a la parte interesada (ej. la v<strong>en</strong>tana sobre<br />
la que se hizo click).<br />
La aplicación puede obviar el m<strong>en</strong>saje, o puede t<strong>en</strong>er código que la<br />
haga reaccionar.<br />
3
<strong>Programación</strong> Bajo <strong>Windows</strong><br />
Estructura g<strong>en</strong>érica de una aplicación windows:<br />
1. Iniciar la aplicación. p<br />
Iniciar la aplicación y la instancia.<br />
En las versiones de 32 bits se inicializa la aplicación cada vez que<br />
se inicializa la instancia.<br />
En las versiones de 16 bits sólo con la 1ª instancia (compartir<br />
información, ahorro memoria).<br />
Todas las aplicaciones ti<strong>en</strong><strong>en</strong> una o más v<strong>en</strong>tanas (hay<br />
excepciones excepciones, como los controladores de dispositivo)<br />
dispositivo).<br />
Clases (tipos) de v<strong>en</strong>tanas definidas mediante parámetros. Registro<br />
de la clase de v<strong>en</strong>tana. Esto se hace al inicializar la aplicación.<br />
Al inicializar la instancia, se crea una v<strong>en</strong>tana de la clase definida.<br />
HHay que ddar el l nombre b dde lla v<strong>en</strong>tana, t sus coord<strong>en</strong>adas, d d<br />
dim<strong>en</strong>siones, m<strong>en</strong>ú, etc.<br />
2. Esperar que llegue algún m<strong>en</strong>saje.<br />
33. Reaccionar ante el m<strong>en</strong>saje recibido recibido.<br />
4. Volver a 2.<br />
4
<strong>Programación</strong> Bajo <strong>Windows</strong><br />
Estructura g<strong>en</strong>érica de una aplicación windows:<br />
1. Iniciar la aplicación.<br />
2. Esperar que llegue algún m<strong>en</strong>saje.<br />
Bucle de captura de m<strong>en</strong>sajes.<br />
Filtrar los m<strong>en</strong>sajes que van a la aplicación, adaptarlos y<br />
hhacerlos l ll llegar a lla v<strong>en</strong>tana t correspondi<strong>en</strong>te. di t<br />
Procedimi<strong>en</strong>to de v<strong>en</strong>tana, recibe m<strong>en</strong>saje y adopta uno u<br />
otro comportami<strong>en</strong>to.<br />
3. Reaccionar ante el m<strong>en</strong>saje recibido.<br />
4. Volver a 2.<br />
5
#include "stdafx.h"<br />
#include <br />
// Crear un proyecto win32 application vacío (o “Hello World” <strong>en</strong> VC 6.0)<br />
LRESULT CALLBACK GGestorM<strong>en</strong>sajes( M j (<br />
{<br />
HANDLE hW hWnd, d<br />
UINT m<strong>en</strong>saje,<br />
WPARAM wParam,<br />
LPARAM lParam)<br />
HDC hDc; // Device context<br />
PAINTSTRUCT ps; // Estructura de dibujado<br />
RECT rect; // Rectángulo cli<strong>en</strong>te<br />
switch (m<strong>en</strong>saje)<br />
{<br />
case WM_PAINT:<br />
hD hDc = BBeginPaint((HWND)hWnd, i P i t((HWND)hW d &ps); & )<br />
Hola Mundo!<br />
GetCli<strong>en</strong>tRect((HWND)hWnd,&rect);<br />
DrawText(hDc, TEXT("¡Hola Mundo!“), -1, &rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER);<br />
EndPaint((HWND)hWnd, &ps);<br />
bbreak; k<br />
case WM_DESTROY:<br />
PostQuitMessage(0);<br />
break;<br />
ddefault: f lt return t DefWindowProc((HWND)hWnd,m<strong>en</strong>saje,wParam,lParam);<br />
D fWi d P ((HWND)hW d j P lP )<br />
}<br />
return (NULL);<br />
}<br />
6
BOOL IniciaAplicacion (HINSTANCE hInstance)<br />
{<br />
WNDCLASS C SS wc;<br />
}<br />
Hola Mundo!<br />
wc.style = CS_HREDRAW | CS_VREDRAW; //Estilo de la clase<br />
wc wc.lpfnWndProc lpfnWndProc = (WNDPROC)GestorM<strong>en</strong>sajes; // Procedimi<strong>en</strong>to gestor<br />
wc.cbClsExtra = 0;<br />
wc.cbWndExtra = 0;<br />
wc.hInstance hI t = hInstance; hI t // Instancia I t i<br />
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // Icono de la v<strong>en</strong>tana<br />
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // cursor de la v<strong>en</strong>tana<br />
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE (HBRUSH)GetStockObject(WHITE_BRUSH); BRUSH); // Color de fondo<br />
wc.lpszM<strong>en</strong>uName = NULL; // Nombre del m<strong>en</strong>ú asociado<br />
wc.lpszClassName = TEXT("ClaseV<strong>en</strong>tana“); // Nombre de la clase de la v<strong>en</strong>tana<br />
return (RegisterClass(&wc));<br />
7
BOOL IniciaInstancia(HINSTANCE hInstance, int nCmdShow)<br />
{<br />
HWND hWnd;<br />
Hola Mundo!<br />
hWnd = CreateWindow(<br />
TEXT("ClaseV<strong>en</strong>tana“), // Clase de v<strong>en</strong>tana a la que pert<strong>en</strong>ece (caract. UNICODE)<br />
TEXT("TACC II, grupo 46, curso 2008/09“),// Título de la v<strong>en</strong>tana<br />
WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_VSCROLL, _ | _ | _<br />
// Estilo<br />
CW_USEDEFAULT, // Posicion X por defecto<br />
CW_USEDEFAULT, // Posicion Y por defecto<br />
CW_USEDEFAULT, // Anchura por defecto<br />
CW_USEDEFAULT, // Altura por defecto<br />
NULL, // Sin v<strong>en</strong>tana padre<br />
NULL, // Sin m<strong>en</strong>u<br />
hInstance, // Instancia<br />
NULL);<br />
if (!hWnd) return FALSE;<br />
// Parametros<br />
ShowWindow(hWnd, nCmdShow); // dice cómo mostrar la v<strong>en</strong>tana<br />
UpdateWindow(hWnd);<br />
return TRUE;<br />
// actualiza la v<strong>en</strong>tana: g<strong>en</strong>era un ev<strong>en</strong>to WM_PAINT<br />
}<br />
8
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,<br />
LPSTR lpCmdLine, int nCmdShow)<br />
{<br />
MSG M<strong>en</strong>saje;<br />
BOOL bret;<br />
}<br />
if (!hPrevInstance){<br />
if (!IniciaAplicacion(hInstance)) return FALSE;<br />
}<br />
if (!IniciaInstancia(hInstance, nCmdShow)) return FALSE;<br />
Hola Mundo!<br />
while ((bret = GetMessage(&M<strong>en</strong>saje, NULL, NULL, NULL)) != 0)<br />
{<br />
TranslateMessage(&M<strong>en</strong>saje); // traduce de teclas conv<strong>en</strong>cionales a WM_CHAR<br />
DispatchMessage(&M<strong>en</strong>saje); // hace llegar el m<strong>en</strong>saje al proc. de v<strong>en</strong>tana<br />
}<br />
return (M<strong>en</strong>saje.wParam);<br />
9
La clase de V<strong>en</strong>tana<br />
typedef struct {<br />
UINT style; // combinación de estilos de clase<br />
WNDPROC lpfnWndProc; // Puntero al procedimi<strong>en</strong>to de v<strong>en</strong>tana<br />
int cbClsExtra; // num. bytes extra a asignar seguidos a esta estructura<br />
int cbWndExtra; // num. bytes extra a asignar seguidos a la instancia<br />
HINSTANCE hInstance; // handle a la instancia que conti<strong>en</strong>e el proc. v<strong>en</strong>tana<br />
HICON hIcon; // handle al icono de la clase (si NULL se da uno por def).<br />
HCURSOR hCursor; // handle al cursor de la clase<br />
HBRUSH hbrBackground; // handle a brocha para color de fondo, o un color<br />
LPCTSTR lpszM<strong>en</strong>uName; // nombre del m<strong>en</strong>ú asociado<br />
LPCTSTR lpszClassName; // nombre de la clase de v<strong>en</strong>tana<br />
} WNDCLASS, *PWNDCLASS;<br />
Tipos de clases de v<strong>en</strong>tana: del sistema (ej.: BUTTON, COMBOBOX,<br />
etc etc.), ) globales y locales de aplicación aplicación.<br />
Algunos estilos: CS_HREDRAW, CS_VREDRAW (redibuja la v<strong>en</strong>ta<br />
<strong>en</strong>tera si hay un cambio de tamaño horizontal), CS_NOCLOSE,.<br />
La estructura WNDCLASSEX permite asociar un icono pequeño a la<br />
v<strong>en</strong>tana (RegisterClassEx).<br />
10
Inicialización de la Instancia<br />
HWND CreateWindow(<br />
LPCTSTR lpClassName, // nombre registrado clase de v<strong>en</strong>tana<br />
LPCTSTR lpWindowName, // título de la v<strong>en</strong>tana<br />
DWORD dwStyle, // estilo de la v<strong>en</strong>tana<br />
iint t x, // posición i ió hhorizontal i t l dde lla v<strong>en</strong>tana t<br />
int y, // posición vertical de la v<strong>en</strong>tana<br />
int nWidth, // anchura de v<strong>en</strong>tana<br />
int nHeight nHeight, // altura de v<strong>en</strong>tana<br />
HWND hWndPar<strong>en</strong>t, // handle de la v<strong>en</strong>tana padre<br />
HMENU hM<strong>en</strong>u, // handle del m<strong>en</strong>ú de v<strong>en</strong>tana<br />
HINSTANCE hInstance hInstance, // handle a la instancia de la aplicación<br />
LPVOID lpParam ); // puntero a parámetros.<br />
CCreación ió dde una v<strong>en</strong>tana t dde una clase l registrada. i t d<br />
CreateWindowEx para estilos ext<strong>en</strong>didos (ej.: layered<br />
windows-> windows v<strong>en</strong>tanas no rectangulares o que cambian de<br />
forma)<br />
11
Estilos de V<strong>en</strong>tana<br />
WS_BORDER: v<strong>en</strong>tana con borde fino.<br />
WS_CAPTION: v<strong>en</strong>tana con barra de título (incluye WS_BORDER).<br />
WS WS_CHILD, CHILD WS WS_CHILDWINDOW CHILDWINDOW : v<strong>en</strong>tana t hij hija ( (no puede d tt<strong>en</strong>er m<strong>en</strong>ú ú ni i puede d usarse con<br />
WS_POPUP).<br />
WS_CLIPCHILDREN: Excluye el área ocupada por las v<strong>en</strong>tanas hijas cuando se dibuja e la padre.<br />
Se usa cuando se crea la v<strong>en</strong>tana padre.<br />
WS WS_CLIPSIBLINGS:<br />
CLIPSIBLINGS:<br />
WS_DISABLED: crea una v<strong>en</strong>tana deshabilitada.<br />
WS_DLGFRAME: v<strong>en</strong>tana con borde igual al de las cajas de diálogo.<br />
WS_GROUP: Primer control de un grupo.<br />
WS_HSCROLL: v<strong>en</strong>tana con scrooll horizonta.<br />
WS_ICONIC, WS_MINIMIZE: v<strong>en</strong>tana inicialm<strong>en</strong>te minimizada.<br />
WS_MAXIMIZE: v<strong>en</strong>tana inicialm<strong>en</strong>te maximizada.<br />
WS_MAXIMIZEBOX, _ , WS_MINIMIZEBOX _<br />
: v<strong>en</strong>tana con botón de maximizar/minimizar.<br />
WS_OVERLAPPED, WS_TILED; v<strong>en</strong>tana con título y borde.<br />
WS_OVERLAPPEDWINDOW, WS_TILEDWINDOW: v<strong>en</strong>tana con estilos: WS_OVERLAPPED,<br />
WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, y<br />
WS_MAXIMIZEBOX<br />
WS_POPUP: v<strong>en</strong>tana de pop-up.<br />
WS_POPUPWINDOW : v<strong>en</strong>tana de pop-up con WS_BORDER, WS_POPUP, y WS_SYSMENU<br />
WS_SIZEBOX, WS_THICKFRAME: v<strong>en</strong>tana con borde redim<strong>en</strong>sionable.<br />
WSS_S SYSMENU: S U v<strong>en</strong>tana e ta a co con m<strong>en</strong>ú e ú de sste sistema. a<br />
WS_TABSTOP: control que recibe el foco cuando se pulsa TAB.<br />
WS_VISIBLE: v<strong>en</strong>tana inicialm<strong>en</strong>te visible.<br />
12<br />
WS_VSCROLL: v<strong>en</strong>tana con barra de desplazami<strong>en</strong>to vertical.
Estilos de V<strong>en</strong>tana<br />
M<strong>en</strong>ú de sistema Barra de título Botones minimizar/<br />
maximizar/cerrar<br />
Area cli<strong>en</strong>te<br />
Scroll horizontal Scroll vertical<br />
borde<br />
13
M<strong>en</strong>sajes<br />
MM<strong>en</strong>sajes: j<br />
typedef struct<br />
{<br />
HWND hwnd; // handle a la v<strong>en</strong>tana que recibe el m<strong>en</strong>saje<br />
UINT message; // id<strong>en</strong>tificador del m<strong>en</strong>saje<br />
WPARAM wParam; // info adicional, dep<strong>en</strong>di<strong>en</strong>te del tipo de m<strong>en</strong>saje<br />
LPARAM lParam; // info adicional, dep<strong>en</strong>di<strong>en</strong>te del tipo de m<strong>en</strong>saje<br />
DWORD time; ; // instante <strong>en</strong> el que q el m<strong>en</strong>saje j fue <strong>en</strong>viado<br />
POINT pt; // posición del cursor <strong>en</strong> coord<strong>en</strong>adas de pantalla<br />
} MSG, *PMSG;<br />
Todos los m<strong>en</strong>sajes que <strong>en</strong>vía windows empiezan<br />
por WM WM_XXX XXX y están definidos <strong>en</strong> windows windows.h<br />
h<br />
14
GetMessage<br />
GetMessage: Espera a que llegue un m<strong>en</strong>saje m<strong>en</strong>saje.<br />
BOOL GetMessage( LPMSG lpMsg, HWND hWnd,<br />
UINT wMsgFilterMin, UINT wMsgFilterMax );<br />
lpMsg: Puntero a la estructura MSG que recibe el m<strong>en</strong>saje<br />
hWnd: Handle de la v<strong>en</strong>tana que recibe los m<strong>en</strong>sajes.<br />
wMsgFilterMin: M<strong>en</strong>or valor <strong>en</strong>tero del m<strong>en</strong>saje a recibir (ej.:<br />
WM_KEYFIRST, WM_MOUSEFIRST o WM_INPUT)<br />
wMsgFilterMax: Mayor valor <strong>en</strong>tero del m<strong>en</strong>saje a recibir (ej.:<br />
WM_KEYFIRST, WM_MOUSEFIRST o WM_INPUT)<br />
Retorno:<br />
Si se devuelve un m<strong>en</strong>saje distinto de WM_QUIT, el valor es distinto de cero.<br />
Si el m<strong>en</strong>saje es WM_QUIT, el valor es cero.<br />
Si hay un error el valor es -1. Por ejemplo, esto sucede si hWnd es un handle<br />
de v<strong>en</strong>tana inválida o lpWnd es un puntero inválido inválido.<br />
15
DispatchMessage<br />
MSG<br />
…<br />
hwnd=h<br />
…<br />
hinstance=h<br />
lpClassName = CN<br />
WNDCLASS<br />
…<br />
lpszClassName = CN<br />
…<br />
lpfnWndProc=proc<br />
DispatchMessage<br />
…<br />
hinstance=h1<br />
lpClassName = CN<br />
…<br />
hinstance=h2<br />
lpClassName = CN2<br />
…<br />
lpszClassName = CN2<br />
…<br />
lpfnWndProc=proc2<br />
instancias de v<strong>en</strong>tana<br />
…<br />
hinstance=h3<br />
lpClassName=CN3<br />
…<br />
lpszClassName = CN3<br />
…<br />
lpfnWndProc=proc3<br />
lpfnWndProc proc lpfnWndProc proc2 lpfnWndProc proc3<br />
clases de v<strong>en</strong>tana registradas<br />
LRESULT CALLBACK proc (HANDLE LRESULT CALLBACK proc2 LRESULT CALLBACK proc3<br />
hWnd, UINT m<strong>en</strong>saje, WPARAM (HANDLE hWnd, UINT (HANDLE hWnd, UINT<br />
wParam, LPARAM lParam){..}<br />
m<strong>en</strong>saje, WPARAM wParam, m<strong>en</strong>saje, WPARAM wParam, 16<br />
LPARAM lParam){..}<br />
LPARAM lParam){..}
Handles<br />
Un id<strong>en</strong>tificador para los distintos objetos: v<strong>en</strong>tanas v<strong>en</strong>tanas,<br />
controles (que son v<strong>en</strong>tanas), ficheros, imág<strong>en</strong>es,<br />
memoria, etc.<br />
Similar a punteros: se obti<strong>en</strong><strong>en</strong> y luego se destruy<strong>en</strong>.<br />
17
Gestionar un nuevo ev<strong>en</strong>to<br />
LRESULT CALLBACK GestorM<strong>en</strong>sajes( HANDLE hWnd, hWnd<br />
UINT m<strong>en</strong>saje,<br />
WPARAM wParam,<br />
LPARAM lParam)<br />
{<br />
HDC hDc; // Device context<br />
//…<br />
switch (m<strong>en</strong>saje)<br />
{<br />
case WM_LBUTTONDOWN:<br />
MessageBox((HWND)hWnd, TEXT("Button click"), TEXT("dialogo"), MB_ICONHAND);<br />
break;<br />
default: return DefWindowProc((HWND)hWnd,m<strong>en</strong>saje,wParam,lParam);<br />
}<br />
return (NULL);<br />
}<br />
18
Juegos de Caracteres<br />
~1890: 1890 BCDIC (6 bit bits->64 64 caracteres). t )<br />
~1950: ASCII (7 ( bits->128 caracteres). )<br />
ASCII ext<strong>en</strong>dido (8 bits->256 caracteres).<br />
páginas páginas de códigos regionales para los últimos<br />
128.<br />
DBCS: DBCS: los primeros 128 bytes igual que<br />
ASCII, los posteriores ocupan dos bytes.<br />
U Unicode: i d 16 bit bits (65536 caracteres). t )<br />
Sistema de doble anchura (wide char).<br />
19
Caracteres Unicode<br />
Tipo de datos wchar_t.<br />
Ej.: j wchar_t _ nombre[50]=L”Bjarne [ ] j Stroustrup”. p<br />
Mejor usar macros, que aseguran que el<br />
programa funciona <strong>en</strong> Unicode o ASCII:<br />
TCHAR * Nombre = TEXT(“Hola”);<br />
20
La Notación Húngara<br />
Conv<strong>en</strong>ción para los nombres de variables (uso de prefijos), de tal<br />
manera que al leerlos sepamos su tipo.<br />
Después del prefijo se empieza por mayúsculas.<br />
Ejemplo:<br />
hWnd es un handle (h) a una v<strong>en</strong>tana.<br />
lpfnWndProc es un puntero (p) largo (l) a una función (fn).<br />
Tipo de Dato Prefijo<br />
char c<br />
BYTE(unsigned char) by<br />
short n<br />
int i<br />
int cuando indica coord<strong>en</strong>adas x, y<br />
int cuando indica dim<strong>en</strong>siones cx, cyy<br />
WORD (unsigned int) w<br />
LONG (long) l<br />
Tipo de Dato Prefijo<br />
DWORD(unsigned long) dw<br />
BOOL(int) o Flag b ó f<br />
Handle h<br />
Puntero p<br />
Función fn<br />
Cad<strong>en</strong>a s<br />
Cad<strong>en</strong>a terminada <strong>en</strong> ‘\0’ sz
El API de <strong>Windows</strong><br />
Llamadas al sistema operativo operativo, almac<strong>en</strong>adas <strong>en</strong> DLLs DLLs.<br />
Win32, WinSock, WinInet, ODBC, etc.<br />
D<strong>en</strong>tro de Win32 se <strong>en</strong>globan como ext<strong>en</strong>siones el resto de las API<br />
que se puedan añadir a <strong>Windows</strong>.<br />
Win32 proprociona un <strong>en</strong>torno de programación común a la<br />
plataforma <strong>Windows</strong>: 3.1 (win32s), 95/98, NT4.0, 2000, CE, XP,<br />
Vista Vista.<br />
En algunas plataformas el win32 (p. ej. CE) no está implem<strong>en</strong>tada<br />
<strong>en</strong> su totalidad totalidad.<br />
Win32: CreateWindow(), RegisterClass(), ShowWindow(),<br />
UpdateWindow() UpdateWindow(), DrawText() DrawText(), etc etc.<br />
22
Win32<br />
Varias categorías de funciones:<br />
Administración de v<strong>en</strong>tanas (<strong>en</strong> user32.dll)<br />
Crear y administrar la GUI, despachar m<strong>en</strong>sajes, administrar<br />
v<strong>en</strong>tanas v<strong>en</strong>tanas, DDE. DDE<br />
Ej.: CreateWindow(), RegisterClass(), ShowWindow()<br />
Graphics Device Interface (GDI).<br />
GG<strong>en</strong>erar salidas lid <strong>en</strong> di distintos ti t di dispositivos: iti pantalla, t ll iimpresora. PP.ej.: j<br />
dibujar objetos.<br />
Ej.: BeginPaint(), GetCli<strong>en</strong>tRect(), DrawText(), EndPaint().<br />
MMedia di Control C t l Interface I t f (MCI) (MCI).<br />
Reproducir y Grabar Audio, uso de vídeo, control de dispositivos<br />
multimedia.<br />
SServicios i i ddel l Si Sistema. t<br />
Administración de memoria, archivos y procesos, funciones de trabajo<br />
<strong>en</strong> red, información del sistema, IPC.<br />
Remote Procedure Call (RPC).<br />
23
Bibliotecas de Ext<strong>en</strong>sión<br />
Proporcionan P i servicios i i a llas apliciones li i<br />
fuera del ámbito del Win32.<br />
Controles comunes.<br />
Cuadros de diálogo comunes.<br />
Descompresión de datos.<br />
Administración de intercambio dinámico de<br />
datos (DDE).<br />
Instalación de archivos.<br />
Intercambio dinámico de datos sobre redes.<br />
...<br />
24
Indice<br />
<strong>Programación</strong> bajo <strong>Windows</strong>.<br />
Introducción a las <strong>MFCs</strong> <strong>MFCs</strong>.<br />
Introducción.<br />
V<strong>en</strong>tana V<strong>en</strong>tana vacía sin el wizard wizard.<br />
Uso del wizard.<br />
Un Un vistazo a las clases de MFC MFC.<br />
Mapas de M<strong>en</strong>sajes.<br />
M<strong>en</strong>ús M<strong>en</strong>ús y Teclas Aceleradoras<br />
Aceleradoras.<br />
Diálogos Comunes.<br />
Controles.<br />
Controles.<br />
Clases de utilidad<br />
Arquitectura Docum<strong>en</strong>to/Vista.<br />
Aspectos avanzados de las <strong>MFCs</strong>.<br />
Bibliografía.<br />
25
Microsoft Foundation Classes<br />
El API para lla programación ió di directa dde aplicaciones li i Wi <strong>Windows</strong> d dda<br />
acceso total a la funcionalidad del sistema operativo, pero es de<br />
bajo nivel.<br />
MFC es un framework que ofrece una serie de funciones,<br />
constantes constantes, tipos de datos y clases que simplifica la creación de<br />
aplicaciones para las distintas plataformas <strong>Windows</strong>.<br />
Es la respuesta de Microsoft a frameworks de otras compañias<br />
como OWL de Borland.<br />
Visual C++ conti<strong>en</strong>e un asist<strong>en</strong>te (wizard) que facilita la creación de<br />
aplicaciones MFC (g<strong>en</strong>eración de código).<br />
26
Clases Básicas para la creación de v<strong>en</strong>tanas<br />
27
Secu<strong>en</strong>cia de Creación de una Aplicación<br />
28
Creación de una<br />
V<strong>en</strong>tana <strong>en</strong> Blanco sin<br />
el l wizard i d<br />
#include "stdafx.h"<br />
#i #include l d < f i h> // MFC core and d standard t d d compon<strong>en</strong>ts t Creación de una<br />
#include // MFC ext<strong>en</strong>sions<br />
// proyecto con Shared DLL<br />
#ifdef _DEBUG<br />
#define new DEBUG DEBUG_NEW NEW<br />
#<strong>en</strong>dif<br />
class CMainFrame : public CFrameWnd {<br />
public: p<br />
CMainFrame() { Create(NULL, _T("Hellow World Application")); } // suele ir <strong>en</strong> OnCreate()<br />
}; // se suele llamar a LoadFrame<br />
class HelloWorldApp : public CWinApp {<br />
public:<br />
virtual i t l BOOL IInitInstance(); itI t ()<br />
};<br />
HelloWorldApp theApp; // Declarar un unico objecto CWinApp<br />
BOOL HelloWorldApp::InitInstance()<br />
{<br />
CWinApp::InitInstance();<br />
SetRegistryKey(_T("Hello g y y(_ ( World Application"));<br />
pp ))<br />
CMainFrame* pFrame = new CMainFrame;<br />
if (!pFrame) return FALSE;<br />
m_pMainWnd = pFrame;<br />
pFrame->ShowWindow(SW_SHOW);<br />
pFrame->UpdateWindow();<br />
F U d t Wi d ()<br />
return TRUE;<br />
}<br />
//NOTA: El WinMain está d<strong>en</strong>tro del framework <strong>MFCs</strong><br />
29
Uso del Asist<strong>en</strong>te<br />
Configuración Inicial de la Aplicación<br />
File/new Project; seleccionar MFC Application<br />
30
Uso del Asist<strong>en</strong>te<br />
Configuración Inicial de la Aplicación<br />
Configurar el tipo de<br />
aplicación:<br />
•Single docum<strong>en</strong>t<br />
•Sin soporte de<br />
arquitectura<br />
Docum<strong>en</strong>to/Vista<br />
Docum<strong>en</strong>to/Vista.<br />
•MFC <strong>en</strong> librería estática<br />
(incluye <strong>en</strong> el exe las<br />
DLLs necesarias)<br />
31
Uso del Asist<strong>en</strong>te<br />
Configuración Inicial de la Aplicación<br />
Configurar el soporte para BBDD<br />
32
Uso del Asist<strong>en</strong>te<br />
Configuración Inicial de la Aplicación<br />
Configurar la interfaz de usuario<br />
33
Uso del Asist<strong>en</strong>te<br />
Configuración Inicial de la Aplicación<br />
Configurar nombre de las clases y de los ficheros que se van a g<strong>en</strong>erar<br />
34
Uso del Asist<strong>en</strong>te<br />
Aplicación G<strong>en</strong>erada<br />
35
Uso del Asist<strong>en</strong>te<br />
¿Qué ficheros se han g<strong>en</strong>erado?<br />
• DDefinición fi i ió dde nombres b dde llos<br />
recursos, para<br />
poder ser usados por la aplicación.<br />
Fichero de recursos (.rc ( y .rc2). )<br />
Clase de la v<strong>en</strong>tana de trabajo (hereda de CWnd),<br />
d<strong>en</strong>tro de la v<strong>en</strong>tana marco<br />
Clase Aplicación (hereda de CWinApp)<br />
Clase de la v<strong>en</strong>tana marco (hereda de CFrameWnd)<br />
• Cabeceras precompiladas. “stdafx.h” incluye las<br />
cabeceras comunes del sistema sistema. Se ha de incluir<br />
antes que cualquier otra<br />
36
Uso del Asist<strong>en</strong>te<br />
Recursos de la Aplicación<br />
Resource.h<br />
#define IDD_ABOUTBOX 100<br />
#define IDP_OLE_INIT_FAILED 100<br />
#define IDR_MAINFRAME IDR MAINFRAME 128<br />
#define IDR_Hello<strong>MFCs</strong>TYPE 129<br />
37
Uso del Asist<strong>en</strong>te<br />
Estructura de la Aplicación<br />
Wi WinMain(): M i ()<br />
D<strong>en</strong>tro del framework.<br />
Se llama a métodos miembros del único objeto de tipo CWinApp:<br />
InitApplication(): Normalm<strong>en</strong>te no hay que tocar este método.<br />
InitInstance(): Tareas g<strong>en</strong>erales de la aplicación, ej: inicializar OLE.<br />
Después se crean las v<strong>en</strong>tanas de la aplicación, y se hac<strong>en</strong> visibles<br />
(ShowWindow())<br />
Run(): Que implem<strong>en</strong>ta al bucle de m<strong>en</strong>sajes hasta que llega WM_QUIT.<br />
CWinApp:<br />
Clase que hay que subclasificar, se debe crear un objeto único global.<br />
Procesa m<strong>en</strong>sajes hasta que llega WM_QUIT, mom<strong>en</strong>to <strong>en</strong> el que<br />
ejecuta ExitInstance() por defecto defecto.<br />
Si no hay m<strong>en</strong>sajes, llama a onIdle(), vacía por defecto.<br />
38
Seccu<strong>en</strong>ccia<br />
dee<br />
Creaciónn<br />
de<br />
unaa<br />
Apliicacióón<br />
39
Uso del Asist<strong>en</strong>te<br />
Estructura de la Aplicación: La clase v<strong>en</strong>tana (CWnd)<br />
CCasi i ttodas d llas aplicaciones li i ti ti<strong>en</strong><strong>en</strong> una o más á v<strong>en</strong>tanas. t<br />
La clase base es CWnd.<br />
Conti<strong>en</strong>e un handle a la v<strong>en</strong>tana física de <strong>Windows</strong>.<br />
La v<strong>en</strong>tana física se crea mediante Create(), se destruye con el<br />
destructor de la subclase de CWnd. Parámetros de Create():<br />
lpszClassName: nombre de la clase registrada con<br />
AfxRegisterWindowClass() o NULL (atributos por defecto).<br />
lpszWindowName: nombre de la v<strong>en</strong>tana.<br />
dwStyle: Estilo de la v<strong>en</strong>tana a crear.<br />
rect: Refer<strong>en</strong>cia a un objeto constante de tipo RECT, para indicar<br />
posición y tamaño de la v<strong>en</strong>tana.<br />
pPar<strong>en</strong>tWindow: puntero al objecto CWnd padre de la v<strong>en</strong>tana. No<br />
puede d ser NULL NULL. Si lla v<strong>en</strong>tana es lla principal, i i l usar<br />
CreateWindowEx().<br />
nId: Id<strong>en</strong>tificador de la v<strong>en</strong>tana.<br />
pContext: C t t PPuntero t a un objeto bj t dde ti tipo CC CCreateContext, t C t t para<br />
asociar vistas y docum<strong>en</strong>tos a la v<strong>en</strong>tana, puede ser NULL.<br />
40
Uso del Asist<strong>en</strong>te<br />
Estructura de la Aplicación: La clase v<strong>en</strong>tana (CWnd)<br />
CW CWndd agrupa acciones i que se podían dí realizar li sobre b v<strong>en</strong>tanas. t<br />
Las hace más accesibles y seguras.<br />
Evita por p ejemplo j p t<strong>en</strong>er qque ppasar el handle como primer p parámtero p<br />
(almac<strong>en</strong>ado <strong>en</strong> el atributo m_hWnd).<br />
Ejemplo:<br />
los métodos de CWnd:<br />
void CWnd::MoveWindow( int x, int y,<br />
int nWidth, int nHeight,<br />
BOOL bRepaint = TRUE );<br />
void CWnd::MoveWindow( LPCRECT lpRect,<br />
BOOL bRepaint = TRUE );<br />
<strong>en</strong>capsulan la llamada a la API de <strong>Windows</strong>:<br />
BOOL MoveWindow( HWND hWnd, int X, int Y,<br />
int nWidth, int nHeight,<br />
BOOL bRepaint);<br />
41
Uso del Asist<strong>en</strong>te<br />
Estructura de la Aplicación: La clase CFrameWnd<br />
HHereda d dde CW CWnd, d es utilizado tili d <strong>en</strong> aplicaciones li i SDI SDI.<br />
Ti<strong>en</strong>e <strong>en</strong> su interior una v<strong>en</strong>tana hija que normalm<strong>en</strong>te será la v<strong>en</strong>tana<br />
principal de la aplicación.<br />
La v<strong>en</strong>tana <strong>en</strong>tana marco interacciona con el usuario s ario cambiando el tamaño tamaño,<br />
moviéndose, etc., y gestiona estos cambios provocando modificaciones <strong>en</strong><br />
la v<strong>en</strong>tana hija.<br />
Para crear una v<strong>en</strong>tana marco:<br />
Create(),<br />
LoadFrame(), que toma m<strong>en</strong>os parámetros. Toma valores por defecto<br />
de los recursos que se le pasan como parámetros: m<strong>en</strong>ú m<strong>en</strong>ú, título título, icono y<br />
tabla de teclas acelaradoras.<br />
virtual BOOL LoadFrame( UINT nIDResource,<br />
DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,<br />
CWnd* pPar<strong>en</strong>tWnd = NULL, CCreateContext* pContext = NULL );<br />
Se destruye llamando a DestroyWindow().<br />
Sus clases derivadas deb<strong>en</strong> declarar DECLARE DECLARE_DYNCREATE() DYNCREATE() (gestión<br />
dinámica de clases) si se usa la arquitectura docum<strong>en</strong>to/vista, y poner<br />
IMPLEMENT_DYNCREATE() <strong>en</strong> la implem<strong>en</strong>tación.<br />
42
Uso del Asist<strong>en</strong>te<br />
Handles<br />
Las clases de la MFC ocultan los handles (CWnd::m_hWnd), para facilitar<br />
su uso uso.<br />
Se pued<strong>en</strong> construir objetos a partir de elem<strong>en</strong>tos gráficos ya construidos:<br />
static CWnd* PASCAL FromHandle( HWND hWnd ) );<br />
El objeto devuelto es temporal (eliminado <strong>en</strong> próxima llamada a OnIdle()).<br />
Clases que <strong>en</strong>capsulan handles a objetos gráficos:<br />
Elem<strong>en</strong>to Gráfico Clase de Objeto<br />
HWND CWnd y derivadas<br />
HDC CDC y derivadas<br />
HMENU CM<strong>en</strong>u<br />
HPEN, HBRUSH, HFONT, HBITMAP,<br />
HPALETTE, HRGN<br />
CGdiObject<br />
HIMAGELIST CImageList<br />
SOCKET CSocket<br />
43
Uso del Asist<strong>en</strong>te<br />
¿Dónde está el bucle de ev<strong>en</strong>tos?<br />
Tabla con los elem<strong>en</strong>tos a manejar: el mapa de m<strong>en</strong>sajes.<br />
Mediante Macros, normalm<strong>en</strong>te insertadas por el asist<strong>en</strong>te.<br />
Declaración del mapa de m<strong>en</strong>sajes <strong>en</strong> la clase:<br />
DECLARE DECLARE_MESSAGE_MAP().<br />
MESSAGE MAP().<br />
Declaramos también los métodos que manejarán los m<strong>en</strong>sajes<br />
mediante afx_msg:<br />
class CMainFrame : public CFrameWnd {<br />
public: CMainFrame();<br />
protected:<br />
DECLARE DECLARE_DYNAMIC(CMainFrame)<br />
DYNAMIC(CM i F )<br />
// Funciones de asignación de m<strong>en</strong>sajes g<strong>en</strong>eradas<br />
protected:<br />
}; }<br />
afx afx_msg msg int OnCreate(LPCREATESTRUCT lpCreateStruct);<br />
afx_msg void OnSetFocus(CWnd *pOldWnd);<br />
DECLARE_MESSAGE_MAP()<br />
44
Uso del Asist<strong>en</strong>te<br />
¿Dónde está el bucle de ev<strong>en</strong>tos?<br />
Una vez declarado, , hay y que q definir el mapa p de m<strong>en</strong>sajes, j , y<br />
<strong>en</strong>lazar<br />
cada m<strong>en</strong>saje con la función que la va a procesar.<br />
En el fichero de implem<strong>en</strong>tación (.cpp) se añade:<br />
BEGIN_MESSAGE_MAP()<br />
//{{AFX_MSG_MAP(CMainFrame)<br />
ON_WM_CREATE() M<strong>en</strong>sajes que<br />
ON_WM_SETFOCUS() se van a tratar<br />
//}}AFX //}}AFX_MSG_MAP MSG MAP<br />
END_MESSAGE_MAP()<br />
Usado por versiones<br />
anteriores de Visual C++ C<br />
LLos m<strong>en</strong>sajes j no refer<strong>en</strong>ciados f i d <strong>en</strong> lla ttabla bl se pasan a lla clase l<br />
padre (o a la clase de la v<strong>en</strong>tana cont<strong>en</strong>edora), y así sucesivam<strong>en</strong>te<br />
hasta que se trate por algún ancestro.<br />
45
Uso del Asist<strong>en</strong>te<br />
Código G<strong>en</strong>erado: Hello<strong>MFCs</strong>.h<br />
// Hello<strong>MFCs</strong>.h: Hello<strong>MFCs</strong> h: archivo de <strong>en</strong>cabezado principal para la aplicación Hello<strong>MFCs</strong><br />
#pragma once<br />
#ifndef __AFXWIN_H__<br />
#error "incluir incluir 'stdafx stdafx.h h' antes de incluir este archivo para PCH" PCH<br />
#<strong>en</strong>dif<br />
#include "resource.h" // Símbolos principales<br />
class CHello<strong>MFCs</strong>App : public CWinApp {<br />
public: CHello<strong>MFCs</strong>App();<br />
// Reemplazos<br />
public:<br />
virtual BOOL InitInstance();<br />
// Implem<strong>en</strong>tación<br />
public:<br />
};<br />
afx_msg void OnAppAbout();<br />
DECLARE DECLARE_MESSAGE_MAP()<br />
MESSAGE MAP()<br />
extern CHello<strong>MFCs</strong>App theApp;<br />
46
#include "stdafx.h"<br />
#include "Hello<strong>MFCs</strong>.h"<br />
#include "MainFrm.h“<br />
#ifdef _DEBUG DEBUG Uso del Asist<strong>en</strong>te<br />
#define new DEBUG_NEW<br />
#<strong>en</strong>dif<br />
Código G<strong>en</strong>erado: Hello<strong>MFCs</strong>.cpp (i)<br />
BEGIN_MESSAGE_MAP(CHello<strong>MFCs</strong>App, CWinApp)<br />
ON_COMMAND(ID_APP_ABOUT, &CHello<strong>MFCs</strong>App::OnAppAbout)<br />
END_MESSAGE_MAP()<br />
CHello<strong>MFCs</strong>App::CHello<strong>MFCs</strong>App() {<br />
// TODO: agregar aquí el código de construcción, Colocar toda la inicialización importante <strong>en</strong> InitInstance }<br />
CHello<strong>MFCs</strong>App theApp; // El único objeto CHello<strong>MFCs</strong>App<br />
// Inicialización de CHello<strong>MFCs</strong>App<br />
BOOL CHello<strong>MFCs</strong>App::InitInstance() {<br />
}<br />
INITCOMMONCONTROLSEX InitCtrls;<br />
InitCtrls.dwSize = sizeof(InitCtrls);<br />
InitCtrls.dwICC = ICC_WIN95_CLASSES;<br />
InitCommonControlsEx(&InitCtrls);<br />
CWinApp::InitInstance();<br />
if (!AfxOleInit()) {// Inicializar bibliotecas OLE<br />
AfxMessageBox(IDP_OLE_INIT_FAILED);<br />
return FALSE; }<br />
AfxEnableControlContainer();<br />
SetRegistryKey( g y y(_ T("Aplicaciones ( p gg<strong>en</strong>eradas con el Asist<strong>en</strong>te ppara aplicaciones p local")); ));<br />
CMainFrame* pFrame = new CMainFrame;<br />
if (!pFrame) return FALSE;<br />
m_pMainWnd = pFrame;<br />
// Crear y cargar el marco con sus recursos<br />
pFrame pFrame->LoadFrame(IDR_MAINFRAME, >LoadFrame(IDR MAINFRAME WS WS_OVERLAPPEDWINDOW OVERLAPPEDWINDOW | FWS FWS_ADDTOTITLE, ADDTOTITLE NULL NULL,NULL); NULL);<br />
pFrame->ShowWindow(SW_SHOW); // Se ha inicializado la única v<strong>en</strong>tana; mostrarla y actualizarla<br />
pFrame->UpdateWindow();<br />
return TRUE;<br />
47
Cuadro de diálogo CAboutDlg utilizado<br />
// para el comando Acerca de<br />
class CAboutDlg : public Cdialog {<br />
public: CAboutDlg();<br />
// Datos del cuadro de diálogo<br />
<strong>en</strong>um { IDD = IDD_ABOUTBOX };<br />
protected:<br />
Uso del Asist<strong>en</strong>te<br />
Código G<strong>en</strong>erado: Hello<strong>MFCs</strong>.cpp (ii)<br />
virtual void DoDataExchange(CDataExchange* g ( g p pDX); ); // Compatibilidad p con DDX/DDV<br />
// Implem<strong>en</strong>tación<br />
protected:<br />
DECLARE_MESSAGE_MAP()<br />
};<br />
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) {}<br />
void CAboutDlg::DoDataExchange(CDataExchange* g g ( g p pDX) ) {<br />
CDialog::DoDataExchange(pDX);<br />
}<br />
BEGIN_MESSAGE_ MAP(CAboutDlg, ( g, CDialog) g)<br />
END_MESSAGE_MAP()<br />
// Comando de la aplicación para ejecutar el cuadro de diálogo<br />
void CHello<strong>MFCs</strong>App::OnAppAbout() pp pp () {<br />
CAboutDlg aboutDlg;<br />
aboutDlg.DoModal();<br />
}<br />
48
#pragma once<br />
#include "ChildView ChildView.h h"<br />
Uso del Asist<strong>en</strong>te<br />
Código G<strong>en</strong>erado: MainFrm.h (i)<br />
class CMainFrame : public CFrameWnd {<br />
Permite acceder a información <strong>en</strong> tiempo de<br />
public: CMainFrame();<br />
ejecución a la clase (puede usarse la macro<br />
protected: DECLARE_DYNAMIC(CMainFrame)<br />
DECLARE DYNAMIC(CMainFrame)<br />
RUNTIME RUNTIME_CLASS CLASS <strong>en</strong> lla arquitectura it t<br />
// Reemplazos<br />
docum<strong>en</strong>to/vista)<br />
public:<br />
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);<br />
virtual BOOL OnCmdMsg(UINT nID, nID int nCode, nCode void void* pExtra pExtra, AFX AFX_CMDHANDLERINFO CMDHANDLERINFO* pHandlerInfo);<br />
// Implem<strong>en</strong>tación<br />
public:<br />
virtual ~CMainFrame();<br />
#ifdef _DEBUG DEBUG<br />
virtual void AssertValid() const;<br />
virtual void Dump(CDumpContext& dc) const;<br />
#<strong>en</strong>dif<br />
protected: // Miembros incrustados de la barra de control<br />
CStatusBar m_wndStatusBar;<br />
CToolBar m_wndToolBar;<br />
CChildView mm_wndView; wndView;<br />
// Funciones de asignación de m<strong>en</strong>sajes g<strong>en</strong>eradas<br />
protected:<br />
afx afx_msg msg int OnCreate(LPCREATESTRUCT lpCreateStruct);<br />
afx_msg void OnSetFocus(CWnd *pOldWnd);<br />
DECLARE_MESSAGE_MAP()<br />
};<br />
49
#include "stdafx.h"<br />
#include "Hello<strong>MFCs</strong>.h“<br />
#include "MainFrm.h“<br />
#ifdef _DEBUG<br />
#define new DEBUG DEBUG_NEW NEW<br />
#<strong>en</strong>dif<br />
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)<br />
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)<br />
ON_WM_CREATE()<br />
ON_WM_SETFOCUS()<br />
END_MESSAGE_MAP()<br />
Uso del Asist<strong>en</strong>te<br />
Código G<strong>en</strong>erado: MainFrm.cpp (i)<br />
static UINT indicators[] = {ID {ID_SEPARATOR, SEPARATOR, ID ID_INDICATOR_CAPS, INDICATOR CAPS, ID_INDICATOR_NUM, ID INDICATOR NUM, ID ID_INDICATOR_SCRL, INDICATOR SCRL, };<br />
// Construcción y destrucción de CMainFrame<br />
CMainFrame::CMainFrame() {// TODO: agregar aquí el código de inicialización de miembros }<br />
CMainFrame::~CMainFrame() { }<br />
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)<br />
{<br />
if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;<br />
// Crear una vista para ocupar el área de cli<strong>en</strong>te del marco<br />
if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL)) {<br />
TRACE0("No se pudo crear la v<strong>en</strong>tana de vista\n");<br />
return -1; }<br />
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP<br />
| CBRS_ GRIPPER | CBRS_ TOOLTIPS | CBRS_ FLYBY | CBRS_SIZE_ DYNAMIC) )|| ||<br />
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) {<br />
TRACE0("No se pudo crear la barra de herrami<strong>en</strong>tas\n"); return -1; /* no se pudo crear */ }<br />
if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT))) {<br />
TRACE0("No se pudo crear la barra de estado\n"); return -1; /* No se pudo crear */}<br />
// TODO: eliminar estas tres líneas si no desea que la barra de herrami<strong>en</strong>tas se pueda acoplar<br />
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);<br />
EnableDocking(CBRS_ALIGN_ANY);<br />
DockControlBar(&m_wndToolBar);<br />
return 0; }<br />
50
Uso del Asist<strong>en</strong>te<br />
Código G<strong>en</strong>erado: MainFrm.cpp (ii)<br />
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) {<br />
// se llama por las <strong>MFCs</strong> antes de crear físicam<strong>en</strong>te la v<strong>en</strong>tana. se devuelve != 0 si la creación debe continuar, 0<br />
<strong>en</strong> otro caso.<br />
if( !CF !CFrameWnd::PreCreateWindow(cs) W d P C Wi d ( ) ) return FALSE FALSE;<br />
// TODO: modificar aquí la clase Window o los estilos cambiando CREATESTRUCT cs<br />
}<br />
cs.dwExStyle &= ~WS_EX_CLIENTEDGE;<br />
cs.lpszClass l Cl = Af AfxRegisterWndClass(0);<br />
R i t W dCl (0)<br />
return TRUE;<br />
#ifd #ifdef f _DEBUG DEBUG<br />
void CMainFrame::AssertValid() const { CFrameWnd::AssertValid();}<br />
void CMainFrame::Dump(CDumpContext& dc) const { CFrameWnd::Dump(dc); }<br />
#<strong>en</strong>dif //_DEBUG<br />
void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/) {<br />
// <strong>en</strong>viar foco a la v<strong>en</strong>tana de vista<br />
m_wndView.SetFocus();<br />
}<br />
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) {<br />
// Permitir que la vista se interrumpa primero <strong>en</strong> el comando<br />
if ( (m_wndView.OnCmdMsg(nID, dVi O C dM ( ID nCode, C d pExtra, E t pHandlerInfo)) H dl I f )) return t TRUE TRUE;<br />
// De lo contrario, proceder con el control predeterminado<br />
51<br />
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);<br />
}
ChildView.h: ChildView h: interfaz de la clase CChildView<br />
//<br />
#pragma once<br />
// V<strong>en</strong>tana de CChildView<br />
class CChildView : public CWnd {<br />
// Construcción<br />
public: CChildView();<br />
// Atributos<br />
public:<br />
// Operaciones<br />
public:<br />
// Reemplazos<br />
protected:<br />
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);<br />
// Implem<strong>en</strong>tación<br />
public:<br />
virtual ~CChildView();<br />
// Funciones de asignación de m<strong>en</strong>sajes g<strong>en</strong>eradas<br />
protected:<br />
};<br />
afx_msg void OnPaint();<br />
DECLARE_MESSAGE_MAP()<br />
Uso del Asist<strong>en</strong>te<br />
Código G<strong>en</strong>erado: ChildView.h<br />
52
#include "stdafx.h"<br />
#include "Hello<strong>MFCs</strong>.h"<br />
#include "ChildView ChildView.h h"<br />
#ifdef _DEBUG<br />
#define new DEBUG_NEW<br />
#<strong>en</strong>dif<br />
CChildView::CChildView() { }<br />
CChildView::~CChildView() { }<br />
BEGIN_MESSAGE_MAP(CChildView, CWnd)<br />
ON_WM_PAINT()<br />
END_MESSAGE_MAP()<br />
// Controladores de m<strong>en</strong>saje de CChildView<br />
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) {<br />
if (!CWnd::PreCreateWindow(cs)) return FALSE;<br />
}<br />
Uso del Asist<strong>en</strong>te<br />
Código G<strong>en</strong>erado: ChildView.cpp<br />
cs.dwExStyle y |= | WS_EX_CLIENTEDGE;<br />
_ _<br />
cs.style &= ~WS_BORDER;<br />
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,<br />
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast(COLOR_WINDOW+1), NULL);<br />
return TRUE;<br />
void CChildView::OnPaint() {}<br />
53
Uso del Asist<strong>en</strong>te<br />
Modificando la aplicación<br />
void CChildView::OnPaint() ()<br />
{<br />
CPaintDC dc(this); // Contexto de dispositivo para dibujo<br />
dc.Rectangle(200, g ( , 200, , 300, , 320); );<br />
dc.DrawText( "Hola <strong>MFCs</strong>!", -1,<br />
CRect( 200, 200, 300, 320),<br />
DT_SINGLELINE|DT_CENTER|<br />
DT_ VCENTER); );<br />
}<br />
54
Bucle de M<strong>en</strong>sajes
Las clases MFC<br />
Arbol jerárquico de clases, con raíz CObject.<br />
CObject permite persist<strong>en</strong>cia (serialize()), chequeo de consist<strong>en</strong>cia de<br />
atributos (AssertValid()), …<br />
Gestión de excepciones: heredan de CException<br />
CException.<br />
ReportError(): muestra la excepción <strong>en</strong> una v<strong>en</strong>tana.<br />
GetErrorMessage(): descripción del error.<br />
Gestión de archivos: CFile.<br />
Contextos de dispositivo: CDC e hijas:<br />
AAcceso al l áárea completa l t dde lla v<strong>en</strong>tana: t CWi CWindowDC. d DC<br />
Dibujo <strong>en</strong> función del ev<strong>en</strong>to WM_PAINT: CPaintDC.<br />
Gestión de Objetos j Gráficos: CGdiObject. j<br />
Gestión de fu<strong>en</strong>tes de letras: CFont.<br />
Gestión de mapas de bits de colores: CBitmap.<br />
Uso de Brochas: CBrush CBrush.<br />
Manejo de plumas: CP<strong>en</strong>.<br />
56
Las clases MFC<br />
CC CCmdTarget: dT t clase l bbase para lla gestión ió dde m<strong>en</strong>sajes. j<br />
Clases docum<strong>en</strong>to: CDocum<strong>en</strong>t, con hijas: COleDocum<strong>en</strong>t,<br />
CHtmlEditDoc, , etc.<br />
Gestión de comunicaciones OLE: COleObjectFactory,<br />
COleDataSource, COleDropTarget, etc.<br />
CW CWnd: d Gestión G tió dde v<strong>en</strong>tanas. t<br />
CFrameWnd e hijas (v<strong>en</strong>tana principal).<br />
CSplitterWnd p (p (paneles de v<strong>en</strong>tana). )<br />
CControlBar (gestión de barras de control y estado): CToolBar,<br />
CStateBar, CReBar, CDialogBar.<br />
CDialog: gestión de v<strong>en</strong>tanas de diálogo. diálogo CColorDialog (selección<br />
de colores), CPrintDialog (imprimir), CFileDialog (elegir un fichero),<br />
CFontDialog (selección de fu<strong>en</strong>tes).<br />
57
Las clases MFC<br />
Gestión de vistas <strong>en</strong> la arquitectura q Docum<strong>en</strong>to/Vista:<br />
CView.<br />
CEditView: Edición de textos.<br />
CHtmlView: Visualización de páginas HTML.<br />
Controles (heredan de CWnd):<br />
Texto estático (CS (CStatic). )<br />
Texto modificable (CEdit).<br />
Listas de elem<strong>en</strong>tos: CListBox, CListBox CCheckListBox CCheckListBox, CDrawListBox<br />
CDrawListBox,<br />
etc.<br />
Clases que no heredan de CObject: Clases de soporte<br />
(ej.: CWaitCursor), API servidor de Internet,<br />
sincronización, etc.<br />
58
Las clases MFC<br />
59
CObject<br />
Las<br />
clases<br />
MFC<br />
CCmdTarget<br />
60
ject<br />
COb<br />
Las clases MFC<br />
61
Mapas de M<strong>en</strong>sajes<br />
Subclases de CCmdTarget.<br />
Declaración del mapa de m<strong>en</strong>sajes: DECLARE_MESSAGE_MAP(),<br />
que nos crea:<br />
Un vector de m<strong>en</strong>sajes privado ( (_messageEntries).<br />
messageEntries)<br />
Un puntero protegido al inicio del vector (messageMap).<br />
Método virtual GetMessageMap(), que devuelve el cont<strong>en</strong>ido de<br />
messageMap. M<br />
Declaración de los métodos que gestionarán los ev<strong>en</strong>tos (precederlos<br />
de afx_msg). g)<br />
Definir la lista que relaciona ev<strong>en</strong>tos con las funciones que los<br />
gestionan:<br />
BEGIN BEGIN_MESSAGE_MAP(clase,claseBase)<br />
MESSAGE MAP(clase claseBase)<br />
Sintaxis que dep<strong>en</strong>de del tipo de ev<strong>en</strong>to: comando, v<strong>en</strong>tana o controles.<br />
END_MESSAGE_MAP()<br />
62
M<strong>en</strong>sajes de V<strong>en</strong>tana<br />
110 tipos de m<strong>en</strong>sajes, producidos por la v<strong>en</strong>tana que<br />
estamos gestionando.<br />
EEmpiezan i por WM WM_XX XX ( (excepto t WM WM_COMMAND).<br />
COMMAND)<br />
Se defin<strong>en</strong> <strong>en</strong> la lista con ON_+.<br />
Ej Ejemplo, l para WM WM_PAINT, PAINT WM WM_RBUTTON_DOWN:<br />
RBUTTON DOWN<br />
BEGIN_MESSAGE_MAP(CChildView, CWnd)<br />
ON ON_WM_PAINT()<br />
WM PAINT()<br />
ON_WM_RBUTTON_DOWN()<br />
END_MESSAGE_MAP()<br />
Se llama a OnPaint() y a OnRButtonDown(UINT, CPoint).<br />
Podemos usar el asist<strong>en</strong>te para gestionar esta lista.<br />
63
M<strong>en</strong>sajes de V<strong>en</strong>tana<br />
Ejemplo: Capturar el ev<strong>en</strong>to WM_LBUTTONDOWN<br />
//ChildView //ChildView.h h<br />
class CChildView : public CWnd<br />
{<br />
public:<br />
CChildView();<br />
protected: p<br />
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);<br />
CPoint lastClicked;<br />
// Implem<strong>en</strong>tación<br />
public:<br />
virtual ~CChildView();<br />
// Funciones de asignación de m<strong>en</strong>sajes g<strong>en</strong>eradas<br />
protected:<br />
afx_msg void OnPaint();<br />
DECLARE_MESSAGE_MAP()<br />
public: bli<br />
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);<br />
};<br />
64
M<strong>en</strong>sajes de V<strong>en</strong>tana<br />
Ejemplo: Capturar el ev<strong>en</strong>to WM_LBUTTONDOWN<br />
//ChildView.cpp<br />
CChildView::CChildView() : lastClicked ( (-1, 1 -1) 1) {}<br />
BEGIN_MESSAGE_MAP(CChildView, CWnd)<br />
ON_WM_PAINT()<br />
ON_WM_LBUTTONDOWN()<br />
END END_MESSAGE_MAP()<br />
MESSAGE MAP()<br />
void CChildView::OnPaint() {<br />
CPaintDC dc(this); // Contexto de dispositivo para dibujo<br />
}<br />
dc.Rectangle(200, 200, 300, 320);<br />
dc.DrawText( "Hola <strong>MFCs</strong>!", -1, CRect( 200, 200, 300, 320),<br />
DT DT_SINGLELINE|DT_CENTER|DT_VCENTER);<br />
SINGLELINE|DT CENTER|DT VCENTER);<br />
if (lastClicked.x>=0 && lastClicked.y>0)<br />
dc.TextOut( lastClicked.x, lastClicked.y, "click");<br />
void CChildView::OnLButtonDown(UINT nFlags, CPoint point) {<br />
lastClicked=point;<br />
InvalidateRect(NULL);<br />
CW CWnd::OnLButtonDown(nFlags, d O LB tt D ( Fl point); i t)<br />
}<br />
65
M<strong>en</strong>sajes de V<strong>en</strong>tana<br />
Ejemplo: Capturar el ev<strong>en</strong>to WM_LBUTTONDOWN<br />
66
M<strong>en</strong>sajes de Controles<br />
EEv<strong>en</strong>tos t que lanza l lla v<strong>en</strong>tana t hij hija al l padre d que lla<br />
conti<strong>en</strong>e.<br />
Ejemplo: el control de edición manda el m<strong>en</strong>saje<br />
EN_CHANGE cuando se modifica el texto que conti<strong>en</strong>e.<br />
Tipos: p<br />
ON_BN_XX: m<strong>en</strong>sajes de botones.<br />
ON_EN_XX: m<strong>en</strong>sajes de editores.<br />
ON ON_CB_XX: CB XX m<strong>en</strong>sajes j dde combo-boxes. b b<br />
ON_LBN_XX: m<strong>en</strong>sajes de listas.<br />
Se mandan mediante el m<strong>en</strong>saje WM WM_COMMAND.<br />
COMMAND<br />
WM_NOTIFY, ON_NOTIFY() para que la función que<br />
gestiona el ev<strong>en</strong>to reciba parámetros.<br />
67
M<strong>en</strong>sajes de Comando<br />
Provi<strong>en</strong><strong>en</strong> de m<strong>en</strong>ús, barras de herrami<strong>en</strong>tas,<br />
teclas aceleradoras y botones.<br />
Macro ON_COMMAND(ev<strong>en</strong>to,metodo).<br />
BEGIN BEGIN_MESSAGE_MAP(CHello<strong>MFCs</strong>App, MESSAGE MAP(CH ll MFC A CWinApp) CWi A )<br />
ON_COMMAND(ID_APP_ABOUT, &CHello<strong>MFCs</strong>App::OnAppAbout)<br />
END_MESSAGE_MAP()<br />
68
M<strong>en</strong>sajes de Comando<br />
Ejemplo: Añadir un elem<strong>en</strong>to de M<strong>en</strong>ú<br />
69
M<strong>en</strong>sajes de Comando<br />
Ejemplo: Añadir el Gestor de Ev<strong>en</strong>tos<br />
70
#pragma once<br />
// V<strong>en</strong>tana de CChildView<br />
class CChildView : public CWnd{<br />
public:<br />
CChildView();<br />
protected: p<br />
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);<br />
private:<br />
const int numColores;<br />
UINT * const CodigoColor; g<br />
CPoint lastClicked;<br />
int curr<strong>en</strong>tColor;<br />
// Implem<strong>en</strong>tación<br />
p<br />
public:<br />
virtual ~CChildView();<br />
protected:<br />
public:<br />
public:<br />
};<br />
M<strong>en</strong>sajes de Comando<br />
// Funciones de asignación g de m<strong>en</strong>sajes j gg<strong>en</strong>eradas<br />
afx_msg void OnPaint();<br />
DECLARE_MESSAGE_MAP()<br />
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);<br />
afx_msg void OnCambiacolor();<br />
Ejemplo: ChildView.h<br />
71
CChildView::CChildView() : numColores (4),<br />
CodigoColor (new UINT[numColores]), curr<strong>en</strong>tColor(0) {<br />
lastClicked = CPoint(-1, -1);<br />
}<br />
CCodigoColor[0] di C l [0] = RGB(0 RGB(0, 00, 0) 0); // Bl Black k<br />
CodigoColor[1] = RGB(255, 0, 0); // Red<br />
CodigoColor[2] = RGB(0, 255, 0); // Gre<strong>en</strong><br />
CodigoColor[3] = RGB(0, 0, 255); // Blue<br />
M<strong>en</strong>sajes de Comando<br />
BEGIN_MESSAGE_MAP(CChildView, CWnd)<br />
ON_WM_PAINT()<br />
ON ON_WM_LBUTTONDOWN()<br />
WM LBUTTONDOWN()<br />
ON_COMMAND(ID_CAMBIACOLOR, &CChildView::OnCambiacolor)<br />
END_MESSAGE_MAP()<br />
Ejemplo: ChildView.cpp<br />
void id CChildVi CChildView::OnPaint() O P i t() {<br />
CPaintDC dc(this); // Contexto de dispositivo para dibujo<br />
dc.Rectangle(200, 200, 300, 320);<br />
dc.DrawText( "Hola <strong>MFCs</strong>!", -1, CRect( 200, 200, 300, 320),DT_SINGLELINE|DT_CENTER|DT_VCENTER);<br />
if (l (lastClicked.x>=0 tCli k d 0 && llastClicked.y>0) tCli k d 0) {<br />
}<br />
}<br />
dc.SetTextColor(CodigoColor[curr<strong>en</strong>tColor]);<br />
dc.DrawText( "Click", -1, CRect( lastClicked, CPoint(lastClicked.x+50, lastClicked.y+20)),<br />
DT_SINGLELINE|DT_CENTER|DT_VCENTER);<br />
void CChildView::OnCambiacolor() { curr<strong>en</strong>tColor = (curr<strong>en</strong>tColor + 1) % numColores; }<br />
72
M<strong>en</strong>sajes de Comando<br />
Resultado<br />
CChildView::~CChildView()<br />
{<br />
delete [ ] CodigoColor;<br />
}<br />
73
Aplicaciones basadas <strong>en</strong> diálogos<br />
Se pued<strong>en</strong> crear aplicaciones basadas <strong>en</strong><br />
diálogo.<br />
Por defecto sin m<strong>en</strong>ús ni teclas aceleradoras.<br />
Para implem<strong>en</strong>tar aplicaciones s<strong>en</strong>cillas,<br />
basadas <strong>en</strong> formularios de toma de datos.<br />
La v<strong>en</strong>tana principal hereda de CDialog CDialog, o de<br />
CDHTMLDialog (para mostrar páginas <strong>en</strong><br />
HTML) HTML).
MapasdeDatos<br />
Mapas de Datos<br />
Intercambio I t bi de d Datos D t de d Diálogo Diál (DDX). (DDX)<br />
Asociar variables a controles del diálogo g<br />
para intercambiar información.<br />
Por Por valor (las variables conti<strong>en</strong><strong>en</strong> el valor<br />
del control) o por refer<strong>en</strong>cia (control).<br />
UpdateData(FALSE) UpdateData(FALSE) actualiza los<br />
controles a partir de las variables.<br />
UpdateData(TRUE) actualiza las variables<br />
a partir del cont<strong>en</strong>ido de los controles.<br />
75
MapasdeDatos<br />
Mapas de Datos<br />
Ejemplo<br />
76
MapasdeDatos<br />
Mapas de Datos<br />
Ejemplo<br />
77
#pragma once<br />
MapasdeDatos<br />
Mapas de Datos<br />
CSimpleDlg.h<br />
// Cuadro de diálogo g de CSimpleDlg p g<br />
class CSimpleDlg : public Cdialog {<br />
// Construcción<br />
public:<br />
CSimpleDlg(CWnd* p g( p pPar<strong>en</strong>t = NULL); ); // Constructor estándar<br />
// Datos del cuadro de diálogo<br />
<strong>en</strong>um { IDD = IDD_SIMPLEDIALOGO_DIALOG };<br />
protected:<br />
virtual void DoDataExchange(CDataExchange* g ( g p pDX); ) // Compatibilidad p con DDX/DDV<br />
// Implem<strong>en</strong>tación<br />
protected:<br />
HICON m_hIcon;<br />
// Funciones de asignación g de m<strong>en</strong>sajes j gg<strong>en</strong>eradas<br />
virtual BOOL OnInitDialog();<br />
afx_msg void OnPaint();<br />
afx_msg HCURSOR OnQueryDragIcon();<br />
DECLARE_MESSAGE_MAP()<br />
_ _ ()<br />
private:<br />
CString strUsrName; // Nombre del usuario<br />
CString strSaludo; // Saludo<br />
public:<br />
afx_msg void OnEnChangeNombre();<br />
afx_msg void OnBnClickedOk();<br />
afx_msg void OnEnKillfocusNombre();<br />
};<br />
78
CSi CSimpleDlg::CSimpleDlg(CWnd* l Dl CSi l Dl (CW d* pPar<strong>en</strong>t P t /*=NULL*/) /* NULL*/)<br />
: CDialog(CSimpleDlg::IDD, pPar<strong>en</strong>t)<br />
, strUsrName(_T(""))<br />
, strSaludo(_T(""))<br />
{<br />
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);<br />
}<br />
void id CSi CSimpleDlg::DoDataExchange(CDataExchange* l Dl D D t E h (CD t E h * pDX) DX)<br />
{<br />
CDialog::DoDataExchange(pDX);<br />
DDX_Text(pDX, IDC_NOMBRE, strUsrName);<br />
DDV DDV_MaxChars(pDX, M Ch ( DX strUsrName, t U N 128); 128)<br />
DDX_Text(pDX, IDC_SALUDO, strSaludo);<br />
}<br />
BEGIN BEGIN_MESSAGE_MAP(CSimpleDlg, MESSAGE MAP(CSi l Dl CDi CDialog) l )<br />
ON_WM_PAINT()<br />
ON_WM_QUERYDRAGICON()<br />
//}}AFX_MSG_MAP<br />
MapasdeDatos<br />
Mapas de Datos<br />
ON ON_EN_CHANGE(IDC_NOMBRE, EN CHANGE(IDC NOMBRE &CSi &CSimpleDlg::OnEnChangeNombre)<br />
l Dl O E Ch N b )<br />
ON_BN_CLICKED(IDOK, &CSimpleDlg::OnBnClickedOk)<br />
ON_EN_KILLFOCUS(IDC_NOMBRE, &CSimpleDlg::OnEnKillfocusNombre)<br />
END_MESSAGE_MAP()<br />
CSimpleDlg.cpp (i)<br />
79
MapasdeDatos<br />
Mapas de Datos<br />
CSimpleDlg.cpp (i)<br />
void CSimpleDlg::OnBnClickedOk()<br />
{<br />
// TODO: Add your control notification handler code here<br />
//OnOK();<br />
}<br />
UpdateData(TRUE);<br />
p ( );<br />
strSaludo = "Hola "+strUsrName+"!";<br />
UpdateData(FALSE);<br />
void CSimpleDlg::OnEnKillfocusNombre()<br />
{ // si ponemos este código <strong>en</strong> EN_CHANGE, se actualiza <strong>en</strong> tiempo de ejecución<br />
UpdateData(TRUE);<br />
strSaludo = "Hola "+strUsrName+"!";<br />
UpdateData(FALSE);<br />
}<br />
80
M<strong>en</strong>ús<br />
Se pued<strong>en</strong> crear <strong>en</strong> el editor de recursos recursos.<br />
El asist<strong>en</strong>te crea un m<strong>en</strong>ú estático <strong>en</strong> la v<strong>en</strong>tana marco (mismo<br />
id<strong>en</strong>tificador que la tabla aceleradora y el icono).<br />
Se cargan todos los recursos <strong>en</strong> InitInstance():<br />
pFrame->LoadFrame(IDR_MAINFRAME,<br />
WS_ OVERLAPPEDWINDOW |FWS | _ ADDTOTITLE, , NULL,NULL); , );<br />
Elem<strong>en</strong>tos del m<strong>en</strong>ú de dos tipos:<br />
pop-up (abr<strong>en</strong> otros m<strong>en</strong>ús).<br />
activos, que g<strong>en</strong>eran un m<strong>en</strong>saje de comando a la aplicación.<br />
Normalm<strong>en</strong>te a través del asist<strong>en</strong>te.<br />
DDos m<strong>en</strong>sajes: j COMMAND y UPDATE_COMMAND_UI.<br />
UPDATE COMMAND UI<br />
El último permite cambiar el aspecto del item de m<strong>en</strong>ú (cambiar<br />
texto, añadir un check, etc.)<br />
81
M<strong>en</strong>ús<br />
Ejemplo<br />
CChildView::CChildView() : numColores (4), CodigoColor (new UINT[numColores]),<br />
curr<strong>en</strong>tColor(0), NombreColor(new CString[numColores]) {<br />
lastClicked = CPoint(-1, -1);<br />
CodigoColor[0] = RGB(0, 0, 0); // Black<br />
//…<br />
NombreColor[0] = "Negro";<br />
//…<br />
}<br />
CChildView::~CChildView() {<br />
delete [] CodigoColor;<br />
delete [] NombreColor;<br />
}<br />
BEGIN_MESSAGE_MAP(CChildView, CWnd)<br />
ON_WM_PAINT()<br />
ON ON_WM_LBUTTONDOWN()<br />
WM LBUTTONDOWN()<br />
ON_COMMAND(ID_CAMBIACOLOR, &CChildView::OnCambiacolor)<br />
ON_UPDATE_COMMAND_UI(ID_CAMBIACOLOR, &CChildView::OnUpdateCambiacolor)<br />
END_MESSAGE_MAP()<br />
void CChildView::OnUpdateCambiacolor(CCmdUI *pCmdUI) {<br />
pCmdUI->SetText("Cambia Color a "+NombreColor[(curr<strong>en</strong>tColor+1)%numColores]);<br />
}<br />
82
CM<strong>en</strong>u<br />
Para cambiar <strong>en</strong>tre distintos m<strong>en</strong>ús, o cargar<br />
uno dinámicam<strong>en</strong>te se usa la clase CM<strong>en</strong>u.<br />
Enmascara un HMENU (<strong>en</strong> m_hM<strong>en</strong>u).<br />
Asignación a la v<strong>en</strong>tana con SetM<strong>en</strong>u().<br />
Algunas funciones miembro:<br />
LoadM<strong>en</strong>u(): LoadM<strong>en</strong>u(): carga un m<strong>en</strong>ú creado como un recurso recurso.<br />
CreateM<strong>en</strong>u(), CreatePopupM<strong>en</strong>u(): crea un m<strong>en</strong>ú<br />
vacío (normal y emerg<strong>en</strong>te).<br />
Attach(): Asocia un CM<strong>en</strong>u a un recurso id<strong>en</strong>tificado por<br />
su HMENU.<br />
83
M<strong>en</strong>ús<br />
Ejemplo: Añadir un M<strong>en</strong>ú a un Diálogo<br />
1<br />
2<br />
3<br />
84
M<strong>en</strong>ús<br />
Ejemplo: Añadir un M<strong>en</strong>ú a un Diálogo<br />
11. Crear el m<strong>en</strong>ú <strong>en</strong> el editor de recursos<br />
(ID=IDR_SIMPLEDIALOG).<br />
22. Añ Añadir di un atributo t ib t dde ti tipo CM CM<strong>en</strong>u a lla clase l CSi CSimpleDlg, l Dl<br />
gestión de items de m<strong>en</strong>ú.<br />
class CSimpleDlg : public CDialog {<br />
…<br />
private:<br />
CM<strong>en</strong>u m<strong>en</strong>u;<br />
CListBox fileListBox; // DDX, control<br />
public:<br />
afx_msg g void OnFicheroSeleccionar(); (); // gestión g de items de m<strong>en</strong>ú<br />
afx_msg void OnFicheroSalir();<br />
};<br />
85
CSimpleDlg::CSimpleDlg(CWnd* pPar<strong>en</strong>t /*=NULL*/)<br />
: CDialog(CSimpleDlg::IDD, pPar<strong>en</strong>t), strUsrName(_T("")), strSaludo(_T("")), m<strong>en</strong>u() {<br />
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);<br />
M<strong>en</strong>ús<br />
}<br />
void CSimpleDlg::DoDataExchange(CDataExchange* pDX) {<br />
CDialog::DoDataExchange(pDX);<br />
DDX_Text(pDX, _ (p IDC_NOMBRE, _ strUsrName); )<br />
DDV_MaxChars(pDX, strUsrName, 12);<br />
DDX_Text(pDX, IDC_SALUDO, strSaludo);<br />
DDX_Control(pDX, IDC_FICHEROS, fileListBox);<br />
}<br />
M<strong>en</strong>ús<br />
CSimpleDlg.cpp<br />
BEGIN_MESSAGE_MAP(CSimpleDlg, CDialog)<br />
ON_WM_PAINT()<br />
ON_WM_QUERYDRAGICON() ()<br />
//}}AFX_MSG_MAP<br />
ON_EN_CHANGE(IDC_NOMBRE, &CSimpleDlg::OnEnChangeNombre)<br />
ON_BN_CLICKED(IDOK, &CSimpleDlg::OnBnClickedOk)<br />
ON_EN_KILLFOCUS(IDC_NOMBRE, &CSimpleDlg::OnEnKillfocusNombre)<br />
ON_COMMAND(ID_FICHERO_SELECCIONAR, &CSimpleDlg::OnFicheroSeleccionar)<br />
ON_COMMAND(ID_FICHERO_SALIR, &CSimpleDlg::OnFicheroSalir)<br />
END_MESSAGE_MAP()<br />
BOOL CSimpleDlg::OnInitDialog() {<br />
CDialog::OnInitDialog();<br />
SetIcon(m_hIcon, TRUE); // Establecer icono grande<br />
}<br />
SetIcon(m_hIcon, FALSE); // Establecer icono pequeño<br />
m<strong>en</strong>u.LoadM<strong>en</strong>u(IDR_SIMPLEDIALOGO);<br />
SetM<strong>en</strong>u(&m<strong>en</strong>u);<br />
return TRUE; // Devuelve TRUE a m<strong>en</strong>os que establezca el foco <strong>en</strong> un control<br />
86
M<strong>en</strong>ús<br />
CSimpleDlg.cpp<br />
void CSimpleDlg::OnFicheroSeleccionar()<br />
{<br />
LPCTSTR C S szCppFilters= C "C++ C Files (* (*.cpp)|*.cpp|All )|* | Files (* (*.*)|*.*||"; *)|* *||<br />
CFileDialog fd(TRUE, "Cpp", "*.cpp",<br />
OFN OFN_FILEMUSTEXIST| FILEMUSTEXIST| OFN_HIDEREADONLY, OFN HIDEREADONLY szCppFilters, szCppFilters this);<br />
if( fd.DoModal ()==IDOK ) {<br />
CString pathName = fd.GetPathName();<br />
UpdateData(TRUE);<br />
fil fileListBox.AddString(pathName);<br />
Li tB AddSt i ( thN )<br />
UpdateData(FALSE);<br />
}<br />
}<br />
void CSimpleDlg::OnFicheroSalir() {<br />
PostMessage(WM_QUIT);<br />
}<br />
87
M<strong>en</strong>ús<br />
Ejemplo: Añadir un M<strong>en</strong>ú Emerg<strong>en</strong>te Dinámico<br />
class CSimpleDlg : public CDialog<br />
{<br />
private:<br />
public:<br />
};<br />
// …<br />
CM<strong>en</strong>u pm<strong>en</strong>u;<br />
afx_msg g void OnRButtonDown(UINT ( nFlags, g , CPoint p point); ); //con asist<strong>en</strong>te<br />
afx_msg void OnItem1(); // a mano<br />
88
CSimpleDlg::CSimpleDlg(CWnd* pPar<strong>en</strong>t /*=NULL*/)<br />
M<strong>en</strong>ús<br />
: CDialog(CSimpleDlg::IDD, pPar<strong>en</strong>t)<br />
, strUsrName(_T("")) , strSaludo(_T("")) , m<strong>en</strong>u(), pm<strong>en</strong>u() {<br />
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); CSimpleDlg.cpp<br />
}<br />
BEGIN_MESSAGE_ MAP(CSimpleDlg, ( p g, CDialog) g)<br />
ON_WM_PAINT()<br />
ON_WM_QUERYDRAGICON()<br />
//}}AFX_MSG_MAP<br />
// …<br />
ON_COMMAND(ID_FICHERO_SELECCIONAR, &CSimpleDlg::OnFicheroSeleccionar)<br />
ON_COMMAND(ID_FICHERO_SALIR, &CSimpleDlg::OnFicheroSalir)<br />
ON_COMMAND(ID_FICHERO_SALIR+1, &CSimpleDlg::OnItem1)<br />
ON ON_WM_RBUTTONDOWN()<br />
WM RBUTTONDOWN()<br />
END_MESSAGE_MAP()<br />
BOOL CSimpleDlg::OnInitDialog() {<br />
CDialog::OnInitDialog();<br />
SetIcon(m_hIcon, TRUE); // Establecer icono grande<br />
SetIcon(m_hIcon, FALSE); // Establecer icono pequeño<br />
m<strong>en</strong>u.LoadM<strong>en</strong>u(IDR ( _ SIMPLEDIALOGO); );<br />
SetM<strong>en</strong>u(&m<strong>en</strong>u);<br />
pm<strong>en</strong>u.CreatePopupM<strong>en</strong>u();<br />
pm<strong>en</strong>u.App<strong>en</strong>dM<strong>en</strong>u(MF_STRING, ID_FICHERO_SALIR+1, "Item 1");<br />
pm<strong>en</strong>u pm<strong>en</strong>u.App<strong>en</strong>dM<strong>en</strong>u(MF_STRING, App<strong>en</strong>dM<strong>en</strong>u(MF STRING ID ID_FICHERO_SELECCIONAR, FICHERO SELECCIONAR "Seleccionar Seleccionar Fichero"); Fichero );<br />
pm<strong>en</strong>u.App<strong>en</strong>dM<strong>en</strong>u(MF_STRING, ID_FICHERO_SALIR, "Salir");<br />
return TRUE; // Devuelve TRUE a m<strong>en</strong>os que establezca el foco <strong>en</strong> un control<br />
}<br />
89
M<strong>en</strong>ús<br />
CSimpleDlg.cpp<br />
void CSimpleDlg::OnFicheroSalir()<br />
{<br />
// TODO: TODO Add your command d hhandler dl code d hhere<br />
PostMessage(WM_QUIT);<br />
}<br />
void CSimpleDlg::OnRButtonDown(UINT nFlags, CPoint point)<br />
{<br />
Cli<strong>en</strong>tToScre<strong>en</strong>(&point);<br />
pm<strong>en</strong>u.TrackPopupM<strong>en</strong>u(TPM_LEFTALIGN, point.x, point.y, this);<br />
}<br />
void CSimpleDlg::OnItem1()<br />
{<br />
AfxMessageBox("Item AfxMessageBox( Item 1 1"); );<br />
}<br />
90
M<strong>en</strong>ús<br />
Ejemplo: Añadir un M<strong>en</strong>ú Emerg<strong>en</strong>te Dinámico<br />
En realidad lo que hemos hecho es un “m<strong>en</strong>ú<br />
contextual”.<br />
PPara ello ll bbasta t con capturar t el l m<strong>en</strong>saje j<br />
WM_CONTEXTMENU.<br />
void id CSimpleDlg::OnContextM<strong>en</strong>u(CWnd* CSi l Dl O C t tM (CW d* pWnd, W d CP CPoint i t point) i t)<br />
{<br />
pm<strong>en</strong>u.TrackPopupM<strong>en</strong>u(TPM_LEFTALIGN, point.x, point. y, this);<br />
}<br />
Si no mostramos un m<strong>en</strong>ú, debemos llamar a<br />
CWnd::OnContextM<strong>en</strong>u(pWnd CWnd::OnContextM<strong>en</strong>u(pWnd, point) antes de salir salir.<br />
91
Teclas Aceleradoras<br />
Asociar una combinación de teclas a un comando.<br />
Si se usa el asist<strong>en</strong>te, la definición de teclas<br />
aceleradoras l d se carga <strong>en</strong> lla v<strong>en</strong>tana t marco con lla<br />
llamada a LoadFrame().<br />
92
Teclas Aceleradoras<br />
Las tablas aceleradoras no funcionan con aplicaciones<br />
basadas <strong>en</strong> diálogo, ya que su bucle de m<strong>en</strong>sajes no<br />
llama a TranslateAccelerator()<br />
TranslateAccelerator().<br />
class CSimpleApp : public CWinApp<br />
{<br />
private:<br />
public: bli<br />
HACCEL m_haccel; // añadir handle a tabla aceleradora<br />
CSimpleApp();<br />
// Reemplazos<br />
public:<br />
virtual BOOL InitInstance();<br />
BOOL ProcessMessageFilter(int code, LPMSG lpMsg); // sobreescribir<br />
DECLARE DECLARE_MESSAGE_MAP()<br />
MESSAGE MAP()<br />
};<br />
93
BOOL CSimpleApp::InitInstance() {<br />
INITCOMMONCONTROLSEX InitCtrls;<br />
InitCtrls.dwSize = sizeof(InitCtrls); Teclas Aceleradoras<br />
InitCtrls.dwICC = ICC_WIN95_CLASSES;<br />
InitCommonControlsEx(&InitCtrls);<br />
CWinApp::InitInstance();<br />
AfxEnableControlContainer(); ();<br />
SetRegistryKey(_T("Aplicaciones g<strong>en</strong>eradas con el Asist<strong>en</strong>te para aplicaciones local"));<br />
m_haccel=::LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR1));<br />
CSimpleDlg dlg;<br />
m_ppMainWnd = &dlg; g;<br />
INT_PTR nResponse = dlg.DoModal();<br />
if (nResponse == IDOK) {<br />
// TODO: insertar aquí el código para controlar cuándo se descarta el cuadro de diálogo con Aceptar<br />
}<br />
else if (nResponse == IDCANCEL) {<br />
// TODO: insertar aquí el código para controlar cuándo se descarta el cuadro de diálogo con Cancelar<br />
}<br />
return FALSE;<br />
}<br />
BOOL CSimpleApp::ProcessMessageFilter(int code, LPMSG lpMsg) {<br />
if (code ( < 0) ) CWinApp::ProcessMessageFilter(code, pp g ( , lpMsg); p g);<br />
if(m_haccel)<br />
{<br />
if (::TranslateAccelerator(m_pMainWnd->m_hWnd, m_haccel, lpMsg))<br />
return(TRUE); ( );<br />
}<br />
return CWinApp::ProcessMessageFilter(code, lpMsg);<br />
}<br />
94
Teclas Aceleradoras<br />
Este podría ser un bucle de m<strong>en</strong>sajes con llamada a las<br />
tteclas l aceleradoras: l d<br />
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nCmdShow) {<br />
MSG msg;<br />
BOOL bRet;<br />
//…<br />
while ( (bRet = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0) {<br />
if (bRet (bR t == -1) 1) {<br />
// handle the error and possibly exit<br />
}<br />
else { // Check for accelerator keystrokes.<br />
if (!TranslateAccelerator(<br />
hwndMain, // handle to receiving window<br />
haccel, // handle to active accelerator table<br />
&msg)) // message data<br />
{<br />
TranslateMessage(&msg);<br />
DispatchMessage(&msg);<br />
}<br />
}<br />
}<br />
//…<br />
}<br />
95
Diálogos<br />
Las <strong>MFCs</strong> conti<strong>en</strong><strong>en</strong> diálogos preconstruidos<br />
que pued<strong>en</strong> ser usados directam<strong>en</strong>te por el<br />
usuario.<br />
Para crear un diálogo: g<br />
Se usa el editor de recursos.<br />
DoModal() () muestra el diálogo g de manera modal.<br />
Devuelve un UINT con la razón por la que se cerró<br />
(ej.: IDCANCEL o IDOK).<br />
Los no modales se crean como si fueran una v<strong>en</strong>tana<br />
(Create()).<br />
96
Ejemplo: Añadir un Diálogo<br />
Se añade un nuevo elem<strong>en</strong>to al m<strong>en</strong>ú<br />
y a la tabla aceleradora<br />
void CSimpleDlg::OnFicheroDialogo() {<br />
CDialogoEjemplo dlg(this);<br />
dlg dlg.DoModal(); DoModal();<br />
}<br />
Creado usando el<br />
editor de recursos.<br />
SSe crea una clase l que<br />
herede de CDialog<br />
con el asist<strong>en</strong>te asist<strong>en</strong>te.<br />
class CDialogoEjemplo : public CDialog {<br />
DECLARE_DYNAMIC(CDialogoEjemplo)<br />
public:<br />
CDialogoEjemplo(CWnd* CDialogoEjemplo(CWnd pPar<strong>en</strong>t = NULL);<br />
virtual ~CDialogoEjemplo();<br />
<strong>en</strong>um { IDD = IDD_DIALOG1 };<br />
protected:<br />
virtual void<br />
DoDataExchange(CDataExchange* pDX);<br />
DECLARE_MESSAGE_MAP()<br />
};<br />
97
Diálogos Predefinidos<br />
CC CColorDialog: l Di l permite i seleccionar l i un<br />
color.<br />
CFileDialog: permite seleccionar<br />
ficheros.<br />
CFindReplaceDialog: permite realizar<br />
búsqueda o buscar/reemplazar (no<br />
modal, se crea con Create()). 98
Diálogos Predefinidos<br />
CFontDialog: permite elegir una<br />
fu<strong>en</strong>te.<br />
CPrintDialog: permite imprimir y<br />
configurar la impresión.<br />
CPageSetupDialog: permite<br />
imprimir y<br />
99
Controles<br />
Las MFC pon<strong>en</strong> a nuestra disposición un<br />
gran g número de controles qque simplifican p<br />
la creación de aplicaciones.<br />
Los Los controles mandan notificaciones a la<br />
v<strong>en</strong>tana padre (ej.: el control de edición<br />
manda EN_CHANGE C G cuando cambia el<br />
texto). )<br />
100
Controles predefinidos MFC<br />
CAnimateCtrl: public CWnd: Permite<br />
mostrar un vídeo <strong>en</strong> formato AVI.<br />
void CAboutDlg::OnBnClickedButton1()<br />
{<br />
avi_player.Op<strong>en</strong>(IDR_AVI1);<br />
avi avi_player.Play(0, player Play(0 -1 -1, -1);<br />
}<br />
101
Controles predefinidos MFC<br />
CButton: permite gestionar botones.<br />
Ev<strong>en</strong>tos: BN BN_CLICKED, CLICKED, BN BN_DOUBLECLICKED.<br />
DOUBLECLICKED.<br />
Métodos: GetState(), SetState(), SetCursor(), GetCursor().<br />
void CAboutDlg::OnBnClickedMessage()<br />
{<br />
anim.Stop();<br />
AfxMessageBox("Stop!");<br />
}<br />
102
Controles predefinidos MFC<br />
CBit CBitmapButton: B tt SSe crea un botón b tó normal l <strong>en</strong> el l<br />
editor de recursos y:<br />
se selecciona OwnerDraw=true<br />
OwnerDraw true.<br />
<strong>en</strong> el caption se pone una descripción (ej: BOTON).<br />
Se crean de 1 a 4 bitmaps:<br />
ID=“BOTONU”, bitmap normal.<br />
ID=“BOTONF”, bitmap foco de teclado.<br />
ID=“BOTONX”, , bitmap p botón desactivado.<br />
ID=“BOTOND”, bitmap botón pulsado.<br />
Se crea un objeto de la clase CBitmapButton como<br />
miembro del diálogo diálogo.<br />
En la inicialización del diálogo (OnInitDialog()) se llama<br />
a AutoLoad().<br />
103
Ejemplo<br />
class CAboutDlg : public CDialog {<br />
public:<br />
CAboutDlg();<br />
CBitmapButton<br />
//…<br />
virtual void DoDataExchange(CDataExchange* pDX); // Compatibilidad con DDX/DDV<br />
// Implem<strong>en</strong>tación<br />
protected:<br />
DECLARE_MESSAGE_MAP()<br />
private: i t<br />
CAnimateCtrl anim;<br />
CBitmapButton BClose;<br />
public:<br />
afx_msg f void id OOnBnClickedStart(); B Cli k dSt t()<br />
afx_msg void OnBnClickedMessage();<br />
public:<br />
BOOL OnInitDialog();<br />
};<br />
void CAboutDlg::DoDataExchange(CDataExchange* pDX) {<br />
CDialog::DoDataExchange(pDX);<br />
DDX_Control(pDX, IDC_ANIMATE1, anim);<br />
DDX DDX_Control(pDX, C t l( DX IDMESSAGE, IDMESSAGE BCl BClose); )<br />
}<br />
//…<br />
BOOL CAboutDlg::OnInitDialog() {<br />
BCl BClose.AutoLoad(IDMESSAGE, A t L d(IDMESSAGE this); thi )<br />
CDialog::OnInitDialog();<br />
return FALSE;<br />
}<br />
104
Controles predefinidos MFC<br />
CListBox:<br />
Listas<br />
Datos iniciales (<strong>en</strong> “OnInitDialog”)<br />
Selección simple o múltiple<br />
Métodos:<br />
int GetCurSel();<br />
int SetCurSel(int nSelect);<br />
int AddString(LPCTSTR lpszItem);<br />
int InsertString(int nIndex,<br />
LPCTSTR lpszItem);<br />
Ejemplo<br />
void CSimpleDlg::OnLbnKillfocusList1()<br />
{<br />
int sel = nameListBox.GetCurSel();<br />
if (sel>-1) {<br />
CString str;<br />
nameListBox.GetText(sel,str);<br />
Af AfxMessageBox("Selected M B ("S l t d It Item: " "+str); t )<br />
}<br />
105<br />
}
Controles predefinidos MFC<br />
CC CComboBox: b B<br />
Simple (lista siempre visible), Drop-down (permite editar), Drop-<br />
Down List.<br />
Métodos:<br />
GetCount(): número de elem<strong>en</strong>tos que ti<strong>en</strong>e la lista.<br />
GetCurSel()/SetCurSel(): obti<strong>en</strong>e/establece el número de ord<strong>en</strong> del<br />
elem<strong>en</strong>to seleccionado.<br />
SetItemData()/GetItemData(): lee el valor asignado a un<br />
determinado elem<strong>en</strong>to de la lisa.<br />
AddString()/DeleteString()/InsertString(). También se pued<strong>en</strong> cargar<br />
valores estáticos <strong>en</strong> el campo “Data” del editor de recursos<br />
(separados mediante ;)<br />
Dir().<br />
CComboBoxEx: permite introducir imág<strong>en</strong>es <strong>en</strong> los<br />
elem<strong>en</strong>tos a seleccionar, <strong>en</strong>tre otras mejoras.<br />
106
Controles predefinidos MFC<br />
CD CDataTimeCtrl. t Ti Ct l<br />
CEdit.<br />
CHeaderCtrl<br />
CHeaderCtrl.<br />
CHotKeyCtrl.<br />
CIpAddressCtrl<br />
CIpAddressCtrl.<br />
CCheckListBox.<br />
CDragListBox<br />
CDragListBox.<br />
CListCtrl.<br />
CMonthCalCtrl.<br />
COleControl.<br />
CProgressCtrl.<br />
107
Controles predefinidos MFC<br />
CR CReBarCtrl. B Ct l<br />
CRichEditCtrl.<br />
CScrollBar CScrollBar.<br />
CSliderCtrl.<br />
CSpinButtonCtrl<br />
CSpinButtonCtrl.<br />
CStatic.<br />
CStatusBarCtrl<br />
CStatusBarCtrl.<br />
CTabCtrl.<br />
CToolBarCtrl<br />
CToolBarCtrl.<br />
CToolTipCtrl.<br />
CTreeCtrl CTreeCtrl.<br />
108
Clases de Utilidad<br />
Cad<strong>en</strong>as de caracteres<br />
CString CString.<br />
Caracteres unicode vs. ascii.<br />
Definiciones de un “const char*”<br />
typedef wchar_t wchar t WCHAR;<br />
// “wchar_t” es un char “Unicode” (2 bytes)<br />
// o “ANSI” (1 byte) dep<strong>en</strong>di<strong>en</strong>do de<br />
// la opción señalada para el proyecto<br />
typedef __nullterminated CONST WCHAR *LPCWSTR;<br />
typedef LPCWSTR LPCTSTR;<br />
Conversiones. Ejemplo: j p<br />
LPCTSTR t;<br />
// si t<strong>en</strong>emos “opción Unicode” es un error: t="abc";<br />
CString c1("abc");<br />
c1="def"; 1 "d f"<br />
t=c1;<br />
// correcto ya que hace un casting implícito<br />
// y está definido un operador p de casting g<br />
109
Clases de Utilidad<br />
Cad<strong>en</strong>as de caracteres<br />
// sobrecarga de =, +=, + etc<br />
CString s;<br />
s="Hola”;<br />
s= Hola ;<br />
s+=“ soy yo”;<br />
cout
Clases de Utilidad<br />
Cont<strong>en</strong>edores<br />
Similares a los cont<strong>en</strong>edores de la STL.<br />
Definiciones <strong>en</strong> afxtempl.h (que debemos incluir <strong>en</strong><br />
stdafx.h). td f h)<br />
Los templates admit<strong>en</strong> dos parámetros: el tipo de dato, y<br />
el tipo para referirse a él (quizá una refer<strong>en</strong>cia) refer<strong>en</strong>cia).<br />
Cont<strong>en</strong>edor Clase Puntero<br />
Vectores CArray CTypedPtrArray<br />
Listas CList CTypedPtrList<br />
Diccionario CMap CTypedPtrMap
Clases de Utilidad<br />
Cont<strong>en</strong>edores: CArray<br />
Si Similar il a vector t dde lla STL STL.<br />
template < class TYPE, class ARG_TYPE =<br />
const TYPE& > class CArray : public<br />
<br />
CObject<br />
ARG_TYPE es el tipo que se usa para<br />
acceder a los elem<strong>en</strong>tos almac<strong>en</strong>ados.<br />
Ej Ejemplo l<br />
CArray myArray;<br />
Tamaño:<br />
//Addelem<strong>en</strong>tstothearray<br />
// Add elem<strong>en</strong>ts to the array.<br />
GetCount(), GetSize(), GetUpperBound(), for (int i=0;i < 10;i++)<br />
IsEmpty(), SetSize().<br />
myArray.Add( CPoint(i, 2*i) );<br />
Operaciones:<br />
p<br />
FreeExtra(), RemoveAll(), RelocateElem<strong>en</strong>ts().<br />
Aum<strong>en</strong>tando el Array:<br />
Add(), (), App<strong>en</strong>d(), pp (), Copy(), py(), SetAtGrow(). ()<br />
Inserción/eliminación:<br />
InsertAt(), RemoveAt()<br />
Operadores:<br />
Acceso/modificación con el operador [].<br />
// Modify all the points in the array.<br />
for (i=0;i
Clases de Utilidad<br />
Cont<strong>en</strong>edores: CList<br />
ttemplate TYPE& class l CLi CList t : public bli CObj CObject t<br />
Iteración: CList myList; y ;<br />
POSITION pos = myList.GetHeadPosition();<br />
while( pos != NULL ) {<br />
}<br />
CMiClase& clase = myList.GetNext( pos );<br />
// //...<br />
IInserción: ió myList.InsertAfter(myList.GetTailPosition(), Li t I tAft ( Li t G tT ilP iti () elem); l )<br />
Eliminación: myList myList.RemoveAt(pos);<br />
RemoveAt(pos);<br />
113
Clases de Utilidad<br />
Cont<strong>en</strong>edores: CMap<br />
template< l class l KEY KEY, class l<br />
ARG_KEY, class VALUE, class<br />
ARG_VALUE >class CMap : public<br />
CObject<br />
Operaciones:<br />
GetHashTableSize()<br />
GetHashTableSize(),<br />
GetNextAssoc(), PGetNextAssoc(),<br />
GetStartPosition(), PGetFirstAssoc(),<br />
InitHashTable() InitHashTable(), Lookup() Lookup(),<br />
PLookup(), operator[], RemoveAll(),<br />
RemoveKey(), SetAt().<br />
Estado:<br />
GetCount(), GetSize(), IsEmpty().<br />
Miembros de Datos:<br />
CMap::CPair<br />
CM CMap i t i t CP i t CP i t myMap; M<br />
int i;<br />
myMap.InitHashTable( 257 );<br />
// Add 10 elem<strong>en</strong>ts to the map.<br />
for (i=0;i < 200;i++)<br />
myMap[i] = CPoint(i, i);<br />
// Remove the elem<strong>en</strong>ts with ev<strong>en</strong><br />
// key values.<br />
CPoint pt;<br />
f for (i=0; (i 0 myMap.Lookup( M L k ( ii, pt t ) ;i+=2) i+ 2)<br />
{<br />
myMap.RemoveKey( i );<br />
}<br />
Ejemplo
Clases de Utilidad<br />
Cont<strong>en</strong>edores de punteros<br />
Si queremos t<strong>en</strong>er listas de objetos heterog<strong>en</strong>eos<br />
heterog<strong>en</strong>eos.<br />
No podemos usar los cont<strong>en</strong>edores anteriores, ya que si<br />
queremos q serializar una lista a disco, se copiarían p los<br />
punteros, y no los objetos.<br />
Por ello, MFC duplica los cont<strong>en</strong>edores para la gestión de<br />
punteros punteros.<br />
template< class BASE_CLASS, class TYPE > class<br />
CTypedPtrList : public BASE_CLASS<br />
BASE BASE_CLASS: CLASS ti tipo ddel l que se hhereda d para construir t i el l<br />
template.<br />
CObList si los elem<strong>en</strong>tos heredan de CObject (se pued<strong>en</strong> serializar).<br />
CPtrList <strong>en</strong> otro caso. caso<br />
TYPE: tipo de los elem<strong>en</strong>tos que insertamos.<br />
Similar para arrays.
typedef CTypedPtrList CMyList;<br />
CMyList ml;<br />
CMyObject* y j pMyObject y j = new CMyObject(); y j ()<br />
ml.AddTail(pMyObject);<br />
CFileException e;<br />
CFile myFile;<br />
myFile.Op<strong>en</strong>("MyFile.txt",<br />
CFile::modeCreate|CFile::modeWrite, &e);<br />
CArchive ar(&myFile, CArchive::store);<br />
ml.Serialize(ar);<br />
ar.Close();<br />
myFile.Close();<br />
while (!ml.IsEmpty())<br />
{<br />
delete ml.GetHead();<br />
ml.RemoveHead();<br />
}<br />
Clases de Utilidad<br />
Cont<strong>en</strong>edores de punteros, ejemplo<br />
//=====================<br />
// //where h CMyObject CM Obj t iis ddefined fi d bby th the ffollowing ll i fil files:<br />
//CMyObject.h<br />
class CMyObject : public Cobject {<br />
public: bli<br />
int i;<br />
void Serialize(CArchive& ar);<br />
CMyObject() { i = 9876;}<br />
protected: t t d<br />
DECLARE_SERIAL(CMyObject)<br />
};<br />
//CM //CMyObject.cpp Obj t<br />
#include "stdafx.h"<br />
#include "CMyObject.h"<br />
IMPLEMENT IMPLEMENT_SERIAL(CMyObject, SERIAL(CM Obj t CObject, CObj t 0)<br />
void CMyObject::Serialize(CArchive& ar) {<br />
CObject::Serialize( ar );<br />
if( ar.IsStoring() )<br />
ar > i;<br />
}
Clases de Utilidad<br />
Cont<strong>en</strong>edores de punteros: CTypedPtrMap<br />
ttemplate< l t < class l BASE_CLASS, BASE CLASS class l KEY KEY, class l VALUE > class l<br />
CTypedPtrMap : public BASE_CLASS<br />
BASE_CLASS: clase base del diccionario, puede ser, <strong>en</strong> función de<br />
llos tipos ti de d la l clave l y elem<strong>en</strong>tos l t a almac<strong>en</strong>ar: l<br />
CMapPtrToPtr,<br />
CMapPtrToWord,<br />
CMapWordToPtr,<br />
CMapStringToPtr<br />
CMapStringToString<br />
p g g<br />
CMapWordToOb<br />
CMapWordToPtr<br />
KEY: tipo de la clave. clave<br />
VALUE: tipo de los elem<strong>en</strong>tos a almac<strong>en</strong>ar (suele ser un<br />
puntero).<br />
Ej.: typedef CTypedPtrMap MapaAMiObjeto;
Indice<br />
P<strong>Programación</strong> ió bbajo j Wi <strong>Windows</strong>. d<br />
Introducción a las <strong>MFCs</strong>.<br />
A Arquitectura it t Docum<strong>en</strong>to/Vista.<br />
D t /Vi t<br />
Introducción.<br />
SDI y MDI.<br />
Plantillas Plantillas de docum<strong>en</strong>to.<br />
docum<strong>en</strong>to<br />
Ejemplo.<br />
D Docum<strong>en</strong>to, t serialización. i li ió<br />
Bibliografía.<br />
118
Arquitectura Docum<strong>en</strong>to Vista<br />
SSeparar lla visualización i li ió ( (vista) i ) dde llos d datos (d (docum<strong>en</strong>to). )<br />
Similar al patrón “Model-View-Controler”.<br />
El asist<strong>en</strong>te g<strong>en</strong>era clases que heredan de: CFrameWnd CFrameWnd, CView y<br />
CDocum<strong>en</strong>t.<br />
CView es abstracta. Otra posibilidad es usar como base una vista<br />
predefinida: d fi id<br />
CEditView (edición de texto básica). Esta se puede usar directam<strong>en</strong>te.<br />
CRichEditView (permite formateo de texto).<br />
CScrollView (scroll vertical y horizontal).<br />
CListView (listas de elem<strong>en</strong>tos).<br />
CTreeView (árbol de elem<strong>en</strong>tos) elem<strong>en</strong>tos).<br />
CFormView (similar a un cuadro de diálogo).<br />
CDaoRecordView (similar a cuadro de diálogo pero para control de<br />
BBDD) BBDD).<br />
CCtrolView (se pued<strong>en</strong> incluir otras vistas d<strong>en</strong>tro).<br />
119
SDI y MDI<br />
Single Docum<strong>en</strong>t Interface: Un solo tipo de docum<strong>en</strong>to docum<strong>en</strong>to.<br />
Multiple Docum<strong>en</strong>t Interface: Varios tipos de docum<strong>en</strong>to.<br />
Una aplicación SDI Una aplicación MDI<br />
120
Las plantillas de docum<strong>en</strong>to<br />
El docum<strong>en</strong>to, el marco y la vista se relacionan usando plantillas de<br />
docum<strong>en</strong>to, que heredan de CDocTemplate.<br />
CSingleDocTemplate y CMultiDocTemplate para SDI y MDI.<br />
BOOL CSDI2App::InitInstance() CSDI2A I itI t () {<br />
//…<br />
pDocTemplate = new CSingleDocTemplate(<br />
IDR_MAINFRAME,<br />
}<br />
RUNTIME RUNTIME_CLASS(CSDI2Doc),<br />
CLASS(CSDI2D )<br />
RUNTIME_CLASS(CMainFrame), // V<strong>en</strong>tana de marco SDI principal<br />
RUNTIME_CLASS(CSDI2View));<br />
if (!pDocTemplate) return FALSE;<br />
AddD AddDocTemplate(pDocTemplate);<br />
T l t ( D T l t )<br />
EnableShellOp<strong>en</strong>();<br />
RegisterShellFileTypes(TRUE);<br />
// …<br />
RUNTIME_CLASS devuelve un struct CRuntimeClass *.<br />
Nota: Sólo se puede obt<strong>en</strong>er esta información de subclases de CObject que<br />
hayan sido declaradas DECLARE_DYNAMIC, DECLARE_DYNCREATE o<br />
DECLARE_SERIAL.<br />
121
Las plantillas de docum<strong>en</strong>to<br />
Una plantilla de docum<strong>en</strong>to por cada tipo de docum<strong>en</strong>to<br />
soportado, y es responsable de crear y gestionar los<br />
docum<strong>en</strong>tos de ese tipo tipo.<br />
La plantilla conti<strong>en</strong>e el ID con los recursos (m<strong>en</strong>ú, icono,<br />
tablas aceleradoras).<br />
aceleradoras)<br />
Conti<strong>en</strong>e también strings con el nombre del tipo de<br />
docum<strong>en</strong>to, docu e o, la a eext<strong>en</strong>sión e s ó de sus ficheros, c e os, eetc. c<br />
EnableShellOp<strong>en</strong>(): permite abrir ficheros de datos<br />
haci<strong>en</strong>do doble click <strong>en</strong> ellos <strong>en</strong> el explorador. p<br />
RegisterShellFileTypes(cCompat): Registra los tipos de<br />
docum<strong>en</strong>tos <strong>en</strong> el explorador. Si bCompat==TRUE<br />
<strong>en</strong>tonces se pued<strong>en</strong> imprimir los ficheros desde el<br />
explorador.<br />
122
Arquitectura Docum<strong>en</strong>to Vista<br />
Ejemplo<br />
123
Arquitectura Docum<strong>en</strong>to Vista<br />
Ejemplo<br />
St String i asociado i d a la l aplicación li ió IDR IDR_MAINFRAME<br />
MAINFRAME<br />
7 pedazos:<br />
Vista derivada de CFormView.<br />
Se crea también un diálogo vacío<br />
<strong>en</strong> el editor de recursos:<br />
124
El Docum<strong>en</strong>to<br />
Encargado de gestionar los datos, incluido su grabación y<br />
recuperación del disco.<br />
virtual BOOL OnNewDocum<strong>en</strong>t(); se llama cuando se va a<br />
crear un nuevo fichero (sobreescribirlo permite chequear si<br />
queremos dejar crearlo o no).<br />
virtual BOOL OnOp<strong>en</strong>Docum<strong>en</strong>t(LPCTSTR lpszPathName);<br />
se llama cuando se va a abrir un fichero.<br />
virtual void OnCloseDocum<strong>en</strong>t(); se llama cuando se va a<br />
cerrar un fichero fichero.<br />
virtual BOOL OnSaveDocum<strong>en</strong>t(LPCTSTR lpszPathName);<br />
se llama cuando se va a salvar un docum<strong>en</strong>to.<br />
void SetModifiedFlag(BOOL bModified = TRUE); marca<br />
el docum<strong>en</strong>to como cambiado.<br />
BOOL IsModified(); comprueba si un docum<strong>en</strong>to está<br />
modificado. 125
Colaboración de Objetos <strong>en</strong> la<br />
Aplicación<br />
AAcceso a unos objetos bj t ddesde d otros: t<br />
Obj Objeto Mé Método d<br />
Docum<strong>en</strong>to GetFirstViewPosition()/GetNextView()<br />
Docum<strong>en</strong>to GetDocTemplate()<br />
Vista GetDocum<strong>en</strong>t()<br />
Vista GetPar<strong>en</strong>tFrame()<br />
V<strong>en</strong>tana marco del docum<strong>en</strong>to GetActiveView()<br />
V<strong>en</strong>tana marco del docum<strong>en</strong>to GetActiveDocum<strong>en</strong>t()<br />
V<strong>en</strong>tana principal (MDI) MDIGetActive()<br />
V<strong>en</strong>tana marco GetActiveFrame()
Colaboración de Objetos <strong>en</strong> la<br />
Aplicación<br />
CWinApp pp<br />
1<br />
1<br />
m_pMainWnd<br />
CFrameWnd<br />
1<br />
1<br />
CView<br />
1..*<br />
getPar<strong>en</strong>t();<br />
1<br />
CDocum<strong>en</strong>t<br />
getActiveView();<br />
g ();<br />
{POSITION p=GetFirstViewPosition();<br />
GetNextView(p);}<br />
getDocum<strong>en</strong>t();<br />
g ();
Arquitectura Docum<strong>en</strong>to Vista<br />
Serialización<br />
GGuardar/leer d /l los l ddatos dde di disco.<br />
virtual void Serialize(CArchive& ar); provisto por CObject.<br />
Sirve para leer y escribir. escribir<br />
Se usan los operadores > sobre el CArchive.<br />
void CSDI2Doc::Serialize(CArchive& ar) {<br />
POSITION pos = GetFirstViewPosition(); // m_viewList conti<strong>en</strong>e lista punteros a vistas<br />
CSDI2View* pView = dynamic_cast(GetNextView(pos));<br />
if (ar.IsStoring()){<br />
}<br />
}<br />
else {<br />
}<br />
pView->UpdateData(TRUE);<br />
pView >UpdateData(TRUE);<br />
ar nombre;<br />
ar direccion;<br />
ar edad;<br />
ar >> pView->nombre;<br />
ar >> pView->direccion;<br />
ar >> pView pView->edad; >edad;<br />
pView->UpdateData(FALSE);<br />
128
Arquitectura Docum<strong>en</strong>to Vista<br />
Serialización<br />
class CSDI2Doc : public CDocum<strong>en</strong>t {<br />
//..<br />
private: p<br />
CSDI2View* pView;<br />
CSDI2View* getView();<br />
// …<br />
};<br />
inline CSDI2View* CSDI2Doc::getView(){<br />
if (!pView) {<br />
}<br />
return pView;<br />
}<br />
void CSDI2Doc::Serialize(CArchive& ar){<br />
getView();<br />
POSITION pos p = GetFirstViewPosition(); ();<br />
pView = dynamic_cast(GetNextView(pos));<br />
if (ar.IsStoring()) {<br />
pView->UpdateData(TRUE);<br />
p p ( )<br />
ar nombre direccion edad;<br />
}<br />
else {<br />
ar >> pView->nombre >> pView->direccion >> pView->edad;<br />
pView->UpdateData(FALSE);<br />
}<br />
}<br />
// el ev<strong>en</strong>to salvar llama por defecto a la serialización del docum<strong>en</strong>to<br />
129
Arquitectura q Docum<strong>en</strong>to Vista<br />
Creación de un nuevo docum<strong>en</strong>to<br />
BOOL CSDI2Doc::OnNewDocum<strong>en</strong>t()<br />
{<br />
if (!CDocum<strong>en</strong>t::OnNewDocum<strong>en</strong>t())<br />
return t FALSE; FALSE<br />
}<br />
// TODO: agregar aquí código de reinicio<br />
// (los docum<strong>en</strong>tos SDI volverán a utilizar este docum<strong>en</strong>to)<br />
getView()->nombre="";<br />
pView->direccion="";<br />
pView pView->edad=0; >edad=0;<br />
pView->UpdateData(FALSE);<br />
return TRUE;<br />
130
Ejemplo
Indice<br />
<strong>Programación</strong> g bajo j <strong>Windows</strong>.<br />
Introducción a las <strong>MFCs</strong>.<br />
Arquitectura Docum<strong>en</strong>to/Vista<br />
Docum<strong>en</strong>to/Vista.<br />
Aspectos avanzados de las <strong>MFCs</strong>.<br />
Diálogos no modales.<br />
Creación Creación dinámica de widgets. widgets<br />
Registro.<br />
Otros aspectos de las <strong>MFCs</strong>.<br />
Bibliografía<br />
Bibliografía.<br />
132
Diálogos No Modales<br />
PPara ejecutar j t diálogos diál <strong>en</strong> fformal l modal, d l<br />
simplem<strong>en</strong>te hay que llamar al método<br />
DoModal().<br />
Para crear un diálogo no modal, hay que<br />
hacerlo como si fuera una v<strong>en</strong>tana cualquiera,<br />
mediante Create().<br />
Esto crea el diálogo y continúa la ejecución.<br />
Por tanto el diálogo se debe crear usando memoria<br />
dinámica!<br />
Liberación de la memoria <strong>en</strong> OnNcDestroy() y() del<br />
diálogo. Aquí se pued<strong>en</strong> pasar datos a la<br />
v<strong>en</strong>tana principal.<br />
133
void CGraficosSDIApp::OnAppAbout() {<br />
}<br />
Diálogos No Modales<br />
if (!pAboutDlg) {<br />
Ejemplo: About No Modal<br />
pAboutDlg = new CAboutDlg(); // puntero miembro<br />
pAboutDlg->Create( MAKEINTRESOURCE(CAboutDlg::IDD), // string con ID<br />
CWnd::GetDesktopWindow()); // puntero al escritorio,<br />
// evita que el diálogo esté siempre <strong>en</strong>cima<br />
pAboutDlg->ShowWindow(SW_SHOW);<br />
}<br />
else pAboutDlg->SetForegroundWindow(); // el diálogo ya existía, llevarlo al fr<strong>en</strong>te<br />
void CGraficosSDIApp::CloseDialog() { // acciones al cerrar el diálogo<br />
pAboutDlg g = 0; // simplem<strong>en</strong>te apunta a NULL<br />
}<br />
void CAboutDlg::OnNcDestroy() { // último m<strong>en</strong>saje que se recibe antes de cerrar<br />
CDialog::OnNcDestroy();<br />
((CGraficosSDIApp*)AfxGetApp())->CloseDialog(); // avisar a la aplicación, podríamos avisar a la v<strong>en</strong>tana padre<br />
// otra posibilidad es mandarle un m<strong>en</strong>saje definido por el<br />
// usuario con GetPar<strong>en</strong>t()->PostMessage(WM_USR,0,0)<br />
delete this; // importante: borramos la memoria dinámica<br />
}<br />
void CAboutDlg::OnOK() { // importante sobreescribir si se ti<strong>en</strong>e un IDOK, ya que por defecto MFC llama a<br />
// EndDialog(), que sólo vale para DoModal()<br />
if(UpdateData(true))<br />
DestroyWindow();<br />
}
Creación dinámica de widgets<br />
void CSDI2View::OnBnClickedButton1()<br />
{<br />
CButton* pButton=new CButton;<br />
pButton->Create("Submit",<br />
pButton Create( Submit ,<br />
WS_CHILD | WS_VISIBLE,<br />
CRect(170, 120, 270, 143),<br />
this, ,<br />
0x302); // un ID<br />
}<br />
135
Registro<br />
La mayoría de las aplicaciones dejan cierto grado de customización al<br />
usuario.<br />
Por ejemplo: posición y tamaño de la v<strong>en</strong>tana v<strong>en</strong>tana, posición de las barras<br />
de controles, etc.<br />
Guardar esta información de configuración <strong>en</strong> el registro (hasta<br />
windows 3.11, esta información se guardaba <strong>en</strong> ficheros INI).<br />
En InitInstance() se llama a SetRegistryKey() SetRegistryKey(), para establecer una<br />
clave (se crea debajo de HKEY_CURRENT_USER/software).<br />
SetRegistryKey() asigna valor al atributo m_pszRegistryKey de la clase<br />
CWinApp. pp<br />
El resto de llamadas del API (GetProfileString(), GetProfileInt(),<br />
WriteProfileString(), g() WriteProfileInt()) ())<br />
utilizan dichos métodos.
Registro<br />
BOOL CGraficosSDIApp::InitInstance()<br />
{<br />
//…<br />
SetRegistryKey(_T("GraficosSDI"));<br />
LoadStdProfileSettings(4); // Cargar opciones de archivo INI estándar<br />
// (incluidas las de la lista MRU)<br />
//…<br />
}<br />
Normalm<strong>en</strong>te se leerá la información del registro <strong>en</strong><br />
“OnCreate()” de la v<strong>en</strong>tana marco.<br />
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)<br />
{<br />
if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;<br />
WINDOWPLACEMENT PosV<strong>en</strong>;<br />
if (LeePosicionV<strong>en</strong>tana(&PosV<strong>en</strong>)) SetWindowPlacem<strong>en</strong>t(&PosV<strong>en</strong>);<br />
//…<br />
}
Registro<br />
bool CMainFrame::LeePosicionV<strong>en</strong>tana(LPWINDOWPLACEMENT pPosV<strong>en</strong>)<br />
{<br />
CString strClave = AfxGetApp()->GetProfileString(_T("Arranque"), _T("Posicion"));<br />
if (strClave.IsEmpty()) return false;<br />
int numDatos = sscanf_s(strClave, "%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",<br />
&pPosV<strong>en</strong>->flags, &pPosV<strong>en</strong>->showCmd, &pPosV<strong>en</strong>->ptMinPosition.x,<br />
&pPosV<strong>en</strong>->ptMinPosition.y, &pPosV<strong>en</strong>->ptMaxPosition.x, &pPosV<strong>en</strong>->ptMaxPosition.y,<br />
&pPosV<strong>en</strong>->rcNormalPosition.left, &pPosV<strong>en</strong>->rcNormalPosition.top,<br />
&pPosV<strong>en</strong>->rcNormalPosition.right, &pPosV<strong>en</strong>->rcNormalPosition.bottom);<br />
if (numDatos != 10) return false;<br />
pPosV<strong>en</strong>->l<strong>en</strong>gth=sizeof(pPosV<strong>en</strong>);<br />
return true;<br />
}
Registro<br />
void id CM CMainFrame::OnClose()<br />
i F O Cl ()<br />
{<br />
WINDOWPLACEMENT PosV<strong>en</strong>;<br />
PosV<strong>en</strong>.l<strong>en</strong>gth=sizeof(PosV<strong>en</strong>);<br />
if (G (GetWindowPlacem<strong>en</strong>t(&PosV<strong>en</strong>))<br />
tWi d Pl t(&P V ))<br />
{<br />
if (PosV<strong>en</strong>.showCmd!=SW_SHOWMINIMIZED)<br />
EscribirPosicionV<strong>en</strong>tana(&PosV<strong>en</strong>);<br />
}<br />
}<br />
CFrameWnd::OnClose();<br />
void CMainFrame::EscribirPosicionV<strong>en</strong>tana(LPWINDOWPLACEMENT pPosV<strong>en</strong>)<br />
{<br />
TCHAR szBuffer[8*6+2*5+9+1];<br />
}<br />
wsprintf(szBuffer, i tf( B ff "%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",<br />
"% % %d%d%d%d%d%d%d%d"<br />
pPosV<strong>en</strong>->flags, pPosV<strong>en</strong>->showCmd, pPosV<strong>en</strong>->ptMinPosition.x,<br />
pPosV<strong>en</strong>->ptMinPosition.y, pPosV<strong>en</strong>->ptMaxPosition.x, pPosV<strong>en</strong>->ptMaxPosition.y,<br />
pPosV<strong>en</strong>->rcNormalPosition.left, pPosV<strong>en</strong>->rcNormalPosition.top,<br />
pPosV<strong>en</strong>->rcNormalPosition.right, P V > N lP iti i ht pPosV<strong>en</strong>->rcNormalPosition.bottom);<br />
P V > N lP iti b tt )<br />
AfxGetApp()->WriteProfileString(_T("Arranque"), _T("Posicion"), szBuffer);
Otros aspectos de las <strong>MFCs</strong><br />
Bases de datos<br />
Sincronización<br />
Sincronización<br />
<strong>Windows</strong> sockets<br />
Servicios Internet<br />
140
Indice<br />
<strong>Programación</strong> bajo <strong>Windows</strong>.<br />
Introducción Introducción a las <strong>MFCs</strong>. <strong>MFCs</strong><br />
Arquitectura Docum<strong>en</strong>to/Vista.<br />
Aspectos avanzados de las <strong>MFCs</strong>.<br />
Bibliografía<br />
Bibliografía.<br />
141
Bibliografía<br />
MSDN (ayuda <strong>en</strong> línea) línea).<br />
“<strong>Programación</strong> Avanzada <strong>en</strong> <strong>Windows</strong> 2000 con Visual<br />
C++ y MFC”. Pascual, J., Charte, F., Segarra, g M. J., de<br />
Antonio, A., Clavijo, J. A. McGraw Hill. 2000.<br />
MFC:<br />
http://www http://www.functionx.com/visualc/<br />
functionx com/visualc/<br />
http://www.dcp.com.ar/mfc/indice.htm<br />
http://www.uta.fi/~jl/pguibook/<br />
http://www http://www.samspublishing.com/library/library.asp?b=Visual_C_<br />
samspublishing com/library/library asp?b Visual C<br />
PlusPlus&rl=1 (libro “Visual C++ Unleashed”)<br />
Docum<strong>en</strong>tación MFC al estilo de javadoc:<br />
http://www http://www.cppdoc.com/example/mfc/mfc.html<br />
cppdoc com/example/mfc/mfc html<br />
Controles<br />
http://www.functionx.com/visualc/controls/<br />
142