Ejemplo: font_one
CreateFont(), la principal API para trabajar con fuentes tiene 14 par�metros, los cuales especifican el alto, estilo, ancho, familia y otros varios atributos.
Afortunadamente no es tan dif�cil como parece y una gran parte del trabajo es realizada con valores por default. Todos menos dos de los valores de CreateFont() pueden ser puestos en 0 o en NULL para que el sistema use los valores por default dando como resultado una fuente plana y com�n.
CreateFont( ) crea un HFONT, un handle a la Fuente L�gica en memoria. Los datos referenciados por este handle pueden ser recuperados dentro de una estrucura LOGFONT usando la operaci�n GetObject( ), de la misma manera que lo hac�amos con los bitmaps donde la estructura BITMAP era rellenada a partir de un HBITMAP.
Los miembros de LOGFONT son id�nticos a los par�metros de CreateFont() y por conveniencia podemos crear directamente una fuente apartir una estructura LOGFONT ya existente, usando CreateFontIndirect( ). Esto es muy �til debido a que hace mas f�cil la tarea de crear una nueva fuente a partir de un handle cuando solo queremos alterar ciertos aspectos de �sta. Para rellenar los campos de la estructura LOGFONT usamos GetObject( ), alteramos los campos que deseamos y creamos una nueva fuente usando CreateFontIndirect( ).
HFONT hf;
HDC hdc;
long lfHeight;
hdc = GetDC(NULL);
lfHeight = -MulDiv(12, GetDeviceCaps(hdc, LOGPIXELSY), 72);
ReleaseDC(NULL, hdc);
hf = CreateFont(lfHeight, 0, 0, 0, 0, TRUE, 0, 0, 0, 0, 0, 0, 0, "Times New Roman");
if(hf)
{
DeleteObject(g_hfFont);
g_hfFont = hf;
}
else
{
MessageBox(hwnd, "Font creation failed!", "Error", MB_OK | MB_ICONEXCLAMATION);
}
Este es el c�digo usado para crear la fuente en la imagen ejemplo. La fuente es Times New Roman de 12 puntos con el estilo It�lica El flag para obtener la fuente en it�lica es el sexto par�metro de CreateFont( ), el cual se puede apreciar que est� puesto en TRUE. El �ltimo par�metro indica el nombre de la fuente que queremos usar.
La �nica parte tramposa de este c�digo es el valor usado para el tama�o de la fuente, el par�metro lfHeight de CreateFont( ). Generalmente las personas, cuando trabajan con fuentes, est�n acostumbradas a trabajar con tama�os especificados en Puntos, Tama�o 10, Tama�o 12, etc... Sin embargo, CreateFont( ) no acepta tama�os en puntos,solo acepta Unidades L�gicas, las cuales son diferentes en nuestra pantalla que en nuestra impresora y a�n entre impresoras y pantallas.
La raz�n de que exista esta situaci�n es porque la resoluci�n de los diferentes dispositivos es bastante diferente... las impresoras pueden imprimir de 600 a 1200 pixeles por pulgada, mientras que una pantalla con suerte llega a mostrar unos 200. Si usamos el mismo tama�o para la pantalla que para la impresora, quiz�s no podamos ver algunos caracteres en particular.
Todo lo que tenemos que hacer es convertir el tama�o punto al tama�o l�gico para un dispositivo determinado. En este caso el dispositivo es la pantalla, por lo tanto obtenemos el HDC de la pantalla y obtenemos el n�mero de pixeles l�gicos por pulgada usando GetDeviceCaps() y metemos esto dentro de la f�rmula provista tan generosamene en MSDN la cual usa MulDiv( ) para convertir nuestro tama�o punto, en este caso 12, al tama�o l�gico que CreateFont( ) espera. Luego almacenamos este en lfHeight y lo pasamos como primer par�metro de CreateFont( ).
GetDC( ) para obtener el HDC de nuestra ventana, la fuente por default que es seleccionada es System, la cual para ser honesto, no es muy atractiva. La forma m�s simple de obtener una fuente mejor sin tener que pasar por CreateFont() es llamar a GetStockObject() y preguntar por la DEFAULT_GUI_FONT.
Este es un objeto del sistema y podemos usarlo todas las veces que deseamos sin necesidad retener memoria, podemos llamar a DeleteObject() para borrarlo pero esto no causar� efecto, lo cual es una buena idea porque no tendremos que averiguar si dicha fuente fu� creada con CreateFont( ) o con GetStockObject( ) antes de intentar eliminarla.
Las opciones b�sicas son TextOut( ) y DrawText( ). TextOut() es mas simple pero tiene menos opciones y no hace cubrimientos de palabras o alineaci�n por nosotros.
char szSize[100];
char szTitle[] = "These are the dimensions of your client area:";
HFONT hfOld = SelectObject(hdc, hf);
SetBkColor(hdc, g_rgbBackground);
SetTextColor(hdc, g_rgbText);
if(g_bOpaque)
{
SetBkMode(hdc, OPAQUE);
}
else
{
SetBkMode(hdc, TRANSPARENT);
}
DrawText(hdc, szTitle, -1, prc, DT_WORDBREAK);
wsprintf(szSize, "{%d, %d, %d, %d}", prc->left, prc->top, prc->right, prc->bottom);
DrawText(hdc, szSize, -1, prc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
SelectObject(hdc, hfOld);
La primer cosa que hacemos es usar SelectObject( ) para obtener la fuente que queremos usar dentro de nuestro HDC y para prepararnos para dibujar. Todas las operaciones de texto usar�n, de aqu� en mas, esta fuente hasta que se seleccione alguna otra.
Ahora vamos a definir los colores del texto y del fondo. Cuando fijamos el color de fondo no cambiamos todo el fondo a un determinado color, solo afecta a ciertas operaciones que dibujan texto usando el color de fondo. Esto tambi�n depende del Modo de Fondo (o Background Mode) que est� seleccionado actualmente. Si est� definido como OPAQUE (el default) entonces cada vez que se escriba texto, el color de fondo del texto ser� el que est� seleccionado como background color. Si est� definido como TRANSPARENT, el texto es dibujado sin color de fondo y quedar� como fondo del texto lo que sea que encuentre dibujado debajo de �ste.
Ahora realmente dibujamos el texto usando DrawText( ), pasamos el HDC a usar y el string a dibujar. El tercer par�metro es la longitud del string, pero hemos pasado -1 debido a que DrawText( ) es lo suficientemente astuto para darse cuenta cual es la longitud del texto. En el cuarto par�metro pasamos prc, el puntero al cliente RECT. DrawText( ) dibujar� dentro de este rect�ngulo bas�ndose en los otros flags que le pasamos.
En la primer llamada especificamos DT_WORDBREAK, el cual alinea por default el texto a la izquierda y acomodar� el texto autom�ticamente a los l�mites del rect�ngulo... muy �til.
Para la segunda llamada solo imprimimos una sola l�nea sin ajustar el texto al rect�ngulo y la centramos horizontalmente y verticalmente (lo cual har� DrawText() cuando dibujemos una sola l�nea).
WNDCLASS es registrada he puesto los estilos CS_VREDRAW y CS_HREDRAW. Esto provoca que el �rea cliente entera sea sea redibujada si la ventana cambia su tama�o, mientras que por default solo se dibujan las partes que han cambiado. Esto luce algo malo debido a que el texto centrado es movido cuando la ventana cambia su tama�o pero no se actualiza como esperamos.
Al igual que los di�logos comunes para abrir y guardar archivos, hay un di�logo com�n para escoger una fuente. Este es llamado ChooseFont( ) y funciona junto con la estructura CHOOSEFONT.
HFONT g_hfFont = GetStockObject(DEFAULT_GUI_FONT); COLORREF g_rgbText = RGB(0, 0, 0);
void DoSelectFont(HWND hwnd)
{
CHOOSEFONT cf = {sizeof(CHOOSEFONT)};
LOGFONT lf;
GetObject(g_hfFont, sizeof(LOGFONT), &lf);
cf.Flags = CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
cf.hwndOwner = hwnd;
cf.lpLogFont = &lf;
cf.rgbColors = g_rgbText;
if(ChooseFont(&cf))
{
HFONT hf = CreateFontIndirect(&lf);
if(hf)
{
g_hfFont = hf;
}
else
{
MessageBox(hwnd, "Font creation failed!", "Error", MB_OK | MB_ICONEXCLAMATION);
}
g_rgbText = cf.rgbColors;
}
}
El hwnd en esta llamada es simplemente la ventana que vamos a usar como padre del di�logo.
La forma m�s f�cil de usar este di�logo es junto con una estructura LOGFONT, la cual es bastante parecida a la estructura HFONT que ven�amos usando. Hacemos que el campo lpLogFont apunte a LOGFONT, que acabamos de llenar con informaci�n y tambi�n agregamos el flag CF_INITTOLOGFONTSTRUCT para que ChooseFont( ) use este campo. El flag CF_EFFECTS le dice a ChooseFont( ) que permita al usuario seleccionar un color como as� tambi�n efectos de subrayado y tachado.
Los estilos Negrita e It�lica no se cuentan como efectos, son considerados partes de la fuente y de hecho algunas fuentes solo vienen en Negrita o en It�lica. Si queremos chequear o prevenir al usuario de seleccionar una fuente negrita o it�lica, podemos chequear los campos lfWeight y lfItalic, respectivamente, de la estructura LOGFONT despu�s de que el usuario ha hecho su elecci�n. Luego se le puede preguntar al usuario si desea hacer otra selecci�n o alg�n cambio a los campos antes de llamar a CreateFontIndirect().
El color de una fuente no est� asociado con un HFONT y por lo tanto debe ser almacenado por separado. EL campo rgbColors de la estructura CHOOSEFONT es usado para pasar el color inicial y para recuperar luego el nuevo color.
CF_SCREENFONTS indica que queremos fuentes dise�adas para funcionar en la pantalla y no fuentes dise�adas para funcionar en una impresora. Algunos soportan ambas, otros soportan una u otra. Dependiendo de para que vas a usar la fuente, este y muchos otros flags pueden ser encontrados en MSDN para definir exactamente que fuentes deseamos que el usuario sea capaz de seleccionar.
ChooseColor( ). Este es el c�digo usado para permitirle al usuario seleccionar el color de fondo en programa ejemplo.
COLORREF g_rgbBackground = RGB(255, 255, 255);
COLORREF g_rgbCustom[16] = {0};
void DoSelectColour(HWND hwnd)
{
CHOOSECOLOR cc = {sizeof(CHOOSECOLOR)};
cc.Flags = CC_RGBINIT | CC_FULLOPEN | CC_ANYCOLOR;
cc.hwndOwner = hwnd;
cc.rgbResult = g_rgbBackground;
cc.lpCustColors = g_rgbCustom;
if(ChooseColor(&cc))
{
g_rgbBackground = cc.rgbResult;
}
}
Esto es algo complicado, nuevamente estamos usando el par�metro hwnd como padre del di�logo. El par�metro CC_RGBINIT indica que debemos comenzar con el color que pasamos en el campo rgbResult, el cual tambi�n es donde obtenemos el color que el usuario ha seleccionado cuando el di�logo se cierra.
El arreglo g_rgbCustom de 16 COLORREFs es necesario para almacenar cualquier valor que el usuario decide poner dentro de la tabla de colores personalizados inclu�da en el di�logo. Podemos potencialmente almacenar estos valores en otro lugar que no sea el registro, porque de no ser as� dichos valores se perder�n al cerrar el programa. Este par�metro no es opcional.
CreateWindow( ) para crear controles como lo hemos hecho en los ejemplos anteriores. Los controles al igual que las ventanas usan la fuente System por default, por lo tanto usamos WM_SETFONT para definir un nuevo handle a la fuente (de GetStockObject()) para que use el control. Podemos usar este m�todo con fuentes que creamos usando CreateFont(). Simplemente pasamos el handle a la fuente como wParam y ponemos lParam en TRUE para hacer que el control se redibuje.
He realizado esto en los ejemplos anteriores, pero tiene sentido mencionarlo aqu� debido a que es relevante y muy breve:
SendDlgItemMessage(hwnd, IDC_OF_YOUR_CONTROL, WM_SETFONT, (WPARAM)hfFont, TRUE);
Donde hfFont es, por su puesto, el HFONT que queremos usar y IDC_OF_YOUR_CONTROL es el ID del control al cual le queremos cambiar la fuente.
Versi�n en Espa�ol: FedericoPizarro - 2003