Detect when child window needs redrawing - c++

Currently I am developing some custom controls and the problem I'm currently facing is that I don't know how to detect when my custom control needs redrawing.
I use WM_PAINT to draw everything, so I relly on RedrawWindow() function. However when my custom control moves outside drawing area and then comes back, it doesn't redraw. I tried catching WM_NCPAINT which works great, but then it sends WM_PAINT messages every time I move mouse inside parent window.
So my question is - how do I detect when to redraw child window after it comes back to drawing area?
Below is my code for CALLBACK:
LRESULT CALLBACK WinMsgHandler(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
settings.TrackingEvent.hwndTrack = hWnd;
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
switch (settings.CurrentState)
{
case cctrl_UNSELECTED_HOVER:
On_UnselectedHover(&hdc, &ps.rcPaint);
break;
case cctrl_UNSELECTED:
On_Unselected(&hdc, &ps.rcPaint);
break;
case cctrl_SELECTED_HOVER:
On_SelectedHover(&hdc, &ps.rcPaint);
break;
case cctrl_SELECTED:
On_Selected(&hdc, &ps.rcPaint);
break;
case cctrl_3STATE_HOVER:
On_IntermediateHover(&hdc, &ps.rcPaint);
break;
case cctrl_3STATE:
On_Intermediate(&hdc, &ps.rcPaint);
break;
default:
break;
}
EndPaint(hWnd, &ps);
}
break;
case WM_NCPAINT:
RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_FRAME
| RDW_INVALIDATE | RDW_ALLCHILDREN);
break;
case WM_MOUSEMOVE:
On_MouseMove();
break;
case WM_MOUSEHOVER:
On_MouseHover();
break;
case WM_MOUSELEAVE:
On_MouseLeave();
break;
case WM_LBUTTONDOWN:
On_LButtonDown();
break;
case WM_LBUTTONUP:
On_LButtonUp();
break;
case WM_DESTROY:
OnDestroy();
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}

Related

Why doesn't drawing onto the hdc immediately update the window?

According to this website, any drawing operation performed on the HDC returned by BeginPaint will immediately display on the screen. However, the number printed by the following code only updates when the window is resized:
int counter = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
std::string s = std::to_string(counter).c_str();
TextOutA(hdc, 0, 0, s.c_str(), s.length());
EndPaint(hWnd, &ps);
}
break;
case WM_KEYDOWN:
counter++;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Even when continuously sending WM_PAINT to the window with
RedrawWindow(hwndMain, 0, 0, RDW_INTERNALPAINT);
after EndPaint, the number only updates when the window is resized. How can I get the number to update without manually resizing the window?
Calling RedrawWindow with different flags solved the problem.
Specifically RedrawWindow(hWnd, 0, 0, RDW_FRAME | RDW_INVALIDATE); after counter++;

get scrollbar id on windows procedure

Here is how I create my scrollbar:
CreateWindowEx(NULL, L"SCROLLBAR", NULL, WS_CHILD | WS_VISIBLE | scrollPos, x, y, width, height, parent, (HMENU)155, GetModuleHandle(NULL), NULL);
How could I restore my id (155) to know which control I will operate?
Here is how I tried:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
int id;
SCROLLBARINFO si;
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (message)
{
case WM_USER:
break;
case WM_USER + 1:
break;
case CONNECT_TO_SERVER:
break;
case WM_VSCROLL:
id = GetDlgCtrlID(hWnd);
//id isn't my 155 id, it is some kind of random number
//wmId isn't my 155 id
break;
case WM_COMMAND:
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I need to regain this id to choose which one of my controls should react inside my own grid.
id = GetDlgCtrlID(hWnd);
That's not correct, hWnd is the handle to your main window, not the scrollbar control. Also beware that WM_VSCROLL can be sent both by your main window and the scrollbar. The lParam argument tells you where it came from. Fix:
case WM_VSCROLL:
if (lParam != 0) {
int id = GetDlgCtrlID((HWND)lParam);
// etc..
}
break;

SendMessage() and PostMessage() proper usage

I've got a problem with using SendMessage() and PostMessage() properly. The thing what i'm trying to do is SendMessage(hWnd, WM_USER + 1, 0, 0); in my window procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case WM_CREATE:
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case WM_USER:
break;
case WM_USER + 1:
break;
default:
if (grid.ProcessEvent(wmId, wmEvent))
{
SendMessage(hWnd, WM_USER + 1, 0, 0);
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Im not really sure why it doesn't work, maybe someone could help. I'm sure SendMessage(...) is called but it doesn't affect to run WndProc with my arguments.
The case label case WM_USER + 1: is nested in the inner case statement (that switches on wmId). It needs to be moved out to the switch (message) case statement, so it is at the same level of nesting as case WM_COMMAND: and case WM_DESTROY:.
The above also applies to case WM_USER:.
SendMessage is specified to not return until the receiver window has processed the message - which it cannot do as you're inside your own WndProc and messaging yourself. This is one of those cases where you should be using PostMessage.

C++ Windows Minimize Not Registered

I have added minimize & restore cases to my even processing, but I found out they are never hit.
Only on startup of the program does Size_Minimized get hit. Afterwards, minimize case never happens.
The Size_Restore case never happens either.
Debug stopping at Size_Minimize only on startup of program:
My other cases work, so I have no idea why minimize & restore dont trigger my code or break points.
I conclude that Size_Minimized & Size_Restore are not related to what I need.
What is it I need to know to handle minimize/restore?
Code, in case I did it wrong:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
PAINTSTRUCT ps;
HDC hdc;
switch(message){
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case SIZE_MINIMIZED:
break;
case SIZE_RESTORED:
break;
case WM_SIZING:
case WM_SIZE:
if(engine.isReady()) engine.resizeDevice();
if(engine.isReady()) engine.draw();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
SIZE_MINIMIZED and SIZE_RESTORED are constants passed to you through the WM_SIZE message; they are not window messages. Your breakpoint is getting hit whenever your window receives a window message with the same id as SIZE_MINIMIZED and/or SIZE_RESTORED.
You would need to have your code look something like this:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
PAINTSTRUCT ps;
HDC hdc;
switch(message){
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
switch(wParam) {
case SIZE_MINIMIZED:
// Do whatever
break;
case SIZE_RESTORED:
// Do whatever
break;
}
case WM_SIZING:
if(engine.isReady()) engine.resizeDevice();
if(engine.isReady()) engine.draw();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

Disable keyboard keys when the console of c Run using c or c++

I want to disable keyboard when my program Run, means that no one can use alt+F4 etc. How I can make it possible using c in window OS.
Handle WM_SYSKEYUP , WM_SYSKEYDOWN and return 0
Here's the WndProc to handle these messages
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Pressing alt + f4 sends WM_CLOSE message.
You should properly handled this message.