WM_PAINT - round 2

So, I want to create a window with text "Please select file to open" in the center, but only on the initial window. Once the user clicks on any button, I want that text to go away forever. So, do I still use WM_PAINT to put that message? Or, put the message somewhere else? Is there another WM message for initial window stuff? I could put a flag in WinMain that is changed when the user clicks on a button and use that flag in WM_PAINT, but is that the best way to do that? Without any flag, it works in WM_PAINT, but the message stays there all the time, because that's what WM_PAINT does.... I tried InvalidateRec(), but that erases all my buttons too.

This is what I have in my WM_PAINT and it works. Not sure if that's the preferred method.

1
2
3
4
5
6
7
8
9
10
        case WM_PAINT:
            BeginPaint(hwnd, &ps);
            if (initflag == 0)
            {
                GetClientRect(hwnd, &rect);
                DrawTextW(hdc, L"Please Select Data File to Open", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
            }
            EndPaint(hwnd, &ps);
            initflag = 1;
            return(0);
Last edited on
maybe this pattern?
on mouse click or something handler
some bool = true //init to false each time, or once per program run via static, ?? whatever???
invalidate

...
case WM_PAINT
if(! some bool)
drawtextw(..)

Last edited on
There is WM_CREATE message which is sent when a window is to be created. That's where you would usually put init stuff.

The order of messages sent to the app's window procedure makes using WM_CREATE instead of WM_PAINT problematical to display text. I know, I tried drawing some text in WM_CREATE instead of WM_PAINT. The text wasn't displayed in the client area as it should.

The order of messages sent to a newly created app are (in part):

WM_CREATE, WM_SIZE, WM_PAINT.

The entire client area initially is invalid until the WM_PAINT message is processed either by the app or DefWindowProc, so any text drawn before the the WM_PAINT is effectively erased.

https://stackoverflow.com/questions/18258668/order-of-events-when-a-window-starts-in-visual-c-mfc
(The question is about MFC, but the answer is still applicable for non-MFC WinAPI apps)

jonnin's idea of a static bool works.

A minimal app wndproc, using a left mouse click (mouse down) to be the one-time toggle:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   HDC         hdc;
   PAINTSTRUCT ps;
   static bool display_text = true;

   switch(message)
   {
   case WM_PAINT:
      hdc = BeginPaint(hwnd, &ps);

      if (display_text)
      {
         RECT rect;
         GetClientRect(hwnd, &rect);
         DrawTextW(hdc, L"Click Me, Baby!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
      }

      EndPaint(hwnd, &ps);
      return S_OK;

   case WM_LBUTTONDOWN:
      MessageBoxW(hwnd, L"Stop Poking Me!", L"Ouch!", MB_OK);
      display_text = false;
      InvalidateRect(hwnd, NULL, TRUE);  // invalidate the entire client area to erase the text
      return S_OK;

   case WM_DESTROY:
      PostQuitMessage(0);
      return S_OK;
   }

   return DefWindowProc(hwnd, message, wParam, lParam);
}
Thanks. This is the way I'm doing it and it works well.
One nice thing using a static bool to toggle the text display is if you want to redisplay the text after hiding it, toggle the bool back to true and invalidate the entire client area. *POOF* There it is again.
BTW, dodge55, in your original snippet you aren't assigning the return of BeginPaint to your device context variable. You need to do it whenever you want to paint to the client area.

Windows can and does alter handles to resources all the time, so any time you want to use a device context you need to get the current handle.
Thanks, Furry Guy, you are right. Missed that.
Registered users can post here. Sign in or register to post.