Sup, I was wondering if anyone else working with win32 think it's kind of ridiculous at the amount of code one has to type for something simple?
The reason I'm asking is because; I just finished a little app that accepts input and updates the characters in the middle of the screen, as well as reposition the Caret for every new char accepted and update the client area as needed.
Here's two functions I wrote just for that.
static void CheckCharacterValue(struct _WndProcInfo *wpi, TCHAR ascii)
{
if ( isalpha(ascii) || (ascii == ASCIIBSPACE)
|| (ascii == ASCIISPACE) )
{
if ( ascii == ASCIIBSPACE )
{
if ( (((wpi->sub_sv.cxCaretPos >> 1)
- (wpi->sub_sv.iFieldWidth >> 1)) >
((wpi->sub_sv.cxClient >> 1)
- (wpi->sub_sv.iFieldWidth >> 1))) )
{
bool_bspace = TRUE;
GetCharWidth32(wpi->hdc,
(UINT)szBuffer[iBuffIndex - 1],
(UINT)szBuffer[iBuffIndex - 1],
&wpi->sub_sv.iCharWidth);
wpi->charRect.bottom = (wpi->sub_sv.cyClient >> 1)
+ (wpi->sub_sv.cyChar >> 1);
wpi->charRect.left = (wpi->sub_sv.cxCaretPos >> 1)
- (wpi->sub_sv.iFieldWidth >> 1) - wpi->sub_sv.iCharWidth;
wpi->charRect.right = (wpi->sub_sv.cxCaretPos >> 1)
- (wpi->sub_sv.iFieldWidth >> 1);
wpi->charRect.top = (wpi->sub_sv.cyClient >> 1)
- (wpi->sub_sv.cyChar >> 1);
InvalidateRect(wpi->hwnd, &wpi->charRect, TRUE);
UpdateWindow(wpi->hwnd);
wpi->sub_sv.cxCaretPos -= wpi->sub_sv.iCharWidth << 1;
SetCaretPos((wpi->sub_sv.cxCaretPos >> 1)
- (wpi->sub_sv.iFieldWidth >> 1),
(wpi->sub_sv.cyClient >> 1)
- (wpi->sub_sv.cyChar >> 1));
szBuffer[--iBuffIndex] = '\0';
bool_bspace = FALSE;
}
}
else if ( ((wpi->sub_sv.cxCaretPos >> 1)
- (wpi->sub_sv.iFieldWidth >> 1)) < ((wpi->sub_sv.cxClient >> 1)
+ (wpi->sub_sv.iFieldWidth >> 1)) && ((iBuffIndex) != (BUFFSIZE - 1)))
{
bool_addchar = TRUE;
GetCharWidth32(wpi->hdc,
(UINT)ascii, (UINT)ascii, &wpi->sub_sv.iCharWidth);
szBuffer[iBuffIndex++] = ascii;
InvalidateRect(wpi->hwnd, NULL, FALSE);
UpdateWindow(wpi->hwnd);
wpi->sub_sv.cxCaretPos += wpi->sub_sv.iCharWidth << 1;
SetCaretPos((wpi->sub_sv.cxCaretPos >> 1)
- (wpi->sub_sv.iFieldWidth >> 1),
(wpi->sub_sv.cyClient >> 1)
- (wpi->sub_sv.cyChar >> 1));
}
}
}
static void GetFieldRectDimensions(struct _WndProcInfo *wpi)
{
wpi->fieldRect.left = (wpi->eraseBkgndRect.right >> 1) - (wpi->sub_sv.iFieldWidth >> 1);
wpi->fieldRect.top = (wpi->eraseBkgndRect.bottom >> 1) - (wpi->sub_sv.cyChar >> 1);
wpi->fieldRect.right = (wpi->eraseBkgndRect.right >> 1) + (wpi->sub_sv.iFieldWidth >> 1);
wpi->fieldRect.bottom = (wpi->eraseBkgndRect.bottom >> 1) + (wpi->sub_sv.cyChar >> 1);
}
Here's my WinMain and Window Procedure
#include <windows.h>
#define ASCIIBSPACE 0x08
#define ASCIISPACE 0x20
#define BUFFSIZE 11
int iBuffIndex;
BOOL bool_addchar = FALSE;
BOOL bool_bspace = FALSE;
TCHAR szBuffer[BUFFSIZE];
struct _SimpleVars
{
int cxClient;
int cyClient;
int cyChar;
int cxChar;
int cxCaps;
int cxCaretPos;
int iFieldWidth;
int iCharWidth;
};
struct _WndProcInfo
{
HDC hdc;
HWND hwnd;
RECT eraseBkgndRect;
RECT fieldRect;
RECT charRect;
PAINTSTRUCT ps;
TEXTMETRIC tm;
struct _SimpleVars sub_sv;
}wpi;
TCHAR szWinName[] = TEXT("WIN32 Project");
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static void CheckCharacterValue(struct _WndProcInfo*, TCHAR);
static void GetFieldRectDimensions(struct _WndProcInfo*);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szClassName[] = TEXT("InputProject");
HWND hwnd;
MSG msg;
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = szClassName;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
if ( !RegisterClass(&wc) )
{
MessageBox(NULL, TEXT("This Program Requires Windows NT!"),
szWinName, MB_ICONEXCLAMATION);
return 0;
}
if ( !(hwnd = CreateWindow(szClassName,
szWinName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL)) )
{
MessageBox(NULL, TEXT("COF::CreateWindow() Failed!"),
szWinName, MB_ICONEXCLAMATION);
return 0;
}
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while ( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.message;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
wpi.hwnd = hwnd;
switch ( iMsg )
{
case WM_CREATE :
wpi.hdc = GetDC(wpi.hwnd);
GetTextMetrics(wpi.hdc, &wpi.tm);
wpi.sub_sv.cxChar = wpi.tm.tmAveCharWidth;
wpi.sub_sv.cxCaps = (wpi.tm.tmPitchAndFamily & 1 ? 3 : 2)
* wpi.sub_sv.cxChar >> 1;
wpi.sub_sv.cyChar = wpi.tm.tmHeight + wpi.tm.tmExternalLeading;
wpi.sub_sv.iFieldWidth = wpi.sub_sv.cxCaps * 15;
ReleaseDC(wpi.hwnd, wpi.hdc);
return 0;
case WM_SETFOCUS :
CreateCaret(wpi.hwnd, NULL, 1, wpi.sub_sv.cyChar);
ShowCaret(wpi.hwnd);
return 0;
case WM_ERASEBKGND :
wpi.hdc = GetDC(wpi.hwnd);
HideCaret(wpi.hwnd);
if ( bool_bspace )
{
FillRect(wpi.hdc, &wpi.charRect,
(HBRUSH)GetStockObject(LTGRAY_BRUSH));
}
else
{
GetClientRect(wpi.hwnd, &wpi.eraseBkgndRect);
GetFieldRectDimensions(&wpi);
FillRect(wpi.hdc, &wpi.fieldRect, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
ExcludeClipRect(wpi.hdc, wpi.fieldRect.left,
wpi.fieldRect.top,
wpi.fieldRect.right,
wpi.fieldRect.bottom);
FillRect(wpi.hdc, &wpi.eraseBkgndRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
SelectClipRgn(wpi.hdc, NULL);
}
ShowCaret(wpi.hwnd);
ReleaseDC(wpi.hwnd, wpi.hdc);
return 1;
case WM_SIZE :
wpi.sub_sv.cxCaretPos -= wpi.sub_sv.cxClient;
wpi.sub_sv.cxClient = LOWORD(lParam);
wpi.sub_sv.cyClient = HIWORD(lParam);
wpi.sub_sv.cxCaretPos += wpi.sub_sv.cxClient;
SetCaretPos((wpi.sub_sv.cxCaretPos >> 1) - (wpi.sub_sv.iFieldWidth >> 1),
(wpi.sub_sv.cyClient >> 1) - (wpi.sub_sv.cyChar >> 1));
return 0;
case WM_PAINT :
wpi.hdc = BeginPaint(hwnd, &wpi.ps);
if ( bool_addchar )
{
SetBkColor(wpi.hdc, RGB(192, 192, 192));
TextOut(wpi.hdc, (wpi.sub_sv.cxCaretPos >> 1)
- (wpi.sub_sv.iFieldWidth >> 1),
(wpi.sub_sv.cyClient >> 1) - (wpi.sub_sv.cyChar >> 1),
&(szBuffer[iBuffIndex - 1]), 1);
bool_addchar = FALSE;
}
else if ( *szBuffer && !bool_bspace )
{
SetBkColor(wpi.hdc, RGB(192, 192, 192));
TextOut(wpi.hdc, (wpi.sub_sv.cxClient >> 1) - (wpi.sub_sv.iFieldWidth >> 1),
(wpi.sub_sv.cyClient >> 1) - (wpi.sub_sv.cyChar >> 1), szBuffer,
(int)strlen(szBuffer));
}
EndPaint(wpi.hwnd, &wpi.ps);
return 0;
case WM_CHAR :
wpi.hdc = GetDC(wpi.hwnd);
CheckCharacterValue(&wpi, (TCHAR)wParam);
ReleaseDC(wpi.hwnd, wpi.hdc);
return 0;
case WM_KILLFOCUS :
DestroyCaret();
return 0;
case WM_DESTROY :
PostQuitMessage(0);
return 0;
default :
break;
}
return DefWindowProc(wpi.hwnd, iMsg, wParam, lParam);
}
I also have another question. I managned to get rid of the flickering for my input field's background everytime the app is resized (which is light gray as you can see in the pic). This is clearly seen when no chars have yet been displayed.
But, I can't seem to get rid of the flickering that occurs as a result of the characters being displayed everytime my app is resized. That occurs because the string displayed is constantly updateing over itself with each resize. Is there a way to get rid of this problem without using double-buffering?
Thanks.