0

I have recently started learning windows API and would like to make more interactive GUI applications. All code is written in C++.

What I have done is made a custom button window, not using the built in button class. I want each button to have different text and would like to set this in the parent window.

So I create the button and save the handle:

hNavBtnNews = CreateWindow(szUW_NAV_BTN, "News", WS_CHILD | WS_VISIBLE, 540, 0, 100, HEADER_HEIGHT, header, NULL, NULL, NULL);

Then to make sure this hasn't failed I check the handle and attempt drawing text:

                if(hNavBtnNews == NULL){
                    printf("\nFailed to Create Window Nav Button \n");
                }else{
                    printf("\nCreated Window Nav Button");
                    HDC hdc;
                    PAINTSTRUCT ps;
                    RECT rect;
                    hdc = BeginPaint(hNavBtnNews, &ps);
                    SetBkMode(hdc, TRANSPARENT);
                    SetTextColor(hdc, BG_TXT_COLOR);
                    GetClientRect(hNavBtnNews, &rect);
                    DrawText(hdc, "News", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
                    EndPaint(hNavBtnNews, &ps);
                }

This is all done in the WM_CREATE case of the parent window procedure (which itself works just fine). The text is a light grey color and the background of the button is a dark blue. Except the text is not being drawn. There are no compiler warnings or errors either. Perhaps subclassing built in controls would be better for this, though I don't know how. Any help in solving this issue would be greatly appreciated.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
UnWorld
  • 129
  • 9
  • 5
    [BeginPaint](https://msdn.microsoft.com/en-us/library/dd183362.aspx): *"An application should not call **BeginPaint** except in response to a **WM_PAINT** message."* – IInspectable Feb 05 '16 at 12:02
  • You can always use [SetWindowSubclass](https://msdn.microsoft.com/en-us/library/windows/desktop/bb762102(v=vs.85).aspx) on a standard button, then simply handle the WM_PAINT message and do the drawing there - _not_ from within the main window's WindowProc. – enhzflep Feb 05 '16 at 12:06
  • 3
    You can't just paint a window once and then expect it to remain forever visible. You have to paint whenever the OS tells you a window needs to be painted. – Jonathan Potter Feb 05 '16 at 12:16
  • You can paint outside of WM_PAINT. I have now tried GetDc() instead of BeginPaint(). No change however. Looks like subclassing is the best way. – UnWorld Feb 05 '16 at 12:20
  • 2
    You are splattering pixels to a window that is not yet visible. That doesn't happen until after you called ShowWindow(). Those pixels are not going to survive long, overdrawn again when the window paints itself. How long that takes is entirely unpredictable. Just don't do this. – Hans Passant Feb 05 '16 at 12:39
  • 1
    Of course you can paint outside your `WM_PAINT` handler. But that's not how the system is designed to work. The system sends a [WM_PAINT](https://msdn.microsoft.com/en-us/library/dd145213.aspx) message, whenever a portion of a window needs to be painted. If you don't handle that message, anything you painted outside a `WM_PAINT` handler will be lost. – IInspectable Feb 05 '16 at 12:46
  • Thanks, I abandoned this method now. No wonder it wasn't working. Switched to subclassing the default button control instead. – UnWorld Feb 05 '16 at 14:09

1 Answers1

2

Consider the following brief snippet as an example of how simple sub-classing can be:

LRESULT CALLBACK myDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam,
                                     LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (uMsg)
    {
        case WM_PAINT:
            onBtnPaint(hWnd, wParam, lParam);
            return TRUE;
    }
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

BOOL CALLBACK DlgMain(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_INITDIALOG:
    {
        HWND button = GetDlgItem(hwndDlg, IDC_BUTTON_TO_SUBCLASS);
        SetWindowSubclass(button, myDrawButtonProc, 0, 0);
    }
    return TRUE;
...
...
...
enhzflep
  • 12,927
  • 2
  • 32
  • 51