I have the following function:
void DeflateRect(RECT* rect)
{
rect->left++;
rect->top++;
rect->bottom--;
rect->right--;
}
#define BTN_NORMAL 0
#define BTN_PRESSED 1
#define BTN_DEFAULT 2
void PushMyButton(HDC dc, RECT *rect, int state)
{
UINT uType = DFCS_BUTTONPUSH;
if (state == BTN_NORMAL) // disabled
uType |= DFCS_INACTIVE;
if (state) // default or pressed
{
FrameRect(dc, rect, GetSysColorBrush(COLOR_WINDOWFRAME));
DeflateRect(rect);
}
if (state & BTN_PRESSED)
{
FrameRect(dc, rect, GetSysColorBrush(COLOR_BTNSHADOW));
DeflateRect(rect);
FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
}
else
{
DrawFrameControl(dc, rect, DFC_BUTTON, uType);
}
}
static void Main_OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
RECT rc, rcc;
BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
rcc.top = rcc.left = 10;
rcc.bottom = rcc.right = 42;
PushMyButton(ps.hdc, &rcc, 0);
Sleep(3000);
PushMyButton(ps.hdc, &rcc, 1);
//MessageBeep(-1);
Sleep(3000);
PushMyButton(ps.hdc, &rcc, &rcc), 0);
EndPaint(hwnd, &ps);
}
If the example runs as is, the first 'Sleep' takes effective 6s and the second 'PushMyButton' is invisible.
If I include the 'MessageBeep' all is as intended, both 'Sleep' functions take 3s and the 3 states of my Button can be seen clearly.
What exactly happens here?
Maybe during the execution of MyBeep the message loop runs and executes messages dispatching? (Sleep stops whole thread)
Always this damned message loop problem! >:(
I don't want be boring, but the good practice for GUI programs development is to have a single thread managing the GUI and executing short time consuming tasks. Where timings, and heavy computation is involved should be preferred a separate thread.
I will do this in real applications. Thank you!
But this was only a short test. And it would be overkill to implement several tasks for this.
As a matter of course in my GUI stuff I use the following (borrowed from VB) in the place where you used MessageBeep().
/// @brief Yields execution of the current thread so that
/// the operating system can process other events.
///
/// @returns VOID.
static VOID DoEvents(VOID)
{
MSG Msg;
while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
So with the example lets suppose we put the DoEvents() in PushMyButton() like so:
void DeflateRect(RECT* rect)
{
rect->left++;
rect->top++;
rect->bottom--;
rect->right--;
}
#define BTN_NORMAL 0
#define BTN_PRESSED 1
#define BTN_DEFAULT 2
void PushMyButton(HDC dc, RECT *rect, int state)
{
UINT uType = DFCS_BUTTONPUSH;
if (state == BTN_NORMAL) // disabled
uType |= DFCS_INACTIVE;
if (state) // default or pressed
{
FrameRect(dc, rect, GetSysColorBrush(COLOR_WINDOWFRAME));
DeflateRect(rect);
}
if (state & BTN_PRESSED)
{
FrameRect(dc, rect, GetSysColorBrush(COLOR_BTNSHADOW));
DeflateRect(rect);
FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
}
else
{
DrawFrameControl(dc, rect, DFC_BUTTON, uType);
}
DoEvents(); //Update the view by emptying the message queue
}
static void Main_OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
RECT rc, rcc;
BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
rcc.top = rcc.left = 10;
rcc.bottom = rcc.right = 42;
PushMyButton(ps.hdc, &rcc, 0);
Sleep(3000);
PushMyButton(ps.hdc, &rcc, 1);
Sleep(3000);
PushMyButton(ps.hdc, &rcc, &rcc), 0);
EndPaint(hwnd, &ps);
}
That should achieve the desired result.